Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

pbuf.c

Go to the documentation of this file.
00001 
00015 /*
00016  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00017  * All rights reserved. 
00018  * 
00019  * Redistribution and use in source and binary forms, with or without modification, 
00020  * are permitted provided that the following conditions are met:
00021  *
00022  * 1. Redistributions of source code must retain the above copyright notice,
00023  *    this list of conditions and the following disclaimer.
00024  * 2. Redistributions in binary form must reproduce the above copyright notice,
00025  *    this list of conditions and the following disclaimer in the documentation
00026  *    and/or other materials provided with the distribution.
00027  * 3. The name of the author may not be used to endorse or promote products
00028  *    derived from this software without specific prior written permission. 
00029  *
00030  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00031  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00032  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00033  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00034  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00035  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00036  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00037  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00038  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00039  * OF SUCH DAMAGE.
00040  *
00041  * This file is part of the lwIP TCP/IP stack.
00042  * 
00043  * Author: Adam Dunkels <adam@sics.se>
00044  *
00045  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00046  *            Departamento de Informática de Sistemas y Computadores          
00047  *            Universidad Politécnica de Valencia                             
00048  *            Valencia (Spain)    
00049  *            Date: April 2003                                          
00050  *  
00051  */
00052 
00053 #include "lwip/opt.h"
00054 #include "lwip/stats.h"
00055 #include "lwip/def.h"
00056 #include "lwip/mem.h"
00057 #include "lwip/memp.h"
00058 #include "lwip/pbuf.h"
00059 #include "lwip/sys.h"
00060 
00061 
00062 static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];
00063 
00064 #if !SYS_LIGHTWEIGHT_PROT
00065 static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
00066 static sys_sem_t pbuf_pool_free_sem;
00067 #endif
00068 
00069 static struct pbuf *pbuf_pool = NULL;
00070 static struct pbuf *pbuf_pool_alloc_cache = NULL;
00071 static struct pbuf *pbuf_pool_free_cache = NULL;
00072 
00085 void
00086 pbuf_init(void)
00087 {
00088   struct pbuf *p, *q = NULL;
00089   u16_t i;
00090 
00091   pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
00092   LWIP_ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0);
00093    
00094 #ifdef PBUF_STATS
00095   lwip_stats.pbuf.avail = PBUF_POOL_SIZE;
00096 #endif /* PBUF_STATS */
00097   
00098   /* Set up ->next pointers to link the pbufs of the pool together */
00099   p = pbuf_pool;
00100   
00101   for(i = 0; i < PBUF_POOL_SIZE; ++i) {
00102     p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
00103     p->len = p->tot_len = PBUF_POOL_BUFSIZE;
00104     p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
00105     q = p;
00106     p = p->next;
00107   }
00108   
00109   /* The ->next pointer of last pbuf is NULL to indicate that there
00110      are no more pbufs in the pool */
00111   q->next = NULL;
00112 
00113 #if !SYS_LIGHTWEIGHT_PROT  
00114   pbuf_pool_alloc_lock = 0;
00115   pbuf_pool_free_lock = 0;
00116   pbuf_pool_free_sem = sys_sem_new(1);
00117 #endif  
00118 }
00119 
00123 static struct pbuf *
00124 pbuf_pool_alloc(void)
00125 {
00126   struct pbuf *p = NULL;
00127 
00128   unsigned int state;
00129   sys_stop_interrupts(&state);
00130   /* First, see if there are pbufs in the cache. */
00131   if(pbuf_pool_alloc_cache) {
00132     p = pbuf_pool_alloc_cache;
00133     if(p) {
00134       pbuf_pool_alloc_cache = p->next; 
00135     }
00136   } else {
00137 #if !SYS_LIGHTWEIGHT_PROT      
00138     /* Next, check the actual pbuf pool, but if the pool is locked, we
00139        pretend to be out of buffers and return NULL. */
00140     if(pbuf_pool_free_lock) {
00141 #ifdef PBUF_STATS
00142       ++lwip_stats.pbuf.alloc_locked;
00143 #endif /* PBUF_STATS */
00144       return NULL;
00145     }
00146     pbuf_pool_alloc_lock = 1;
00147     if(!pbuf_pool_free_lock) {
00148 #endif /* SYS_LIGHTWEIGHT_PROT */        
00149       p = pbuf_pool;
00150       if(p) {
00151         pbuf_pool = p->next; 
00152       }
00153 #if !SYS_LIGHTWEIGHT_PROT      
00154 #ifdef PBUF_STATS
00155     } else {
00156       ++lwip_stats.pbuf.alloc_locked;
00157 #endif /* PBUF_STATS */
00158     }
00159     pbuf_pool_alloc_lock = 0;
00160 #endif /* SYS_LIGHTWEIGHT_PROT */    
00161   }
00162   
00163 #ifdef PBUF_STATS
00164   if(p != NULL) {    
00165     ++lwip_stats.pbuf.used;
00166     if(lwip_stats.pbuf.used > lwip_stats.pbuf.max) {
00167       lwip_stats.pbuf.max = lwip_stats.pbuf.used;
00168     }
00169   }
00170 #endif /* PBUF_STATS */
00171 
00172   sys_allow_interrupts(&state);
00173   return p;   
00174 }
00175 
00179 static void
00180 pbuf_pool_free(struct pbuf *p)
00181 {
00182   struct pbuf *q;
00183   unsigned int state;
00184   sys_stop_interrupts(&state);
00185 
00186 #ifdef PBUF_STATS
00187     for(q = p; q != NULL; q = q->next) {
00188       --lwip_stats.pbuf.used;
00189     }
00190 #endif /* PBUF_STATS */
00191 
00192   if(pbuf_pool_alloc_cache == NULL) {
00193     pbuf_pool_alloc_cache = p;
00194   } else {  
00195     for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next);
00196     q->next = p;    
00197   }
00198   sys_allow_interrupts(&state);
00199 }
00200 
00230 struct pbuf *
00231 pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
00232 {
00233   struct pbuf *p, *q, *r;
00234   u16_t offset;
00235   s32_t rem_len; /* remaining length */
00236 
00237   /* determine header offset */
00238   offset = 0;
00239   switch (l) {
00240   case PBUF_TRANSPORT:
00241     /* add room for transport (often TCP) layer header */
00242     offset += PBUF_TRANSPORT_HLEN;
00243     /* FALLTHROUGH */
00244   case PBUF_IP:
00245     /* add room for IP layer header */
00246     offset += PBUF_IP_HLEN;
00247     /* FALLTHROUGH */
00248   case PBUF_LINK:
00249     /* add room for link layer header */
00250     offset += PBUF_LINK_HLEN;
00251     break;
00252   case PBUF_RAW:
00253     break;
00254   default:
00255     LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
00256     return NULL;
00257   }
00258 
00259   switch (flag) {
00260   case PBUF_POOL:
00261     /* allocate head of pbuf chain into p */
00262     p = pbuf_pool_alloc();
00263     if (p == NULL) {
00264 #ifdef PBUF_STATS
00265       ++lwip_stats.pbuf.err;
00266 #endif /* PBUF_STATS */
00267       return NULL;
00268     }
00269     p->next = NULL;
00270     
00271     /* make the payload pointer point 'offset' bytes into pbuf data memory */
00272     p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
00273     LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
00274             ((u32_t)p->payload % MEM_ALIGNMENT) == 0);
00275     /* the total length of the pbuf chain is the requested size */
00276     p->tot_len = length;
00277     /* set the length of the first pbuf in the chain */
00278     p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;
00279     /* set pbuf type */
00280     p->flags = PBUF_FLAG_POOL;
00281     
00282     /* now allocate the tail of the pbuf chain */
00283     
00284     /* remember first pbuf for linkage in next iteration */
00285     r = p;
00286     /* remaining length to be allocated */
00287     rem_len = length - p->len;
00288     /* any remaining pbufs to be allocated? */
00289     while(rem_len > 0) {      
00290       q = pbuf_pool_alloc();
00291       if (q == NULL) {
00292        DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
00293 #ifdef PBUF_STATS
00294         ++lwip_stats.pbuf.err;
00295 #endif /* PBUF_STATS */
00296         /* bail out unsuccesfully */
00297         pbuf_pool_free(p);
00298         return NULL;
00299       }
00300       //q->next = NULL;
00301       /* make previous pbuf point to this pbuf */
00302       r->next = q;
00303       /* set length of this pbuf */
00304       q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
00305       q->flags = PBUF_FLAG_POOL;
00306       q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
00307       LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
00308               ((u32_t)q->payload % MEM_ALIGNMENT) == 0);
00309       q->ref = 1;
00310       /* calculate remaining length to be allocated */
00311       rem_len -= q->len;
00312       /* remember this pbuf for linkage in next iteration */
00313       r = q;
00314     }
00315     /* end of chain */
00316     r->next = NULL;
00317 
00318     break;
00319   case PBUF_RAM:
00320     /* If pbuf is to be allocated in RAM, allocate memory for it. */
00321     p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset));
00322     if (p == NULL) {
00323       return NULL;
00324     }
00325     /* Set up internal structure of the pbuf. */
00326     p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
00327     p->len = p->tot_len = length;
00328     p->next = NULL;
00329     p->flags = PBUF_FLAG_RAM;
00330 
00331     LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
00332            ((u32_t)p->payload % MEM_ALIGNMENT) == 0);
00333     break;
00334   /* pbuf references existing (static constant) ROM payload? */
00335   case PBUF_ROM:
00336   /* pbuf references existing (externally allocated) RAM payload? */
00337   case PBUF_REF:
00338     /* only allocate memory for the pbuf structure */
00339     p = memp_mallocp(MEMP_PBUF);
00340     if (p == NULL) {
00341       DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_REF.\n"));
00342       return NULL;
00343     }
00344     /* caller must set this field properly, afterwards */
00345     p->payload = NULL;
00346     p->len = p->tot_len = length;
00347     p->next = NULL;
00348     p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);
00349     break;
00350   default:
00351     LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
00352     return NULL;
00353   }
00354   p->ref = 1;
00355   return p;
00356 }
00357 
00364 void
00365 pbuf_refresh(void)
00366 {
00367   struct pbuf *p;
00368   unsigned int state;
00369   sys_stop_interrupts(&state);
00370  
00371 #if !SYS_LIGHTWEIGHT_PROT
00372   sys_sem_wait(pbuf_pool_free_sem);
00373 #endif /* else SYS_LIGHTWEIGHT_PROT */
00374   
00375   if(pbuf_pool_free_cache != NULL) {
00376 #if !SYS_LIGHTWEIGHT_PROT      
00377     pbuf_pool_free_lock = 1;
00378     if(!pbuf_pool_alloc_lock) {
00379 #endif /* SYS_LIGHTWEIGHT_PROT */
00380       if(pbuf_pool == NULL) {
00381         pbuf_pool = pbuf_pool_free_cache;       
00382       } else {  
00383         for(p = pbuf_pool; p->next != NULL; p = p->next);
00384         p->next = pbuf_pool_free_cache;   
00385       }
00386       pbuf_pool_free_cache = NULL;
00387 #if !SYS_LIGHTWEIGHT_PROT      
00388 #ifdef PBUF_STATS
00389     } else {
00390       ++lwip_stats.pbuf.refresh_locked;
00391 #endif /* PBUF_STATS */
00392     }
00393     
00394     pbuf_pool_free_lock = 0;
00395 #endif /* SYS_LIGHTWEIGHT_PROT */    
00396   }
00397   sys_allow_interrupts(&state);
00398 #if !SYS_LIGHTWEIGHT_PROT      
00399   sys_sem_signal(pbuf_pool_free_sem);
00400 #endif /* SYS_LIGHTWEIGHT_PROT */  
00401 }
00402 
00403 #ifdef PBUF_STATS
00404 #define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)
00405 #else /* PBUF_STATS */
00406 #define DEC_PBUF_STATS
00407 #endif /* PBUF_STATS */
00408 
00409 #define PBUF_POOL_FAST_FREE(p)  do {                                    \
00410                                   p->next = pbuf_pool_free_cache;       \
00411                                   pbuf_pool_free_cache = p;             \
00412                                   DEC_PBUF_STATS;                       \
00413                                 } while (0)
00414 
00415 #if SYS_LIGHTWEIGHT_PROT
00416 #define PBUF_POOL_FREE(p)  do {                                         \
00417                                 unsigned int state;                     \
00418                                 sys_stop_interrupts(&state);            \
00419                                 PBUF_POOL_FAST_FREE(p);                 \
00420                                 sys_allow_interrupts(&state)            \
00421                                } while(0)
00422 #else /* SYS_LIGHTWEIGHT_PROT */
00423 #define PBUF_POOL_FREE(p)  do {                                         \
00424                              sys_sem_wait(pbuf_pool_free_sem);          \
00425                              PBUF_POOL_FAST_FREE(p);                    \
00426                              sys_sem_signal(pbuf_pool_free_sem);        \
00427                            } while(0)
00428 #endif /* SYS_LIGHTWEIGHT_PROT */
00429 
00444 void
00445 pbuf_realloc(struct pbuf *p, u16_t new_len)
00446 {
00447   struct pbuf *q;
00448   u16_t rem_len; /* remaining length */
00449   s16_t grow;
00450 
00451   LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
00452               p->flags == PBUF_FLAG_ROM ||
00453               p->flags == PBUF_FLAG_RAM ||
00454               p->flags == PBUF_FLAG_REF);
00455 
00456   /* desired length larger than current length? */
00457   if (new_len >= p->tot_len) {
00458     /* enlarging not yet supported */
00459     return;
00460   }
00461   
00462   /* the pbuf chain grows by (new_len - p->tot_len) bytes
00463    * (which may be negative in case of shrinking) */
00464   grow = new_len - p->tot_len;
00465   
00466   /* first, step over any pbufs that should remain in the chain */
00467   rem_len = new_len;
00468   q = p;  
00469   /* this pbuf should be kept? */
00470   while (rem_len > q->len) {
00471     /* decrease remaining length by pbuf length */
00472     rem_len -= q->len;
00473     /* decrease total length indicator */
00474     q->tot_len += grow;
00475     /* proceed to next pbuf in chain */
00476     q = q->next;
00477   }
00478   /* we have now reached the new last pbuf (in q) */
00479   /* rem_len == desired length for pbuf q */  
00480 
00481   /* shrink allocated memory for PBUF_RAM */
00482   /* (other types merely adjust their length fields */
00483   if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {
00484     /* reallocate and adjust the length of the pbuf that will be split */
00485     mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
00486   }
00487   /* adjust length fields for new last pbuf */
00488   q->len = rem_len;
00489   q->tot_len = q->len;
00490 
00491   /* any remaining pbufs in chain? */
00492   if (q->next != NULL) {
00493     /* free remaining pbufs in chain */
00494     pbuf_free(q->next);
00495   }
00496   /* q is last packet in chain */
00497   q->next = NULL;
00498 
00499   pbuf_refresh();
00500 }
00501 
00519 u8_t
00520 pbuf_header(struct pbuf *p, s16_t header_size)
00521 {
00522   void *payload;
00523 
00524   /* remember current payload pointer */
00525   payload = p->payload;
00526 
00527   /* pbuf types containing payloads? */
00528   if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) {
00529     /* set new payload pointer */
00530     p->payload = (u8_t *)p->payload - header_size;
00531     /* boundary check fails? */
00532     if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
00533       DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n",
00534         (u8_t *)p->payload,
00535         (u8_t *)p + sizeof(struct pbuf)) );\
00536       /* restore old payload pointer */
00537       p->payload = payload;
00538       /* bail out unsuccesfully */
00539       return 1;
00540     }
00541   /* pbuf types refering to payloads? */
00542   } else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) {
00543     /* hide a header in the payload? */
00544     if ((header_size < 0) && (header_size - p->len <= 0)) {
00545       /* increase payload pointer */
00546       p->payload = (u8_t *)p->payload - header_size;
00547     } else {
00548       /* cannot expand payload to front (yet!)
00549        * bail out unsuccesfully */
00550       return 1;
00551     }
00552   }
00553   DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size) );
00554   /* modify pbuf length fields */
00555   p->len += header_size;
00556   p->tot_len += header_size;
00557 
00558   return 0;
00559 }
00560 
00588 u8_t
00589 pbuf_free(struct pbuf *p)
00590 {
00591   struct pbuf *q;
00592   u8_t count;
00593   unsigned int state;
00594 
00595   if (p == NULL) {
00596     DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
00597     return 0;
00598   }
00599 
00600 //  PERF_START;
00601 
00602   LWIP_ASSERT("pbuf_free: sane flags",
00603     p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||
00604     p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);
00605 
00606   count = 0;
00607   /* Since decrementing ref cannot be guaranteed to be a single machine operation
00608    * we must protect it. Also, the later test of ref must be protected.
00609    */
00610   sys_stop_interrupts(&state);
00611   /* de-allocate all consecutive pbufs from the head of the chain that
00612    * obtain a zero reference count */
00613   while (p != NULL) {
00614     /* all pbufs in a chain are referenced at least once */
00615     LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
00616     p->ref--;
00617     /* this pbuf is no longer referenced to? */
00618     if (p->ref == 0) {
00619       /* remember next pbuf in chain for next iteration */
00620       q = p->next;
00621       /* is this a pbuf from the pool? */
00622       if (p->flags == PBUF_FLAG_POOL) {
00623         p->len = p->tot_len = PBUF_POOL_BUFSIZE;
00624         p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
00625         PBUF_POOL_FREE(p);
00626       /* a RAM/ROM referencing pbuf */
00627       } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
00628         memp_freep(MEMP_PBUF, p);
00629       /* pbuf with data */
00630       } else {
00631         mem_free(p);
00632       }
00633       count++;
00634       /* proceed to next pbuf */
00635       p = q;
00636     /* p->ref > 0, this pbuf is still referenced to */
00637     /* (so the remaining pbufs in chain as well)    */
00638     } else {
00639       /* stop walking through chain */
00640       p = NULL;
00641     }
00642   }
00643   sys_allow_interrupts(&state);
00644   pbuf_refresh();
00645 //  PERF_STOP("pbuf_free");
00646   /* return number of de-allocated pbufs */
00647   return count;
00648 }
00649 
00657 u8_t
00658 pbuf_clen(struct pbuf *p)
00659 {
00660   u8_t len;
00661 
00662   len = 0;  
00663   while (p != NULL) {
00664     ++len;
00665     p = p->next;
00666   }
00667   return len;
00668 }
00676 void
00677 pbuf_ref(struct pbuf *p)
00678 {
00679   unsigned int state;
00680   /* pbuf given? */  
00681   if (p != NULL) {
00682     sys_stop_interrupts(&state);
00683     ++(p->ref);
00684     sys_allow_interrupts(&state);
00685   }
00686 }
00687 
00695 void
00696 pbuf_ref_chain(struct pbuf *p)
00697 {
00698   unsigned int state;
00699   sys_stop_interrupts(&state);
00700     
00701   while (p != NULL) {
00702     ++p->ref;
00703     p = p->next;
00704   }
00705   sys_allow_interrupts(&state);
00706 }
00707 
00708 
00718 void
00719 pbuf_chain(struct pbuf *h, struct pbuf *t)
00720 {
00721   struct pbuf *p;
00722 
00723   LWIP_ASSERT("h != NULL", h != NULL);
00724   LWIP_ASSERT("t != NULL", t != NULL);
00725   
00726   /* proceed to last pbuf of chain */
00727   for (p = h; p->next != NULL; p = p->next) {
00728     /* add total length of second chain to all totals of first chain */
00729     p->tot_len += t->tot_len;
00730   }
00731   /* p is last pbuf of first h chain */
00732   /* add total length of second chain to last pbuf total of first chain */
00733   p->tot_len += t->tot_len;
00734   /* chain last pbuf of h chain (p) with first of tail (t) */
00735   p->next = t;
00736   /* t is now referenced to one more time */
00737   pbuf_ref(t);
00738   DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t));
00739 }
00740 
00748 struct pbuf *
00749 pbuf_dechain(struct pbuf *p)
00750 {
00751   struct pbuf *q;
00752   u8_t tail_gone = 1;
00753   /* tail */  
00754   q = p->next;
00755   /* pbuf has successor in chain? */
00756   if (q != NULL) {
00757     /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
00758     LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
00759     /* enforce invariant if assertion is disabled */
00760     q->tot_len = p->tot_len - p->len;
00761     /* decouple pbuf from remainder */
00762     p->next = NULL;
00763     /* total length of pbuf p is its own length only */
00764     p->tot_len = p->len;
00765     /* q is no longer referenced by p, free it */
00766     DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q));
00767     tail_gone = pbuf_free(q);
00768     /* return remaining tail or NULL if deallocated */
00769   }
00770   /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
00771   LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
00772   return (tail_gone > 0? NULL: q);
00773 }
00774 
00796 struct pbuf *
00797 pbuf_take(struct pbuf *p)
00798 {
00799   struct pbuf *q , *prev, *head;
00800   LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
00801   DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));
00802 
00803   prev = NULL;
00804   head = p;
00805   /* iterate through pbuf chain */
00806   do
00807   {
00808     /* pbuf is of type PBUF_REF? */
00809     if (p->flags == PBUF_FLAG_REF) {
00810       DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
00811       /* allocate a pbuf (w/ payload) fully in RAM */
00812       /* PBUF_POOL buffers are faster if we can use them */
00813       if (p->len <= PBUF_POOL_BUFSIZE) {
00814         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
00815         if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
00816       } else {
00817         /* no replacement pbuf yet */
00818         q = NULL;
00819         DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
00820       }
00821       /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
00822       if (q == NULL) {
00823         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
00824         if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
00825       }
00826       /* replacement pbuf could be allocated? */
00827       if (q != NULL)
00828       {
00829         /* copy p to q */  
00830         /* copy successor */
00831         q->next = p->next;
00832         /* remove linkage from original pbuf */
00833         p->next = NULL;
00834         /* remove linkage to original pbuf */
00835         if (prev != NULL) {
00836           /* prev->next == p at this point */
00837           LWIP_ASSERT("prev->next == p", prev->next == p);
00838           /* break chain and insert new pbuf instead */
00839           prev->next = q;
00840         /* prev == NULL, so we replaced the head pbuf of the chain */
00841         } else {
00842           head = q;
00843         }
00844         /* copy pbuf payload */
00845         memcpy(q->payload, p->payload, p->len);
00846         q->tot_len = p->tot_len;
00847         q->len = p->len;
00848         /* in case p was the first pbuf, it is no longer refered to by
00849          * our caller, as the caller MUST do p = pbuf_take(p);
00850          * in case p was not the first pbuf, it is no longer refered to
00851          * by prev. we can safely free the pbuf here.
00852          * (note that we have set p->next to NULL already so that
00853          * we will not free the rest of the chain by accident.)
00854          */
00855         pbuf_free(p);
00856         /* do not copy ref, since someone else might be using the old buffer */
00857         DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
00858         p = q;
00859       } else {
00860         /* deallocate chain */
00861         pbuf_free(head);
00862         DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
00863         return NULL;
00864       }
00865     /* p->flags != PBUF_FLAG_REF */
00866     } else {
00867       DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
00868     }
00869     /* remember this pbuf */
00870     prev = p;
00871     /* proceed to next pbuf in original chain */
00872     p = p->next;
00873   } while (p);
00874   DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));
00875   
00876   return head;
00877 }
00878 

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4