ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pbuf.c
Go to the documentation of this file.
00001 
00032 /*
00033  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00034  * All rights reserved.
00035  *
00036  * Redistribution and use in source and binary forms, with or without modification,
00037  * are permitted provided that the following conditions are met:
00038  *
00039  * 1. Redistributions of source code must retain the above copyright notice,
00040  *    this list of conditions and the following disclaimer.
00041  * 2. Redistributions in binary form must reproduce the above copyright notice,
00042  *    this list of conditions and the following disclaimer in the documentation
00043  *    and/or other materials provided with the distribution.
00044  * 3. The name of the author may not be used to endorse or promote products
00045  *    derived from this software without specific prior written permission.
00046  *
00047  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00048  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00049  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00050  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00051  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00052  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00053  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00054  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00055  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00056  * OF SUCH DAMAGE.
00057  *
00058  * This file is part of the lwIP TCP/IP stack.
00059  *
00060  * Author: Adam Dunkels <adam@sics.se>
00061  *
00062  */
00063 
00064 #include "lwip/opt.h"
00065 
00066 #include "lwip/stats.h"
00067 #include "lwip/def.h"
00068 #include "lwip/mem.h"
00069 #include "lwip/memp.h"
00070 #include "lwip/pbuf.h"
00071 #include "lwip/sys.h"
00072 #include "arch/perf.h"
00073 #if TCP_QUEUE_OOSEQ
00074 #include "lwip/tcp_impl.h"
00075 #endif
00076 #if LWIP_CHECKSUM_ON_COPY
00077 #include "lwip/inet_chksum.h"
00078 #endif
00079 
00080 #include <string.h>
00081 
00082 #define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
00083 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
00084    aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
00085 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
00086 
00087 #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
00088 #define PBUF_POOL_IS_EMPTY()
00089 #else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
00090 
00091 #ifndef PBUF_POOL_FREE_OOSEQ
00092 #define PBUF_POOL_FREE_OOSEQ 1
00093 #endif /* PBUF_POOL_FREE_OOSEQ */
00094 
00095 #if PBUF_POOL_FREE_OOSEQ
00096 #include "lwip/tcpip.h"
00097 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
00098 static u8_t pbuf_free_ooseq_queued;
00107 static void
00108 pbuf_free_ooseq(void* arg)
00109 {
00110   struct tcp_pcb* pcb;
00111   SYS_ARCH_DECL_PROTECT(old_level);
00112   LWIP_UNUSED_ARG(arg);
00113 
00114   SYS_ARCH_PROTECT(old_level);
00115   pbuf_free_ooseq_queued = 0;
00116   SYS_ARCH_UNPROTECT(old_level);
00117 
00118   for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
00119     if (NULL != pcb->ooseq) {
00121       LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
00122       tcp_segs_free(pcb->ooseq);
00123       pcb->ooseq = NULL;
00124       return;
00125     }
00126   }
00127 }
00128 
00130 static void
00131 pbuf_pool_is_empty(void)
00132 {
00133   u8_t queued;
00134   SYS_ARCH_DECL_PROTECT(old_level);
00135 
00136   SYS_ARCH_PROTECT(old_level);
00137   queued = pbuf_free_ooseq_queued;
00138   pbuf_free_ooseq_queued = 1;
00139   SYS_ARCH_UNPROTECT(old_level);
00140 
00141   if(!queued) {
00142     /* queue a call to pbuf_free_ooseq if not already queued */
00143     if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
00144       SYS_ARCH_PROTECT(old_level);
00145       pbuf_free_ooseq_queued = 0;
00146       SYS_ARCH_UNPROTECT(old_level);
00147     }
00148   }
00149 }
00150 #endif /* PBUF_POOL_FREE_OOSEQ */
00151 #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
00152 
00184 struct pbuf *
00185 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
00186 {
00187   struct pbuf *p, *q, *r;
00188   u16_t offset;
00189   s32_t rem_len; /* remaining length */
00190   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
00191 
00192   /* determine header offset */
00193   offset = 0;
00194   switch (layer) {
00195   case PBUF_TRANSPORT:
00196     /* add room for transport (often TCP) layer header */
00197     offset += PBUF_TRANSPORT_HLEN;
00198     /* FALLTHROUGH */
00199   case PBUF_IP:
00200     /* add room for IP layer header */
00201     offset += PBUF_IP_HLEN;
00202     /* FALLTHROUGH */
00203   case PBUF_LINK:
00204     /* add room for link layer header */
00205     offset += PBUF_LINK_HLEN;
00206     break;
00207   case PBUF_RAW:
00208     break;
00209   default:
00210     LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
00211     return NULL;
00212   }
00213 
00214   switch (type) {
00215   case PBUF_POOL:
00216     /* allocate head of pbuf chain into p */
00217     p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
00218     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
00219     if (p == NULL) {
00220       PBUF_POOL_IS_EMPTY();
00221       return NULL;
00222     }
00223     p->type = type;
00224     p->next = NULL;
00225 
00226     /* make the payload pointer point 'offset' bytes into pbuf data memory */
00227     p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
00228     LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
00229             ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
00230     /* the total length of the pbuf chain is the requested size */
00231     p->tot_len = length;
00232     /* set the length of the first pbuf in the chain */
00233     p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
00234     LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
00235                 ((u8_t*)p->payload + p->len <=
00236                  (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
00237     LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
00238       (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
00239     /* set reference count (needed here in case we fail) */
00240     p->ref = 1;
00241 
00242     /* now allocate the tail of the pbuf chain */
00243 
00244     /* remember first pbuf for linkage in next iteration */
00245     r = p;
00246     /* remaining length to be allocated */
00247     rem_len = length - p->len;
00248     /* any remaining pbufs to be allocated? */
00249     while (rem_len > 0) {
00250       q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
00251       if (q == NULL) {
00252         PBUF_POOL_IS_EMPTY();
00253         /* free chain so far allocated */
00254         pbuf_free(p);
00255         /* bail out unsuccesfully */
00256         return NULL;
00257       }
00258       q->type = type;
00259       q->flags = 0;
00260       q->next = NULL;
00261       /* make previous pbuf point to this pbuf */
00262       r->next = q;
00263       /* set total length of this pbuf and next in chain */
00264       LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
00265       q->tot_len = (u16_t)rem_len;
00266       /* this pbuf length is pool size, unless smaller sized tail */
00267       q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
00268       q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
00269       LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
00270               ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
00271       LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
00272                   ((u8_t*)p->payload + p->len <=
00273                    (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
00274       q->ref = 1;
00275       /* calculate remaining length to be allocated */
00276       rem_len -= q->len;
00277       /* remember this pbuf for linkage in next iteration */
00278       r = q;
00279     }
00280     /* end of chain */
00281     /*r->next = NULL;*/
00282 
00283     break;
00284   case PBUF_RAM:
00285     /* If pbuf is to be allocated in RAM, allocate memory for it. */
00286     p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
00287     if (p == NULL) {
00288       return NULL;
00289     }
00290     /* Set up internal structure of the pbuf. */
00291     p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
00292     p->len = p->tot_len = length;
00293     p->next = NULL;
00294     p->type = type;
00295 
00296     LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
00297            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
00298     break;
00299   /* pbuf references existing (non-volatile static constant) ROM payload? */
00300   case PBUF_ROM:
00301   /* pbuf references existing (externally allocated) RAM payload? */
00302   case PBUF_REF:
00303     /* only allocate memory for the pbuf structure */
00304     p = (struct pbuf *)memp_malloc(MEMP_PBUF);
00305     if (p == NULL) {
00306       LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
00307                   ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
00308                   (type == PBUF_ROM) ? "ROM" : "REF"));
00309       return NULL;
00310     }
00311     /* caller must set this field properly, afterwards */
00312     p->payload = NULL;
00313     p->len = p->tot_len = length;
00314     p->next = NULL;
00315     p->type = type;
00316     break;
00317   default:
00318     LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
00319     return NULL;
00320   }
00321   /* set reference count */
00322   p->ref = 1;
00323   /* set flags */
00324   p->flags = 0;
00325   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
00326   return p;
00327 }
00328 
00329 #if LWIP_SUPPORT_CUSTOM_PBUF
00330 
00343 struct pbuf*
00344 pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
00345                     void *payload_mem, u16_t payload_mem_len)
00346 {
00347   u16_t offset;
00348   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
00349 
00350   /* determine header offset */
00351   offset = 0;
00352   switch (l) {
00353   case PBUF_TRANSPORT:
00354     /* add room for transport (often TCP) layer header */
00355     offset += PBUF_TRANSPORT_HLEN;
00356     /* FALLTHROUGH */
00357   case PBUF_IP:
00358     /* add room for IP layer header */
00359     offset += PBUF_IP_HLEN;
00360     /* FALLTHROUGH */
00361   case PBUF_LINK:
00362     /* add room for link layer header */
00363     offset += PBUF_LINK_HLEN;
00364     break;
00365   case PBUF_RAW:
00366     break;
00367   default:
00368     LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
00369     return NULL;
00370   }
00371 
00372   if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
00373     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
00374     return NULL;
00375   }
00376 
00377   p->pbuf.next = NULL;
00378   if (payload_mem != NULL) {
00379     p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
00380   } else {
00381     p->pbuf.payload = NULL;
00382   }
00383   p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
00384   p->pbuf.len = p->pbuf.tot_len = length;
00385   p->pbuf.type = type;
00386   p->pbuf.ref = 1;
00387   return &p->pbuf;
00388 }
00389 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */
00390 
00406 void
00407 pbuf_realloc(struct pbuf *p, u16_t new_len)
00408 {
00409   struct pbuf *q;
00410   u16_t rem_len; /* remaining length */
00411   s32_t grow;
00412 
00413   LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
00414   LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
00415               p->type == PBUF_ROM ||
00416               p->type == PBUF_RAM ||
00417               p->type == PBUF_REF);
00418 
00419   /* desired length larger than current length? */
00420   if (new_len >= p->tot_len) {
00421     /* enlarging not yet supported */
00422     return;
00423   }
00424 
00425   /* the pbuf chain grows by (new_len - p->tot_len) bytes
00426    * (which may be negative in case of shrinking) */
00427   grow = new_len - p->tot_len;
00428 
00429   /* first, step over any pbufs that should remain in the chain */
00430   rem_len = new_len;
00431   q = p;
00432   /* should this pbuf be kept? */
00433   while (rem_len > q->len) {
00434     /* decrease remaining length by pbuf length */
00435     rem_len -= q->len;
00436     /* decrease total length indicator */
00437     LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
00438     q->tot_len += (u16_t)grow;
00439     /* proceed to next pbuf in chain */
00440     q = q->next;
00441     LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
00442   }
00443   /* we have now reached the new last pbuf (in q) */
00444   /* rem_len == desired length for pbuf q */
00445 
00446   /* shrink allocated memory for PBUF_RAM */
00447   /* (other types merely adjust their length fields */
00448   if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
00449     /* reallocate and adjust the length of the pbuf that will be split */
00450     q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
00451     LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
00452   }
00453   /* adjust length fields for new last pbuf */
00454   q->len = rem_len;
00455   q->tot_len = q->len;
00456 
00457   /* any remaining pbufs in chain? */
00458   if (q->next != NULL) {
00459     /* free remaining pbufs in chain */
00460     pbuf_free(q->next);
00461   }
00462   /* q is last packet in chain */
00463   q->next = NULL;
00464 
00465 }
00466 
00487 u8_t
00488 pbuf_header(struct pbuf *p, s16_t header_size_increment)
00489 {
00490   u16_t type;
00491   void *payload;
00492   u16_t increment_magnitude;
00493 
00494   LWIP_ASSERT("p != NULL", p != NULL);
00495   if ((header_size_increment == 0) || (p == NULL)) {
00496     return 0;
00497   }
00498  
00499   if (header_size_increment < 0){
00500     increment_magnitude = -header_size_increment;
00501     /* Check that we aren't going to move off the end of the pbuf */
00502     LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
00503   } else {
00504     increment_magnitude = header_size_increment;
00505 #if 0
00506     /* Can't assert these as some callers speculatively call
00507          pbuf_header() to see if it's OK.  Will return 1 below instead. */
00508     /* Check that we've got the correct type of pbuf to work with */
00509     LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 
00510                 p->type == PBUF_RAM || p->type == PBUF_POOL);
00511     /* Check that we aren't going to move off the beginning of the pbuf */
00512     LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
00513                 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
00514 #endif
00515   }
00516 
00517   type = p->type;
00518   /* remember current payload pointer */
00519   payload = p->payload;
00520 
00521   /* pbuf types containing payloads? */
00522   if (type == PBUF_RAM || type == PBUF_POOL) {
00523     /* set new payload pointer */
00524     p->payload = (u8_t *)p->payload - header_size_increment;
00525     /* boundary check fails? */
00526     if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
00527       LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
00528         ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
00529         (void *)p->payload, (void *)(p + 1)));
00530       /* restore old payload pointer */
00531       p->payload = payload;
00532       /* bail out unsuccesfully */
00533       return 1;
00534     }
00535   /* pbuf types refering to external payloads? */
00536   } else if (type == PBUF_REF || type == PBUF_ROM) {
00537     /* hide a header in the payload? */
00538     if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
00539       /* increase payload pointer */
00540       p->payload = (u8_t *)p->payload - header_size_increment;
00541     } else {
00542       /* cannot expand payload to front (yet!)
00543        * bail out unsuccesfully */
00544       return 1;
00545     }
00546   } else {
00547     /* Unknown type */
00548     LWIP_ASSERT("bad pbuf type", 0);
00549     return 1;
00550   }
00551   /* modify pbuf length fields */
00552   p->len += header_size_increment;
00553   p->tot_len += header_size_increment;
00554 
00555   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
00556     (void *)payload, (void *)p->payload, header_size_increment));
00557 
00558   return 0;
00559 }
00560 
00594 u8_t
00595 pbuf_free(struct pbuf *p)
00596 {
00597   u16_t type;
00598   struct pbuf *q;
00599   u8_t count;
00600 
00601   if (p == NULL) {
00602     LWIP_ASSERT("p != NULL", p != NULL);
00603     /* if assertions are disabled, proceed with debug output */
00604     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
00605       ("pbuf_free(p == NULL) was called.\n"));
00606     return 0;
00607   }
00608   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
00609 
00610   PERF_START;
00611 
00612   LWIP_ASSERT("pbuf_free: sane type",
00613     p->type == PBUF_RAM || p->type == PBUF_ROM ||
00614     p->type == PBUF_REF || p->type == PBUF_POOL);
00615 
00616   count = 0;
00617   /* de-allocate all consecutive pbufs from the head of the chain that
00618    * obtain a zero reference count after decrementing*/
00619   while (p != NULL) {
00620     u16_t ref;
00621     SYS_ARCH_DECL_PROTECT(old_level);
00622     /* Since decrementing ref cannot be guaranteed to be a single machine operation
00623      * we must protect it. We put the new ref into a local variable to prevent
00624      * further protection. */
00625     SYS_ARCH_PROTECT(old_level);
00626     /* all pbufs in a chain are referenced at least once */
00627     LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
00628     /* decrease reference count (number of pointers to pbuf) */
00629     ref = --(p->ref);
00630     SYS_ARCH_UNPROTECT(old_level);
00631     /* this pbuf is no longer referenced to? */
00632     if (ref == 0) {
00633       /* remember next pbuf in chain for next iteration */
00634       q = p->next;
00635       LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
00636       type = p->type;
00637 #if LWIP_SUPPORT_CUSTOM_PBUF
00638       /* is this a custom pbuf? */
00639       if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
00640         struct pbuf_custom *pc = (struct pbuf_custom*)p;
00641         LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
00642         pc->custom_free_function(p);
00643       } else
00644 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */
00645       {
00646         /* is this a pbuf from the pool? */
00647         if (type == PBUF_POOL) {
00648           memp_free(MEMP_PBUF_POOL, p);
00649         /* is this a ROM or RAM referencing pbuf? */
00650         } else if (type == PBUF_ROM || type == PBUF_REF) {
00651           memp_free(MEMP_PBUF, p);
00652         /* type == PBUF_RAM */
00653         } else {
00654           mem_free(p);
00655         }
00656       }
00657       count++;
00658       /* proceed to next pbuf */
00659       p = q;
00660     /* p->ref > 0, this pbuf is still referenced to */
00661     /* (and so the remaining pbufs in chain as well) */
00662     } else {
00663       LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
00664       /* stop walking through the chain */
00665       p = NULL;
00666     }
00667   }
00668   PERF_STOP("pbuf_free");
00669   /* return number of de-allocated pbufs */
00670   return count;
00671 }
00672 
00680 u8_t
00681 pbuf_clen(struct pbuf *p)
00682 {
00683   u8_t len;
00684 
00685   len = 0;
00686   while (p != NULL) {
00687     ++len;
00688     p = p->next;
00689   }
00690   return len;
00691 }
00692 
00699 void
00700 pbuf_ref(struct pbuf *p)
00701 {
00702   SYS_ARCH_DECL_PROTECT(old_level);
00703   /* pbuf given? */
00704   if (p != NULL) {
00705     SYS_ARCH_PROTECT(old_level);
00706     ++(p->ref);
00707     SYS_ARCH_UNPROTECT(old_level);
00708   }
00709 }
00710 
00721 void
00722 pbuf_cat(struct pbuf *h, struct pbuf *t)
00723 {
00724   struct pbuf *p;
00725 
00726   LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
00727              ((h != NULL) && (t != NULL)), return;);
00728 
00729   /* proceed to last pbuf of chain */
00730   for (p = h; p->next != NULL; p = p->next) {
00731     /* add total length of second chain to all totals of first chain */
00732     p->tot_len += t->tot_len;
00733   }
00734   /* { p is last pbuf of first h chain, p->next == NULL } */
00735   LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
00736   LWIP_ASSERT("p->next == NULL", p->next == NULL);
00737   /* add total length of second chain to last pbuf total of first chain */
00738   p->tot_len += t->tot_len;
00739   /* chain last pbuf of head (p) with first of tail (t) */
00740   p->next = t;
00741   /* p->next now references t, but the caller will drop its reference to t,
00742    * so netto there is no change to the reference count of t.
00743    */
00744 }
00745 
00762 void
00763 pbuf_chain(struct pbuf *h, struct pbuf *t)
00764 {
00765   pbuf_cat(h, t);
00766   /* t is now referenced by h */
00767   pbuf_ref(t);
00768   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
00769 }
00770 
00779 struct pbuf *
00780 pbuf_dechain(struct pbuf *p)
00781 {
00782   struct pbuf *q;
00783   u8_t tail_gone = 1;
00784   /* tail */
00785   q = p->next;
00786   /* pbuf has successor in chain? */
00787   if (q != NULL) {
00788     /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
00789     LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
00790     /* enforce invariant if assertion is disabled */
00791     q->tot_len = p->tot_len - p->len;
00792     /* decouple pbuf from remainder */
00793     p->next = NULL;
00794     /* total length of pbuf p is its own length only */
00795     p->tot_len = p->len;
00796     /* q is no longer referenced by p, free it */
00797     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
00798     tail_gone = pbuf_free(q);
00799     if (tail_gone > 0) {
00800       LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
00801                   ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
00802     }
00803     /* return remaining tail or NULL if deallocated */
00804   }
00805   /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
00806   LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
00807   return ((tail_gone > 0) ? NULL : q);
00808 }
00809 
00828 err_t
00829 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
00830 {
00831   u16_t offset_to=0, offset_from=0, len;
00832 
00833   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
00834     (void*)p_to, (void*)p_from));
00835 
00836   /* is the target big enough to hold the source? */
00837   LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
00838              (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
00839 
00840   /* iterate through pbuf chain */
00841   do
00842   {
00843     LWIP_ASSERT("p_to != NULL", p_to != NULL);
00844     /* copy one part of the original chain */
00845     if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
00846       /* complete current p_from fits into current p_to */
00847       len = p_from->len - offset_from;
00848     } else {
00849       /* current p_from does not fit into current p_to */
00850       len = p_to->len - offset_to;
00851     }
00852     MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
00853     offset_to += len;
00854     offset_from += len;
00855     LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
00856     if (offset_to == p_to->len) {
00857       /* on to next p_to (if any) */
00858       offset_to = 0;
00859       p_to = p_to->next;
00860     }
00861     LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
00862     if (offset_from >= p_from->len) {
00863       /* on to next p_from (if any) */
00864       offset_from = 0;
00865       p_from = p_from->next;
00866     }
00867 
00868     if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
00869       /* don't copy more than one packet! */
00870       LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
00871                  (p_from->next == NULL), return ERR_VAL;);
00872     }
00873     if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
00874       /* don't copy more than one packet! */
00875       LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
00876                   (p_to->next == NULL), return ERR_VAL;);
00877     }
00878   } while (p_from);
00879   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
00880   return ERR_OK;
00881 }
00882 
00894 u16_t
00895 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
00896 {
00897   struct pbuf *p;
00898   u16_t left;
00899   u16_t buf_copy_len;
00900   u16_t copied_total = 0;
00901 
00902   LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
00903   LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
00904 
00905   left = 0;
00906 
00907   if((buf == NULL) || (dataptr == NULL)) {
00908     return 0;
00909   }
00910 
00911   /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
00912   for(p = buf; len != 0 && p != NULL; p = p->next) {
00913     if ((offset != 0) && (offset >= p->len)) {
00914       /* don't copy from this buffer -> on to the next */
00915       offset -= p->len;
00916     } else {
00917       /* copy from this buffer. maybe only partially. */
00918       buf_copy_len = p->len - offset;
00919       if (buf_copy_len > len)
00920           buf_copy_len = len;
00921       /* copy the necessary parts of the buffer */
00922       MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
00923       copied_total += buf_copy_len;
00924       left += buf_copy_len;
00925       len -= buf_copy_len;
00926       offset = 0;
00927     }
00928   }
00929   return copied_total;
00930 }
00931 
00942 err_t
00943 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
00944 {
00945   struct pbuf *p;
00946   u16_t buf_copy_len;
00947   u16_t total_copy_len = len;
00948   u16_t copied_total = 0;
00949 
00950   LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
00951   LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
00952 
00953   if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
00954     return ERR_ARG;
00955   }
00956 
00957   /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
00958   for(p = buf; total_copy_len != 0; p = p->next) {
00959     LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
00960     buf_copy_len = total_copy_len;
00961     if (buf_copy_len > p->len) {
00962       /* this pbuf cannot hold all remaining data */
00963       buf_copy_len = p->len;
00964     }
00965     /* copy the necessary parts of the buffer */
00966     MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
00967     total_copy_len -= buf_copy_len;
00968     copied_total += buf_copy_len;
00969   }
00970   LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
00971   return ERR_OK;
00972 }
00973 
00986 struct pbuf*
00987 pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
00988 {
00989   struct pbuf *q;
00990   err_t err;
00991   if (p->next == NULL) {
00992     return p;
00993   }
00994   q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
00995   if (q == NULL) {
00996     /* @todo: what do we do now? */
00997     return p;
00998   }
00999   err = pbuf_copy(q, p);
01000   LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
01001   pbuf_free(p);
01002   return q;
01003 }
01004 
01005 #if LWIP_CHECKSUM_ON_COPY
01006 
01018 err_t
01019 pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
01020                  u16_t len, u16_t *chksum)
01021 {
01022   u32_t acc;
01023   u16_t copy_chksum;
01024   char *dst_ptr;
01025   LWIP_ASSERT("p != NULL", p != NULL);
01026   LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
01027   LWIP_ASSERT("chksum != NULL", chksum != NULL);
01028   LWIP_ASSERT("len != 0", len != 0);
01029 
01030   if ((start_offset >= p->len) || (start_offset + len > p->len)) {
01031     return ERR_ARG;
01032   }
01033 
01034   dst_ptr = ((char*)p->payload) + start_offset;
01035   copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
01036   if ((start_offset & 1) != 0) {
01037     copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
01038   }
01039   acc = *chksum;
01040   acc += copy_chksum;
01041   *chksum = FOLD_U32T(acc);
01042   return ERR_OK;
01043 }
01044 #endif /* LWIP_CHECKSUM_ON_COPY */
01045 
01053 u8_t
01054 pbuf_get_at(struct pbuf* p, u16_t offset)
01055 {
01056   u16_t copy_from = offset;
01057   struct pbuf* q = p;
01058 
01059   /* get the correct pbuf */
01060   while ((q != NULL) && (q->len <= copy_from)) {
01061     copy_from -= q->len;
01062     q = q->next;
01063   }
01064   /* return requested data if pbuf is OK */
01065   if ((q != NULL) && (q->len > copy_from)) {
01066     return ((u8_t*)q->payload)[copy_from];
01067   }
01068   return 0;
01069 }
01070 
01080 u16_t
01081 pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
01082 {
01083   u16_t start = offset;
01084   struct pbuf* q = p;
01085 
01086   /* get the correct pbuf */
01087   while ((q != NULL) && (q->len <= start)) {
01088     start -= q->len;
01089     q = q->next;
01090   }
01091   /* return requested data if pbuf is OK */
01092   if ((q != NULL) && (q->len > start)) {
01093     u16_t i;
01094     for(i = 0; i < n; i++) {
01095       u8_t a = pbuf_get_at(q, start + i);
01096       u8_t b = ((u8_t*)s2)[i];
01097       if (a != b) {
01098         return i+1;
01099       }
01100     }
01101     return 0;
01102   }
01103   return 0xffff;
01104 }
01105 
01116 u16_t
01117 pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
01118 {
01119   u16_t i;
01120   u16_t max = p->tot_len - mem_len;
01121   if (p->tot_len >= mem_len + start_offset) {
01122     for(i = start_offset; i <= max; ) {
01123       u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
01124       if (plus == 0) {
01125         return i;
01126       } else {
01127         i += plus;
01128       }
01129     }
01130   }
01131   return 0xFFFF;
01132 }
01133 
01144 u16_t
01145 pbuf_strstr(struct pbuf* p, const char* substr)
01146 {
01147   size_t substr_len;
01148   if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
01149     return 0xFFFF;
01150   }
01151   substr_len = strlen(substr);
01152   if (substr_len >= 0xFFFF) {
01153     return 0xFFFF;
01154   }
01155   return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
01156 }

Generated on Sat May 26 2012 04:34:57 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.