Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
pbuf.c
00001 /** 00002 * @file 00003 * Packet buffer management 00004 * 00005 * Packets are built from the pbuf data structure. It supports dynamic 00006 * memory allocation for packet contents or can reference externally 00007 * managed packet contents both in RAM and ROM. Quick allocation for 00008 * incoming packets is provided through pools with fixed sized pbufs. 00009 * 00010 * A packet may span over multiple pbufs, chained as a singly linked 00011 * list. This is called a "pbuf chain". 00012 * 00013 * Multiple packets may be queued, also using this singly linked list. 00014 * This is called a "packet queue". 00015 * 00016 * So, a packet queue consists of one or more pbuf chains, each of 00017 * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE 00018 * NOT SUPPORTED!!! Use helper structs to queue multiple packets. 00019 * 00020 * The differences between a pbuf chain and a packet queue are very 00021 * precise but subtle. 00022 * 00023 * The last pbuf of a packet has a ->tot_len field that equals the 00024 * ->len field. It can be found by traversing the list. If the last 00025 * pbuf of a packet has a ->next field other than NULL, more packets 00026 * are on the queue. 00027 * 00028 * Therefore, looping through a pbuf of a single packet, has an 00029 * loop end condition (tot_len == p->len), NOT (next == NULL). 00030 */ 00031 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.h" 00075 #endif 00076 00077 #include <string.h> 00078 00079 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) 00080 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically 00081 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ 00082 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) 00083 00084 #if TCP_QUEUE_OOSEQ 00085 #define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0) 00086 #else 00087 #define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0) 00088 #endif 00089 00090 00091 #if TCP_QUEUE_OOSEQ 00092 /** 00093 * Attempt to reclaim some memory from queued out-of-sequence TCP segments 00094 * if we run out of pool pbufs. It's better to give priority to new packets 00095 * if we're running out. 00096 * 00097 * @return the allocated pbuf. 00098 */ 00099 static struct pbuf * 00100 alloc_pool_pbuf(void) 00101 { 00102 struct tcp_pcb *pcb; 00103 struct pbuf *p; 00104 00105 retry: 00106 p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); 00107 if (NULL == p) { 00108 for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { 00109 if (NULL != pcb->ooseq) { 00110 tcp_segs_free(pcb->ooseq); 00111 pcb->ooseq = NULL; 00112 goto retry; 00113 } 00114 } 00115 } 00116 return p; 00117 } 00118 #endif /* TCP_QUEUE_OOSEQ */ 00119 00120 /** 00121 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). 00122 * 00123 * The actual memory allocated for the pbuf is determined by the 00124 * layer at which the pbuf is allocated and the requested size 00125 * (from the size parameter). 00126 * 00127 * @param layer flag to define header size 00128 * @param length size of the pbuf's payload 00129 * @param type this parameter decides how and where the pbuf 00130 * should be allocated as follows: 00131 * 00132 * - PBUF_RAM: buffer memory for pbuf is allocated as one large 00133 * chunk. This includes protocol headers as well. 00134 * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for 00135 * protocol headers. Additional headers must be prepended 00136 * by allocating another pbuf and chain in to the front of 00137 * the ROM pbuf. It is assumed that the memory used is really 00138 * similar to ROM in that it is immutable and will not be 00139 * changed. Memory which is dynamic should generally not 00140 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. 00141 * - PBUF_REF: no buffer memory is allocated for the pbuf, even for 00142 * protocol headers. It is assumed that the pbuf is only 00143 * being used in a single thread. If the pbuf gets queued, 00144 * then pbuf_take should be called to copy the buffer. 00145 * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from 00146 * the pbuf pool that is allocated during pbuf_init(). 00147 * 00148 * @return the allocated pbuf. If multiple pbufs where allocated, this 00149 * is the first pbuf of a pbuf chain. 00150 */ 00151 struct pbuf * 00152 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) 00153 { 00154 struct pbuf *p, *q, *r; 00155 u16_t offset; 00156 s32_t rem_len; /* remaining length */ 00157 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length)); 00158 00159 /* determine header offset */ 00160 offset = 0; 00161 switch (layer) { 00162 case PBUF_TRANSPORT: 00163 /* add room for transport (often TCP) layer header */ 00164 offset += PBUF_TRANSPORT_HLEN; 00165 /* FALLTHROUGH */ 00166 case PBUF_IP: 00167 /* add room for IP layer header */ 00168 offset += PBUF_IP_HLEN; 00169 /* FALLTHROUGH */ 00170 case PBUF_LINK: 00171 /* add room for link layer header */ 00172 offset += PBUF_LINK_HLEN; 00173 break; 00174 case PBUF_RAW: 00175 break; 00176 default: 00177 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); 00178 return NULL; 00179 } 00180 00181 switch (type) { 00182 case PBUF_POOL: 00183 /* allocate head of pbuf chain into p */ 00184 ALLOC_POOL_PBUF(p); 00185 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); 00186 if (p == NULL) { 00187 return NULL; 00188 } 00189 p->type = type; 00190 p->next = NULL; 00191 00192 /* make the payload pointer point 'offset' bytes into pbuf data memory */ 00193 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); 00194 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", 00195 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00196 /* the total length of the pbuf chain is the requested size */ 00197 p->tot_len = length; 00198 /* set the length of the first pbuf in the chain */ 00199 p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); 00200 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", 00201 ((u8_t*)p->payload + p->len <= 00202 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); 00203 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", 00204 (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); 00205 /* set reference count (needed here in case we fail) */ 00206 p->ref = 1; 00207 00208 /* now allocate the tail of the pbuf chain */ 00209 00210 /* remember first pbuf for linkage in next iteration */ 00211 r = p; 00212 /* remaining length to be allocated */ 00213 rem_len = length - p->len; 00214 /* any remaining pbufs to be allocated? */ 00215 while (rem_len > 0) { 00216 ALLOC_POOL_PBUF(q); 00217 if (q == NULL) { 00218 /* free chain so far allocated */ 00219 pbuf_free(p); 00220 /* bail out unsuccesfully */ 00221 return NULL; 00222 } 00223 q->type = type; 00224 q->flags = 0; 00225 q->next = NULL; 00226 /* make previous pbuf point to this pbuf */ 00227 r->next = q; 00228 /* set total length of this pbuf and next in chain */ 00229 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); 00230 q->tot_len = (u16_t)rem_len; 00231 /* this pbuf length is pool size, unless smaller sized tail */ 00232 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); 00233 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); 00234 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", 00235 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); 00236 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", 00237 ((u8_t*)p->payload + p->len <= 00238 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); 00239 q->ref = 1; 00240 /* calculate remaining length to be allocated */ 00241 rem_len -= q->len; 00242 /* remember this pbuf for linkage in next iteration */ 00243 r = q; 00244 } 00245 /* end of chain */ 00246 /*r->next = NULL;*/ 00247 00248 break; 00249 case PBUF_RAM: 00250 /* If pbuf is to be allocated in RAM, allocate memory for it. */ 00251 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); 00252 if (p == NULL) { 00253 return NULL; 00254 } 00255 /* Set up internal structure of the pbuf. */ 00256 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); 00257 p->len = p->tot_len = length; 00258 p->next = NULL; 00259 p->type = type; 00260 00261 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", 00262 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00263 break; 00264 /* pbuf references existing (non-volatile static constant) ROM payload? */ 00265 case PBUF_ROM: 00266 /* pbuf references existing (externally allocated) RAM payload? */ 00267 case PBUF_REF: 00268 /* only allocate memory for the pbuf structure */ 00269 p = (struct pbuf *)memp_malloc(MEMP_PBUF); 00270 if (p == NULL) { 00271 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", 00272 (type == PBUF_ROM) ? "ROM" : "REF")); 00273 return NULL; 00274 } 00275 /* caller must set this field properly, afterwards */ 00276 p->payload = NULL; 00277 p->len = p->tot_len = length; 00278 p->next = NULL; 00279 p->type = type; 00280 break; 00281 default: 00282 LWIP_ASSERT("pbuf_alloc: erroneous type", 0); 00283 return NULL; 00284 } 00285 /* set reference count */ 00286 p->ref = 1; 00287 /* set flags */ 00288 p->flags = 0; 00289 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); 00290 return p; 00291 } 00292 00293 00294 /** 00295 * Shrink a pbuf chain to a desired length. 00296 * 00297 * @param p pbuf to shrink. 00298 * @param new_len desired new length of pbuf chain 00299 * 00300 * Depending on the desired length, the first few pbufs in a chain might 00301 * be skipped and left unchanged. The new last pbuf in the chain will be 00302 * resized, and any remaining pbufs will be freed. 00303 * 00304 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. 00305 * @note May not be called on a packet queue. 00306 * 00307 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). 00308 */ 00309 void 00310 pbuf_realloc(struct pbuf *p, u16_t new_len) 00311 { 00312 struct pbuf *q; 00313 u16_t rem_len; /* remaining length */ 00314 s32_t grow; 00315 00316 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); 00317 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || 00318 p->type == PBUF_ROM || 00319 p->type == PBUF_RAM || 00320 p->type == PBUF_REF); 00321 00322 /* desired length larger than current length? */ 00323 if (new_len >= p->tot_len) { 00324 /* enlarging not yet supported */ 00325 return; 00326 } 00327 00328 /* the pbuf chain grows by (new_len - p->tot_len) bytes 00329 * (which may be negative in case of shrinking) */ 00330 grow = new_len - p->tot_len; 00331 00332 /* first, step over any pbufs that should remain in the chain */ 00333 rem_len = new_len; 00334 q = p; 00335 /* should this pbuf be kept? */ 00336 while (rem_len > q->len) { 00337 /* decrease remaining length by pbuf length */ 00338 rem_len -= q->len; 00339 /* decrease total length indicator */ 00340 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); 00341 q->tot_len += (u16_t)grow; 00342 /* proceed to next pbuf in chain */ 00343 q = q->next; 00344 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); 00345 } 00346 /* we have now reached the new last pbuf (in q) */ 00347 /* rem_len == desired length for pbuf q */ 00348 00349 /* shrink allocated memory for PBUF_RAM */ 00350 /* (other types merely adjust their length fields */ 00351 if ((q->type == PBUF_RAM) && (rem_len != q->len)) { 00352 /* reallocate and adjust the length of the pbuf that will be split */ 00353 q = (struct pbuf *)mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); 00354 LWIP_ASSERT("mem_realloc give q == NULL", q != NULL); 00355 } 00356 /* adjust length fields for new last pbuf */ 00357 q->len = rem_len; 00358 q->tot_len = q->len; 00359 00360 /* any remaining pbufs in chain? */ 00361 if (q->next != NULL) { 00362 /* free remaining pbufs in chain */ 00363 pbuf_free(q->next); 00364 } 00365 /* q is last packet in chain */ 00366 q->next = NULL; 00367 00368 } 00369 00370 /** 00371 * Adjusts the payload pointer to hide or reveal headers in the payload. 00372 * 00373 * Adjusts the ->payload pointer so that space for a header 00374 * (dis)appears in the pbuf payload. 00375 * 00376 * The ->payload, ->tot_len and ->len fields are adjusted. 00377 * 00378 * @param p pbuf to change the header size. 00379 * @param header_size_increment Number of bytes to increment header size which 00380 * increases the size of the pbuf. New space is on the front. 00381 * (Using a negative value decreases the header size.) 00382 * If hdr_size_inc is 0, this function does nothing and returns succesful. 00383 * 00384 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00385 * the call will fail. A check is made that the increase in header size does 00386 * not move the payload pointer in front of the start of the buffer. 00387 * @return non-zero on failure, zero on success. 00388 * 00389 */ 00390 u8_t 00391 pbuf_header(struct pbuf *p, s16_t header_size_increment) 00392 { 00393 u16_t type; 00394 void *payload; 00395 u16_t increment_magnitude; 00396 00397 LWIP_ASSERT("p != NULL", p != NULL); 00398 if ((header_size_increment == 0) || (p == NULL)) 00399 return 0; 00400 00401 if (header_size_increment < 0){ 00402 increment_magnitude = -header_size_increment; 00403 /* Check that we aren't going to move off the end of the pbuf */ 00404 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); 00405 } else { 00406 increment_magnitude = header_size_increment; 00407 #if 0 00408 /* Can't assert these as some callers speculatively call 00409 pbuf_header() to see if it's OK. Will return 1 below instead. */ 00410 /* Check that we've got the correct type of pbuf to work with */ 00411 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 00412 p->type == PBUF_RAM || p->type == PBUF_POOL); 00413 /* Check that we aren't going to move off the beginning of the pbuf */ 00414 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", 00415 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); 00416 #endif 00417 } 00418 00419 type = p->type; 00420 /* remember current payload pointer */ 00421 payload = p->payload; 00422 00423 /* pbuf types containing payloads? */ 00424 if (type == PBUF_RAM || type == PBUF_POOL) { 00425 /* set new payload pointer */ 00426 p->payload = (u8_t *)p->payload - header_size_increment; 00427 /* boundary check fails? */ 00428 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { 00429 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", 00430 (void *)p->payload, 00431 (void *)(p + 1)));\ 00432 /* restore old payload pointer */ 00433 p->payload = payload; 00434 /* bail out unsuccesfully */ 00435 return 1; 00436 } 00437 /* pbuf types refering to external payloads? */ 00438 } else if (type == PBUF_REF || type == PBUF_ROM) { 00439 /* hide a header in the payload? */ 00440 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { 00441 /* increase payload pointer */ 00442 p->payload = (u8_t *)p->payload - header_size_increment; 00443 } else { 00444 /* cannot expand payload to front (yet!) 00445 * bail out unsuccesfully */ 00446 return 1; 00447 } 00448 } 00449 else { 00450 /* Unknown type */ 00451 LWIP_ASSERT("bad pbuf type", 0); 00452 return 1; 00453 } 00454 /* modify pbuf length fields */ 00455 p->len += header_size_increment; 00456 p->tot_len += header_size_increment; 00457 00458 LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n", 00459 (void *)payload, (void *)p->payload, header_size_increment)); 00460 00461 return 0; 00462 } 00463 00464 /** 00465 * Dereference a pbuf chain or queue and deallocate any no-longer-used 00466 * pbufs at the head of this chain or queue. 00467 * 00468 * Decrements the pbuf reference count. If it reaches zero, the pbuf is 00469 * deallocated. 00470 * 00471 * For a pbuf chain, this is repeated for each pbuf in the chain, 00472 * up to the first pbuf which has a non-zero reference count after 00473 * decrementing. So, when all reference counts are one, the whole 00474 * chain is free'd. 00475 * 00476 * @param p The pbuf (chain) to be dereferenced. 00477 * 00478 * @return the number of pbufs that were de-allocated 00479 * from the head of the chain. 00480 * 00481 * @note MUST NOT be called on a packet queue (Not verified to work yet). 00482 * @note the reference counter of a pbuf equals the number of pointers 00483 * that refer to the pbuf (or into the pbuf). 00484 * 00485 * @internal examples: 00486 * 00487 * Assuming existing chains a->b->c with the following reference 00488 * counts, calling pbuf_free(a) results in: 00489 * 00490 * 1->2->3 becomes ...1->3 00491 * 3->3->3 becomes 2->3->3 00492 * 1->1->2 becomes ......1 00493 * 2->1->1 becomes 1->1->1 00494 * 1->1->1 becomes ....... 00495 * 00496 */ 00497 u8_t 00498 pbuf_free(struct pbuf *p) 00499 { 00500 u16_t type; 00501 struct pbuf *q; 00502 u8_t count; 00503 00504 if (p == NULL) { 00505 LWIP_ASSERT("p != NULL", p != NULL); 00506 /* if assertions are disabled, proceed with debug output */ 00507 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); 00508 return 0; 00509 } 00510 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); 00511 00512 PERF_START; 00513 00514 LWIP_ASSERT("pbuf_free: sane type", 00515 p->type == PBUF_RAM || p->type == PBUF_ROM || 00516 p->type == PBUF_REF || p->type == PBUF_POOL); 00517 00518 count = 0; 00519 /* de-allocate all consecutive pbufs from the head of the chain that 00520 * obtain a zero reference count after decrementing*/ 00521 while (p != NULL) { 00522 u16_t ref; 00523 SYS_ARCH_DECL_PROTECT(old_level); 00524 /* Since decrementing ref cannot be guaranteed to be a single machine operation 00525 * we must protect it. We put the new ref into a local variable to prevent 00526 * further protection. */ 00527 SYS_ARCH_PROTECT(old_level); 00528 /* all pbufs in a chain are referenced at least once */ 00529 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); 00530 /* decrease reference count (number of pointers to pbuf) */ 00531 ref = --(p->ref); 00532 SYS_ARCH_UNPROTECT(old_level); 00533 /* this pbuf is no longer referenced to? */ 00534 if (ref == 0) { 00535 /* remember next pbuf in chain for next iteration */ 00536 q = p->next; 00537 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); 00538 type = p->type; 00539 /* is this a pbuf from the pool? */ 00540 if (type == PBUF_POOL) { 00541 memp_free(MEMP_PBUF_POOL, p); 00542 /* is this a ROM or RAM referencing pbuf? */ 00543 } else if (type == PBUF_ROM || type == PBUF_REF) { 00544 memp_free(MEMP_PBUF, p); 00545 /* type == PBUF_RAM */ 00546 } else { 00547 mem_free(p); 00548 } 00549 count++; 00550 /* proceed to next pbuf */ 00551 p = q; 00552 /* p->ref > 0, this pbuf is still referenced to */ 00553 /* (and so the remaining pbufs in chain as well) */ 00554 } else { 00555 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); 00556 /* stop walking through the chain */ 00557 p = NULL; 00558 } 00559 } 00560 PERF_STOP("pbuf_free"); 00561 /* return number of de-allocated pbufs */ 00562 return count; 00563 } 00564 00565 /** 00566 * Count number of pbufs in a chain 00567 * 00568 * @param p first pbuf of chain 00569 * @return the number of pbufs in a chain 00570 */ 00571 00572 u8_t 00573 pbuf_clen(struct pbuf *p) 00574 { 00575 u8_t len; 00576 00577 len = 0; 00578 while (p != NULL) { 00579 ++len; 00580 p = p->next; 00581 } 00582 return len; 00583 } 00584 00585 /** 00586 * Increment the reference count of the pbuf. 00587 * 00588 * @param p pbuf to increase reference counter of 00589 * 00590 */ 00591 void 00592 pbuf_ref(struct pbuf *p) 00593 { 00594 SYS_ARCH_DECL_PROTECT(old_level); 00595 /* pbuf given? */ 00596 if (p != NULL) { 00597 SYS_ARCH_PROTECT(old_level); 00598 ++(p->ref); 00599 SYS_ARCH_UNPROTECT(old_level); 00600 } 00601 } 00602 00603 /** 00604 * Concatenate two pbufs (each may be a pbuf chain) and take over 00605 * the caller's reference of the tail pbuf. 00606 * 00607 * @note The caller MAY NOT reference the tail pbuf afterwards. 00608 * Use pbuf_chain() for that purpose. 00609 * 00610 * @see pbuf_chain() 00611 */ 00612 00613 void 00614 pbuf_cat(struct pbuf *h, struct pbuf *t) 00615 { 00616 struct pbuf *p; 00617 00618 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", 00619 ((h != NULL) && (t != NULL)), return;); 00620 00621 /* proceed to last pbuf of chain */ 00622 for (p = h; p->next != NULL; p = p->next) { 00623 /* add total length of second chain to all totals of first chain */ 00624 p->tot_len += t->tot_len; 00625 } 00626 /* { p is last pbuf of first h chain, p->next == NULL } */ 00627 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); 00628 LWIP_ASSERT("p->next == NULL", p->next == NULL); 00629 /* add total length of second chain to last pbuf total of first chain */ 00630 p->tot_len += t->tot_len; 00631 /* chain last pbuf of head (p) with first of tail (t) */ 00632 p->next = t; 00633 /* p->next now references t, but the caller will drop its reference to t, 00634 * so netto there is no change to the reference count of t. 00635 */ 00636 } 00637 00638 /** 00639 * Chain two pbufs (or pbuf chains) together. 00640 * 00641 * The caller MUST call pbuf_free(t) once it has stopped 00642 * using it. Use pbuf_cat() instead if you no longer use t. 00643 * 00644 * @param h head pbuf (chain) 00645 * @param t tail pbuf (chain) 00646 * @note The pbufs MUST belong to the same packet. 00647 * @note MAY NOT be called on a packet queue. 00648 * 00649 * The ->tot_len fields of all pbufs of the head chain are adjusted. 00650 * The ->next field of the last pbuf of the head chain is adjusted. 00651 * The ->ref field of the first pbuf of the tail chain is adjusted. 00652 * 00653 */ 00654 void 00655 pbuf_chain(struct pbuf *h, struct pbuf *t) 00656 { 00657 pbuf_cat(h, t); 00658 /* t is now referenced by h */ 00659 pbuf_ref(t); 00660 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); 00661 } 00662 00663 /** 00664 * Dechains the first pbuf from its succeeding pbufs in the chain. 00665 * 00666 * Makes p->tot_len field equal to p->len. 00667 * @param p pbuf to dechain 00668 * @return remainder of the pbuf chain, or NULL if it was de-allocated. 00669 * @note May not be called on a packet queue. 00670 */ 00671 struct pbuf * 00672 pbuf_dechain(struct pbuf *p) 00673 { 00674 struct pbuf *q; 00675 u8_t tail_gone = 1; 00676 /* tail */ 00677 q = p->next; 00678 /* pbuf has successor in chain? */ 00679 if (q != NULL) { 00680 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00681 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); 00682 /* enforce invariant if assertion is disabled */ 00683 q->tot_len = p->tot_len - p->len; 00684 /* decouple pbuf from remainder */ 00685 p->next = NULL; 00686 /* total length of pbuf p is its own length only */ 00687 p->tot_len = p->len; 00688 /* q is no longer referenced by p, free it */ 00689 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); 00690 tail_gone = pbuf_free(q); 00691 if (tail_gone > 0) { 00692 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, 00693 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); 00694 } 00695 /* return remaining tail or NULL if deallocated */ 00696 } 00697 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00698 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); 00699 return ((tail_gone > 0) ? NULL : q); 00700 } 00701 00702 /** 00703 * 00704 * Create PBUF_RAM copies of pbufs. 00705 * 00706 * Used to queue packets on behalf of the lwIP stack, such as 00707 * ARP based queueing. 00708 * 00709 * @note You MUST explicitly use p = pbuf_take(p); 00710 * 00711 * @note Only one packet is copied, no packet queue! 00712 * 00713 * @param p_to pbuf destination of the copy 00714 * @param p_from pbuf source of the copy 00715 * 00716 * @return ERR_OK if pbuf was copied 00717 * ERR_ARG if one of the pbufs is NULL or p_to is not big 00718 * enough to hold p_from 00719 */ 00720 err_t 00721 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) 00722 { 00723 u16_t offset_to=0, offset_from=0, len; 00724 00725 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n", 00726 (void*)p_to, (void*)p_from)); 00727 00728 /* is the target big enough to hold the source? */ 00729 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && 00730 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); 00731 00732 /* iterate through pbuf chain */ 00733 do 00734 { 00735 LWIP_ASSERT("p_to != NULL", p_to != NULL); 00736 /* copy one part of the original chain */ 00737 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { 00738 /* complete current p_from fits into current p_to */ 00739 len = p_from->len - offset_from; 00740 } else { 00741 /* current p_from does not fit into current p_to */ 00742 len = p_to->len - offset_to; 00743 } 00744 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); 00745 offset_to += len; 00746 offset_from += len; 00747 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); 00748 if (offset_to == p_to->len) { 00749 /* on to next p_to (if any) */ 00750 offset_to = 0; 00751 p_to = p_to->next; 00752 } 00753 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); 00754 if (offset_from >= p_from->len) { 00755 /* on to next p_from (if any) */ 00756 offset_from = 0; 00757 p_from = p_from->next; 00758 } 00759 00760 if((p_from != NULL) && (p_from->len == p_from->tot_len)) { 00761 /* don't copy more than one packet! */ 00762 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00763 (p_from->next == NULL), return ERR_VAL;); 00764 } 00765 if((p_to != NULL) && (p_to->len == p_to->tot_len)) { 00766 /* don't copy more than one packet! */ 00767 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00768 (p_to->next == NULL), return ERR_VAL;); 00769 } 00770 } while (p_from); 00771 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n")); 00772 return ERR_OK; 00773 } 00774 00775 /** 00776 * Copy (part of) the contents of a packet buffer 00777 * to an application supplied buffer. 00778 * 00779 * @param buf the pbuf from which to copy data 00780 * @param dataptr the application supplied buffer 00781 * @param len length of data to copy (dataptr must be big enough). No more 00782 * than buf->tot_len will be copied, irrespective of len 00783 * @param offset offset into the packet buffer from where to begin copying len bytes 00784 * @return the number of bytes copied, or 0 on failure 00785 */ 00786 u16_t 00787 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) 00788 { 00789 struct pbuf *p; 00790 u16_t left; 00791 u16_t buf_copy_len; 00792 u16_t copied_total = 0; 00793 00794 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); 00795 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); 00796 00797 left = 0; 00798 00799 if((buf == NULL) || (dataptr == NULL)) { 00800 return 0; 00801 } 00802 00803 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00804 for(p = buf; len != 0 && p != NULL; p = p->next) { 00805 if ((offset != 0) && (offset >= p->len)) { 00806 /* don't copy from this buffer -> on to the next */ 00807 offset -= p->len; 00808 } else { 00809 /* copy from this buffer. maybe only partially. */ 00810 buf_copy_len = p->len - offset; 00811 if (buf_copy_len > len) 00812 buf_copy_len = len; 00813 /* copy the necessary parts of the buffer */ 00814 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); 00815 copied_total += buf_copy_len; 00816 left += buf_copy_len; 00817 len -= buf_copy_len; 00818 offset = 0; 00819 } 00820 } 00821 return copied_total; 00822 } 00823 00824 /** 00825 * Copy application supplied data into a pbuf. 00826 * This function can only be used to copy the equivalent of buf->tot_len data. 00827 * 00828 * @param buf pbuf to fill with data 00829 * @param dataptr application supplied data buffer 00830 * @param len length of the application supplied data buffer 00831 * 00832 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough 00833 */ 00834 err_t 00835 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) 00836 { 00837 struct pbuf *p; 00838 u16_t buf_copy_len; 00839 u16_t total_copy_len = len; 00840 u16_t copied_total = 0; 00841 00842 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); 00843 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); 00844 00845 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { 00846 return ERR_ARG; 00847 } 00848 00849 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00850 for(p = buf; total_copy_len != 0; p = p->next) { 00851 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); 00852 buf_copy_len = total_copy_len; 00853 if (buf_copy_len > p->len) { 00854 /* this pbuf cannot hold all remaining data */ 00855 buf_copy_len = p->len; 00856 } 00857 /* copy the necessary parts of the buffer */ 00858 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); 00859 total_copy_len -= buf_copy_len; 00860 copied_total += buf_copy_len; 00861 } 00862 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); 00863 return ERR_OK; 00864 } 00865 00866 /** 00867 * Creates a single pbuf out of a queue of pbufs. 00868 * 00869 * @remark: The source pbuf 'p' is not freed by this function because that can 00870 * be illegal in some places! 00871 * 00872 * @param p the source pbuf 00873 * @param layer pbuf_layer of the new pbuf 00874 * 00875 * @return a new, single pbuf (p->next is NULL) 00876 * or the old pbuf if allocation fails 00877 */ 00878 struct pbuf* 00879 pbuf_coalesce(struct pbuf *p, pbuf_layer layer) 00880 { 00881 struct pbuf *q; 00882 err_t err; 00883 if (p->next == NULL) { 00884 return p; 00885 } 00886 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); 00887 if (q == NULL) { 00888 /* @todo: what do we do now? */ 00889 return p; 00890 } 00891 err = pbuf_copy(q, p); 00892 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); 00893 pbuf_free(p); 00894 return q; 00895 }
Generated on Wed Jul 13 2022 07:13:43 by
1.7.2