--- src/lwip/lwip-1.1.1/lwip/src/core/ipv4/ip_frag.c	2006-03-03 11:25:36.000000000 +0000
+++ packages/net/lwip_tcpip/current/src/core/ipv4/ip_frag.c	2006-11-30 16:20:16.000000000 +0000
@@ -46,7 +46,7 @@
 #include "lwip/netif.h"
 #include "lwip/stats.h"
 
-
+#if IP_REASSEMBLY || IP_FRAG_USES_STATIC_BUF
 /*
  * Copy len bytes from offset in pbuf to buffer 
  *
@@ -67,16 +67,13 @@ copy_from_pbuf(struct pbuf *p, u16_t * o
     len -= l;
     if (len)
       p = p->next;
-    else
-      *offset = l;
   }
+  *offset = l;
   return p;
 }
+#endif
 
-#define IP_REASS_BUFSIZE 5760
-#define IP_REASS_MAXAGE 30
-#define IP_REASS_TMO 1000
-
+#if IP_REASSEMBLY
 static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
 static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];
 static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
@@ -278,9 +275,11 @@ nullreturn:
   pbuf_free(p);
   return NULL;
 }
+#endif
 
-#define MAX_MTU 1500
-static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)];
+#if IP_FRAG_USES_STATIC_BUF
+static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
+#endif
 
 /**
  * Fragment an IP datagram if too large for the netif.
@@ -288,21 +287,35 @@ static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)]
  * Chop the datagram in MTU sized chunks and send them in order
  * by using a fixed size static memory buffer (PBUF_ROM)
  */
+#if IP_FRAG
 err_t 
 ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
 {
   struct pbuf *rambuf;
+#if IP_FRAG_USES_STATIC_BUF
   struct pbuf *header;
+#else
+  struct pbuf *newpbuf;
+  struct ip_hdr *original_iphdr;
+#endif
   struct ip_hdr *iphdr;
-  u16_t nfb = 0;
+  u16_t nfb;
   u16_t left, cop;
   u16_t mtu = netif->mtu;
   u16_t ofo, omf;
   u16_t last;
   u16_t poff = IP_HLEN;
   u16_t tmp;
+#if !IP_FRAG_USES_STATIC_BUF
+  u16_t newpbuflen, left_to_copy;
+#endif
 
   /* Get a RAM based MTU sized pbuf */
+#if IP_FRAG_USES_STATIC_BUF
+  /* When using a static buffer, we use a PBUF_REF, which we will
+   * use to reference the packet (without link header).
+   * Layer and length is irrelevant.
+   */
   rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
   if (rambuf == NULL) {
     return ERR_MEM;
@@ -313,6 +326,9 @@ ip_frag(struct pbuf *p, struct netif *ne
   /* Copy the IP header in it */
   iphdr = rambuf->payload;
   memcpy(iphdr, p->payload, IP_HLEN);
+#else
+  original_iphdr = p->payload;
+#endif
 
   /* Save original offset */
   tmp = ntohs(IPH_OFFSET(iphdr));
@@ -321,29 +337,75 @@ ip_frag(struct pbuf *p, struct netif *ne
 
   left = p->tot_len - IP_HLEN;
 
+  nfb = (mtu - IP_HLEN) / 8;
+
   while (left) {
     last = (left <= mtu - IP_HLEN);
 
     /* Set new offset and MF flag */
-    ofo += nfb;
     tmp = omf | (IP_OFFMASK & (ofo));
     if (!last)
       tmp = tmp | IP_MF;
-    IPH_OFFSET_SET(iphdr, htons(tmp));
 
     /* Fill this fragment */
-    nfb = (mtu - IP_HLEN) / 8;
     cop = last ? left : nfb * 8;
 
+#if IP_FRAG_USES_STATIC_BUF
     p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
+#else
+    /* When not using a static buffer, create a chain of pbufs.
+     * The first will be a PBUF_RAM holding the link and IP header.
+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
+     * but limited to the size of an mtu.
+     */
+    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
+    if (rambuf == NULL) {
+      return ERR_MEM;
+    }
+    memcpy(rambuf->payload, original_iphdr, IP_HLEN);
+    iphdr = rambuf->payload;
+
+    /* Can just adjust p directly for needed offset. */
+    p->payload = (u8_t *)p->payload + poff;
+    p->len -= poff;
+
+    left_to_copy = cop;
+    while (left_to_copy) {
+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
+      /* Is this pbuf already empty? */
+      if (!newpbuflen) {
+        p = p->next;
+        continue;
+      }
+      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
+      if (newpbuf == NULL) {
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      /* Mirror this pbuf, although we might not need all of it. */
+      newpbuf->payload = p->payload;
+      newpbuf->len = newpbuf->tot_len = newpbuflen;
+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
+       * so that it is removed when pbuf_dechain is later called on rambuf.
+       */
+      pbuf_cat(rambuf, newpbuf);
+      left_to_copy -= newpbuflen;
+      if (left_to_copy)
+        p = p->next;
+    }
+    poff = newpbuflen;
+#endif
 
     /* Correct header */
+    IPH_OFFSET_SET(iphdr, htons(tmp));
     IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
     IPH_CHKSUM_SET(iphdr, 0);
     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
 
+#if IP_FRAG_USES_STATIC_BUF
     if (last)
       pbuf_realloc(rambuf, left + IP_HLEN);
+
     /* This part is ugly: we alloc a RAM based pbuf for 
      * the link level header for each chunk and then 
      * free it.A PBUF_ROM style pbuf for which pbuf_header
@@ -359,8 +421,28 @@ ip_frag(struct pbuf *p, struct netif *ne
       pbuf_free(rambuf);      
       return ERR_MEM;    
     }
+#else /* !IP_FRAG_USES_STATIC_BUF */
+    /* No need for separate header pbuf - we allowed room for it in rambuf
+     * when allocated.
+     */
+    netif->output(netif, rambuf, dest);
+    IPFRAG_STATS_INC(ip_frag.xmit);
+
+    /* Unfortunately we can't reuse rambuf - the hardware may still be
+     * using the buffer. Instead we free it (and the ensuing chain) and
+     * recreate it next time round the loop. If we're lucky the hardware
+     * will have already sent the packet, the free will really free, and
+     * there will be zero memory penalty.
+     */
+    
+    pbuf_free(rambuf);
+#endif
     left -= cop;
+    ofo += nfb;
   }
+#if IP_FRAG_USES_STATIC_BUF
   pbuf_free(rambuf);
+#endif
   return ERR_OK;
 }
+#endif
