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

pbuf.c File Reference

#include "lwip/opt.h"
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"

Include dependency graph for pbuf.c:

Go to the source code of this file.

Defines

#define DEC_PBUF_STATS
#define PBUF_POOL_FAST_FREE(p)
#define PBUF_POOL_FREE(p)

Functions

void pbuf_init (void)
pbufpbuf_pool_alloc (void)
void pbuf_pool_free (struct pbuf *p)
pbufpbuf_alloc (pbuf_layer l, u16_t length, pbuf_flag flag)
void pbuf_refresh (void)
void pbuf_realloc (struct pbuf *p, u16_t new_len)
u8_t pbuf_header (struct pbuf *p, s16_t header_size)
u8_t pbuf_free (struct pbuf *p)
u8_t pbuf_clen (struct pbuf *p)
void pbuf_ref (struct pbuf *p)
void pbuf_ref_chain (struct pbuf *p)
void pbuf_chain (struct pbuf *h, struct pbuf *t)
pbufpbuf_dechain (struct pbuf *p)
pbufpbuf_take (struct pbuf *p)

Variables

u8_t pbuf_pool_memory [(PBUF_POOL_SIZE *MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE+sizeof(struct pbuf)))]
volatile u8_t pbuf_pool_free_lock
volatile u8_t pbuf_pool_alloc_lock
sys_sem_t pbuf_pool_free_sem
pbufpbuf_pool = NULL
pbufpbuf_pool_alloc_cache = NULL
pbufpbuf_pool_free_cache = NULL


Detailed Description

Packet buffer management

Packets are represented by the pbuf data structure. It supports dynamic memory allocation for packet contents or can reference externally managed packet contents both in RAM and ROM. Quick allocation for incoming packets is provided through pools with fixed sized pbufs.

Pbufs can be chained as a singly linked list, called a pbuf chain, so that a packet may span over several pbufs.

Definition in file pbuf.c.


Define Documentation

#define DEC_PBUF_STATS
 

Definition at line 406 of file pbuf.c.

#define PBUF_POOL_FAST_FREE  ) 
 

Value:

do {                                    \
                                  p->next = pbuf_pool_free_cache;       \
                                  pbuf_pool_free_cache = p;             \
                                  DEC_PBUF_STATS;                       \
                                } while (0)

Definition at line 409 of file pbuf.c.

#define PBUF_POOL_FREE  ) 
 

Value:

do {                                         \
                             sys_sem_wait(pbuf_pool_free_sem);          \
                             PBUF_POOL_FAST_FREE(p);                    \
                             sys_sem_signal(pbuf_pool_free_sem);        \
                           } while(0)

Definition at line 423 of file pbuf.c.

Referenced by pbuf_free().


Function Documentation

struct pbuf* pbuf_alloc pbuf_layer  l,
u16_t  length,
pbuf_flag  flag
 

Allocates a pbuf.

The actual memory allocated for the pbuf is determined by the layer at which the pbuf is allocated and the requested size (from the size parameter).

Parameters:
flag this parameter decides how and where the pbuf should be allocated as follows:
  • PBUF_RAM: buffer memory for pbuf is allocated as one large chunk. This includes protocol headers as well.
  • PBUF_ROM: no buffer memory is allocated for the pbuf, even for protocol headers. Additional headers must be prepended by allocating another pbuf and chain in to the front of the ROM pbuf. It is assumed that the memory used is really similar to ROM in that it is immutable and will not be changed. Memory which is dynamic should generally not be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
  • PBUF_REF: no buffer memory is allocated for the pbuf, even for protocol headers. It is assumed that the pbuf is only being used in a single thread. If the pbuf gets queued, then pbuf_take should be called to copy the buffer.
  • PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from the pbuf pool that is allocated during pbuf_init().

Returns:
the allocated pbuf. If multiple pbufs where allocated, this is the first pbuf of a pbuf chain.

Definition at line 231 of file pbuf.c.

References DBG_TRACE, DEBUGF, LWIP_ASSERT, MEM_ALIGN, MEM_ALIGN_SIZE, mem_malloc(), memp_mallocp(), MEMP_PBUF, NULL, PBUF_DEBUG, PBUF_FLAG_POOL, PBUF_FLAG_RAM, PBUF_FLAG_REF, PBUF_FLAG_ROM, PBUF_IP, PBUF_IP_HLEN, PBUF_LINK, PBUF_POOL, pbuf_pool_alloc(), pbuf_pool_free(), PBUF_RAM, PBUF_RAW, PBUF_REF, PBUF_ROM, PBUF_TRANSPORT, PBUF_TRANSPORT_HLEN, s32_t, u16_t, u32_t, and u8_t.

Referenced by arp_query(), dhcp_create_request(), etharp_query(), icmp_dest_unreach(), icmp_time_exceeded(), ip_frag(), ip_reass(), loopif_output(), netbuf_alloc(), netbuf_ref(), pbuf_take(), rt_3com905cif_low_level_input(), rt_rtl8139if_low_level_input(), and slipif_input().

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 }

Here is the call graph for this function:

void pbuf_chain struct pbuf h,
struct pbuf t
 

Link two pbufs (or chains) together.

Parameters:
h head pbuf (chain)
t tail pbuf (chain)
The ->tot_len field of the first pbuf (h) is adjusted.

Definition at line 719 of file pbuf.c.

References DBG_FRESH, DEBUGF, LWIP_ASSERT, pbuf::next, NULL, PBUF_DEBUG, pbuf_ref(), and pbuf::tot_len.

Referenced by ip_frag(), netbuf_chain(), and slipif_input().

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 }

Here is the call graph for this function:

u8_t pbuf_clen struct pbuf p  ) 
 

Count number of pbufs in a chain

Parameters:
p first pbuf of chain
Returns:
the number of pbufs in a chain

Definition at line 658 of file pbuf.c.

References len, pbuf::next, NULL, and u8_t.

00659 {
00660   u8_t len;
00661 
00662   len = 0;  
00663   while (p != NULL) {
00664     ++len;
00665     p = p->next;
00666   }
00667   return len;
00668 }

struct pbuf* pbuf_dechain struct pbuf p  ) 
 

Dechains the first pbuf from its succeeding pbufs in the chain.

Makes p->tot_len field equal to p->len.

Parameters:
p pbuf to dechain
Returns:
remainder of the pbuf chain, or NULL if it was de-allocated.

Definition at line 749 of file pbuf.c.

References DBG_STATE, DEBUGF, pbuf::len, LWIP_ASSERT, pbuf::next, NULL, PBUF_DEBUG, pbuf_free(), pbuf::tot_len, and u8_t.

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 }

Here is the call graph for this function:

u8_t pbuf_free struct pbuf p  ) 
 

Free a pbuf (chain) from usage, de-allocate non-used head of chain.

Decrements the pbuf reference count. If it reaches zero, the pbuf is deallocated.

For a pbuf chain, this is repeated for each pbuf in the chain, until a non-zero reference count is encountered, or the end of the chain is reached.

Parameters:
pbuf pbuf (chain) to be freed from one user.
Returns:
the number of unreferenced pbufs that were de-allocated from the head of the chain.
Note:
the reference counter of a pbuf equals the number of pointers that refer to the pbuf (or into the pbuf).

For internal use only.

examples:

1->2->3 becomes ...1->3 3->3->3 becomes 2->3->3 1->1->2 becomes ....->1 2->1->1 becomes 1->1->1 1->1->1 becomes .......

Definition at line 589 of file pbuf.c.

References DBG_TRACE, DEBUGF, pbuf::flags, pbuf::len, LWIP_ASSERT, mem_free(), memp_freep(), MEMP_PBUF, pbuf::next, NULL, pbuf::payload, PBUF_DEBUG, PBUF_FLAG_POOL, PBUF_FLAG_RAM, PBUF_FLAG_REF, PBUF_FLAG_ROM, PBUF_POOL_FREE, pbuf_refresh(), pbuf::ref, sys_allow_interrupts(), sys_stop_interrupts(), pbuf::tot_len, and u8_t.

Referenced by arp_arp_input(), dhcp_delete_request(), dhcp_recv(), dhcp_stop(), etharp_arp_input(), etharp_query(), etharp_tmr(), http_recv(), icmp_dest_unreach(), icmp_input(), icmp_time_exceeded(), ip_forward(), ip_frag(), ip_input(), ip_reass(), netbuf_alloc(), netbuf_delete(), netbuf_free(), netbuf_ref(), netconn_delete(), pbuf_dechain(), pbuf_realloc(), pbuf_take(), rt_3c905cif_input(), rt_rtl8139if_input(), tcpip_input(), and update_arp_entry().

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 }

Here is the call graph for this function:

u8_t pbuf_header struct pbuf p,
s16_t  header_size
 

Adjusts the payload pointer to hide or reveal headers in the payload.

Adjusts the ->payload pointer so that space for a header (dis)appears in the pbuf payload.

The ->payload, ->tot_len and ->len fields are adjusted.

Parameters:
hdr_size Number of bytes to increment header size which increases the size of the pbuf. New space is on the front. (Using a negative value decreases the header size.)
PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so the call will fail. A check is made that the increase in header size does not move the payload pointer in front of the start of the buffer.
Returns:
1 on failure, 0 on success.

Definition at line 520 of file pbuf.c.

References DEBUGF, pbuf::flags, pbuf::len, pbuf::payload, PBUF_DEBUG, PBUF_FLAG_POOL, PBUF_FLAG_RAM, PBUF_FLAG_REF, PBUF_FLAG_ROM, s16_t, pbuf::tot_len, and u8_t.

Referenced by etharp_output(), icmp_input(), ip_input(), ip_output_if(), rt_3c905cif_input(), and rt_rtl8139if_input().

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 }

void pbuf_init void   ) 
 

Initializes the pbuf module.

A large part of memory is allocated for holding the pool of pbufs. The size of the individual pbufs in the pool is given by the size parameter, and the number of pbufs in the pool by the num parameter.

After the memory has been allocated, the pbufs are set up. The ->next pointer in each pbuf is set up to point to the next pbuf in the pool.

Definition at line 86 of file pbuf.c.

References pbuf::len, LWIP_ASSERT, MEM_ALIGN, pbuf::next, NULL, pbuf_pool, pbuf_pool_alloc_lock, pbuf_pool_free_lock, pbuf_pool_free_sem, pbuf_pool_memory, sys_sem_new(), u16_t, and u8_t.

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 }

Here is the call graph for this function:

struct pbuf* pbuf_pool_alloc void   )  [static]
 

For internal use only.

only called from pbuf_alloc()

Definition at line 124 of file pbuf.c.

References pbuf::next, NULL, pbuf_pool, pbuf_pool_alloc_cache, pbuf_pool_alloc_lock, pbuf_pool_free_lock, sys_allow_interrupts(), and sys_stop_interrupts().

Referenced by pbuf_alloc().

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 }

Here is the call graph for this function:

void pbuf_pool_free struct pbuf p  )  [static]
 

For internal use only.

only called from pbuf_alloc()

Definition at line 180 of file pbuf.c.

References pbuf::next, NULL, pbuf_pool_alloc_cache, sys_allow_interrupts(), and sys_stop_interrupts().

Referenced by pbuf_alloc().

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 }

Here is the call graph for this function:

void pbuf_realloc struct pbuf p,
u16_t  new_len
 

Shrink a pbuf chain to a desired length.

Parameters:
p pbuf to shrink.
new_len desired new length of pbuf chain
Depending on the desired length, the first few pbufs in a chain might be skipped and left unchanged. The new last pbuf in the chain will be resized, and any remaining pbufs will be freed.

Note:
If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.

Bug:
Cannot grow the size of a pbuf (chain) (yet).

Definition at line 445 of file pbuf.c.

References pbuf::flags, pbuf::len, LWIP_ASSERT, mem_realloc(), NULL, PBUF_FLAG_POOL, PBUF_FLAG_RAM, PBUF_FLAG_REF, PBUF_FLAG_ROM, pbuf_free(), pbuf_refresh(), s16_t, pbuf::tot_len, u16_t, and u8_t.

Referenced by dhcp_discover(), dhcp_inform(), dhcp_rebind(), dhcp_release(), dhcp_renew(), dhcp_select(), ip_frag(), ip_input(), and slipif_input().

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 }

Here is the call graph for this function:

void pbuf_ref struct pbuf p  ) 
 

Increment the reference count of the pbuf.

Parameters:
p pbuf to increase reference counter of

Definition at line 677 of file pbuf.c.

References NULL, pbuf::ref, sys_allow_interrupts(), and sys_stop_interrupts().

Referenced by etharp_query(), and pbuf_chain().

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 }

Here is the call graph for this function:

void pbuf_ref_chain struct pbuf p  ) 
 

Increment the reference count of all pbufs in a chain.

Parameters:
p first pbuf of chain

Definition at line 696 of file pbuf.c.

References pbuf::next, NULL, pbuf::ref, sys_allow_interrupts(), and sys_stop_interrupts().

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 }

Here is the call graph for this function:

void pbuf_refresh void   ) 
 

Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool list (if possible).

Definition at line 365 of file pbuf.c.

References pbuf::next, NULL, pbuf_pool, pbuf_pool_alloc_lock, pbuf_pool_free_cache, pbuf_pool_free_lock, pbuf_pool_free_sem, sys_allow_interrupts(), sys_sem_signal(), sys_sem_wait(), and sys_stop_interrupts().

Referenced by pbuf_free(), and pbuf_realloc().

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 }

Here is the call graph for this function:

struct pbuf* pbuf_take struct pbuf p  ) 
 

Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.

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 pbuf_take()!

Any replaced pbufs will be freed through pbuf_free().

Used to queue packets on behalf of the lwIP stack, such as ARP based queueing.

Parameters:
p Head of pbuf chain to process
Returns:
Pointer to new head of pbuf chain

Definition at line 797 of file pbuf.c.

References DBG_TRACE, DEBUGF, LWIP_ASSERT, NULL, pbuf_alloc(), PBUF_DEBUG, PBUF_FLAG_REF, pbuf_free(), PBUF_POOL, PBUF_RAM, and PBUF_RAW.

Referenced by etharp_query().

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 }

Here is the call graph for this function:


Variable Documentation

struct pbuf* pbuf_pool = NULL [static]
 

Definition at line 69 of file pbuf.c.

Referenced by pbuf_init(), pbuf_pool_alloc(), and pbuf_refresh().

struct pbuf* pbuf_pool_alloc_cache = NULL [static]
 

Definition at line 70 of file pbuf.c.

Referenced by pbuf_pool_alloc(), and pbuf_pool_free().

volatile u8_t pbuf_pool_alloc_lock [static]
 

Definition at line 65 of file pbuf.c.

Referenced by pbuf_init(), pbuf_pool_alloc(), and pbuf_refresh().

struct pbuf* pbuf_pool_free_cache = NULL [static]
 

Definition at line 71 of file pbuf.c.

Referenced by pbuf_refresh().

volatile u8_t pbuf_pool_free_lock [static]
 

Definition at line 65 of file pbuf.c.

Referenced by pbuf_init(), pbuf_pool_alloc(), and pbuf_refresh().

sys_sem_t pbuf_pool_free_sem [static]
 

Definition at line 66 of file pbuf.c.

Referenced by pbuf_init(), and pbuf_refresh().

u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))] [static]
 

Definition at line 62 of file pbuf.c.

Referenced by pbuf_init().


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