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", p->len != 0); 00204 /* set reference count (needed here in case we fail) */ 00205 p->ref = 1; 00206 00207 /* now allocate the tail of the pbuf chain */ 00208 00209 /* remember first pbuf for linkage in next iteration */ 00210 r = p; 00211 /* remaining length to be allocated */ 00212 rem_len = length - p->len; 00213 /* any remaining pbufs to be allocated? */ 00214 while (rem_len > 0) { 00215 ALLOC_POOL_PBUF(q); 00216 if (q == NULL) { 00217 /* free chain so far allocated */ 00218 pbuf_free(p); 00219 /* bail out unsuccesfully */ 00220 return NULL; 00221 } 00222 q->type = type; 00223 q->flags = 0; 00224 q->next = NULL; 00225 /* make previous pbuf point to this pbuf */ 00226 r->next = q; 00227 /* set total length of this pbuf and next in chain */ 00228 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); 00229 q->tot_len = (u16_t)rem_len; 00230 /* this pbuf length is pool size, unless smaller sized tail */ 00231 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); 00232 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); 00233 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", 00234 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); 00235 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", 00236 ((u8_t*)p->payload + p->len <= 00237 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); 00238 q->ref = 1; 00239 /* calculate remaining length to be allocated */ 00240 rem_len -= q->len; 00241 /* remember this pbuf for linkage in next iteration */ 00242 r = q; 00243 } 00244 /* end of chain */ 00245 /*r->next = NULL;*/ 00246 00247 break; 00248 case PBUF_RAM: 00249 /* If pbuf is to be allocated in RAM, allocate memory for it. */ 00250 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); 00251 if (p == NULL) { 00252 return NULL; 00253 } 00254 /* Set up internal structure of the pbuf. */ 00255 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); 00256 p->len = p->tot_len = length; 00257 p->next = NULL; 00258 p->type = type; 00259 00260 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", 00261 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00262 break; 00263 /* pbuf references existing (non-volatile static constant) ROM payload? */ 00264 case PBUF_ROM: 00265 /* pbuf references existing (externally allocated) RAM payload? */ 00266 case PBUF_REF: 00267 /* only allocate memory for the pbuf structure */ 00268 p = (struct pbuf *)(memp_malloc(MEMP_PBUF)); // static_cast<struct pbuf *>(x) 00269 if (p == NULL) { 00270 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", 00271 (type == PBUF_ROM) ? "ROM" : "REF")); 00272 return NULL; 00273 } 00274 /* caller must set this field properly, afterwards */ 00275 p->payload = NULL; 00276 p->len = p->tot_len = length; 00277 p->next = NULL; 00278 p->type = type; 00279 break; 00280 default: 00281 LWIP_ASSERT("pbuf_alloc: erroneous type", 0); 00282 return NULL; 00283 } 00284 /* set reference count */ 00285 p->ref = 1; 00286 /* set flags */ 00287 p->flags = 0; 00288 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); 00289 return p; 00290 } 00291 00292 00293 /** 00294 * Shrink a pbuf chain to a desired length. 00295 * 00296 * @param p pbuf to shrink. 00297 * @param new_len desired new length of pbuf chain 00298 * 00299 * Depending on the desired length, the first few pbufs in a chain might 00300 * be skipped and left unchanged. The new last pbuf in the chain will be 00301 * resized, and any remaining pbufs will be freed. 00302 * 00303 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. 00304 * @note May not be called on a packet queue. 00305 * 00306 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). 00307 */ 00308 void 00309 pbuf_realloc(struct pbuf *p, u16_t new_len) 00310 { 00311 struct pbuf *q; 00312 u16_t rem_len; /* remaining length */ 00313 s32_t grow; 00314 00315 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); 00316 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || 00317 p->type == PBUF_ROM || 00318 p->type == PBUF_RAM || 00319 p->type == PBUF_REF); 00320 00321 /* desired length larger than current length? */ 00322 if (new_len >= p->tot_len) { 00323 /* enlarging not yet supported */ 00324 return; 00325 } 00326 00327 /* the pbuf chain grows by (new_len - p->tot_len) bytes 00328 * (which may be negative in case of shrinking) */ 00329 grow = new_len - p->tot_len; 00330 00331 /* first, step over any pbufs that should remain in the chain */ 00332 rem_len = new_len; 00333 q = p; 00334 /* should this pbuf be kept? */ 00335 while (rem_len > q->len) { 00336 /* decrease remaining length by pbuf length */ 00337 rem_len -= q->len; 00338 /* decrease total length indicator */ 00339 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); 00340 q->tot_len += (u16_t)grow; 00341 /* proceed to next pbuf in chain */ 00342 q = q->next; 00343 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); 00344 } 00345 /* we have now reached the new last pbuf (in q) */ 00346 /* rem_len == desired length for pbuf q */ 00347 00348 /* shrink allocated memory for PBUF_RAM */ 00349 /* (other types merely adjust their length fields */ 00350 if ((q->type == PBUF_RAM) && (rem_len != q->len)) { 00351 /* reallocate and adjust the length of the pbuf that will be split */ 00352 q = (struct pbuf *)(mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len)); // static_cast<struct pbuf *>(x) 00353 LWIP_ASSERT("mem_realloc give q == NULL", q != NULL); 00354 } 00355 /* adjust length fields for new last pbuf */ 00356 q->len = rem_len; 00357 q->tot_len = q->len; 00358 00359 /* any remaining pbufs in chain? */ 00360 if (q->next != NULL) { 00361 /* free remaining pbufs in chain */ 00362 pbuf_free(q->next); 00363 } 00364 /* q is last packet in chain */ 00365 q->next = NULL; 00366 00367 } 00368 00369 /** 00370 * Adjusts the payload pointer to hide or reveal headers in the payload. 00371 * 00372 * Adjusts the ->payload pointer so that space for a header 00373 * (dis)appears in the pbuf payload. 00374 * 00375 * The ->payload, ->tot_len and ->len fields are adjusted. 00376 * 00377 * @param p pbuf to change the header size. 00378 * @param header_size_increment Number of bytes to increment header size which 00379 * increases the size of the pbuf. New space is on the front. 00380 * (Using a negative value decreases the header size.) 00381 * If hdr_size_inc is 0, this function does nothing and returns succesful. 00382 * 00383 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00384 * the call will fail. A check is made that the increase in header size does 00385 * not move the payload pointer in front of the start of the buffer. 00386 * @return non-zero on failure, zero on success. 00387 * 00388 */ 00389 u8_t 00390 pbuf_header(struct pbuf *p, s16_t header_size_increment) 00391 { 00392 u16_t type; 00393 void *payload; 00394 u16_t increment_magnitude; 00395 00396 LWIP_ASSERT("p != NULL", p != NULL); 00397 if ((header_size_increment == 0) || (p == NULL)) 00398 return 0; 00399 00400 if (header_size_increment < 0){ 00401 increment_magnitude = -header_size_increment; 00402 /* Check that we aren't going to move off the end of the pbuf */ 00403 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); 00404 } else { 00405 increment_magnitude = header_size_increment; 00406 #if 0 00407 /* Can't assert these as some callers speculatively call 00408 pbuf_header() to see if it's OK. Will return 1 below instead. */ 00409 /* Check that we've got the correct type of pbuf to work with */ 00410 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 00411 p->type == PBUF_RAM || p->type == PBUF_POOL); 00412 /* Check that we aren't going to move off the beginning of the pbuf */ 00413 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", 00414 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); 00415 #endif 00416 } 00417 00418 type = p->type; 00419 /* remember current payload pointer */ 00420 payload = p->payload; 00421 00422 /* pbuf types containing payloads? */ 00423 if (type == PBUF_RAM || type == PBUF_POOL) { 00424 /* set new payload pointer */ 00425 p->payload = (u8_t *)p->payload - header_size_increment; 00426 /* boundary check fails? */ 00427 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { 00428 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", 00429 (void *)p->payload, 00430 (void *)(p + 1)));\ 00431 /* restore old payload pointer */ 00432 p->payload = payload; 00433 /* bail out unsuccesfully */ 00434 return 1; 00435 } 00436 /* pbuf types refering to external payloads? */ 00437 } else if (type == PBUF_REF || type == PBUF_ROM) { 00438 /* hide a header in the payload? */ 00439 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { 00440 /* increase payload pointer */ 00441 p->payload = (u8_t *)p->payload - header_size_increment; 00442 } else { 00443 /* cannot expand payload to front (yet!) 00444 * bail out unsuccesfully */ 00445 return 1; 00446 } 00447 } 00448 else { 00449 /* Unknown type */ 00450 LWIP_ASSERT("bad pbuf type", 0); 00451 return 1; 00452 } 00453 /* modify pbuf length fields */ 00454 p->len += header_size_increment; 00455 p->tot_len += header_size_increment; 00456 00457 LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n", 00458 (void *)payload, (void *)p->payload, header_size_increment)); 00459 00460 return 0; 00461 } 00462 00463 /** 00464 * Dereference a pbuf chain or queue and deallocate any no-longer-used 00465 * pbufs at the head of this chain or queue. 00466 * 00467 * Decrements the pbuf reference count. If it reaches zero, the pbuf is 00468 * deallocated. 00469 * 00470 * For a pbuf chain, this is repeated for each pbuf in the chain, 00471 * up to the first pbuf which has a non-zero reference count after 00472 * decrementing. So, when all reference counts are one, the whole 00473 * chain is free'd. 00474 * 00475 * @param p The pbuf (chain) to be dereferenced. 00476 * 00477 * @return the number of pbufs that were de-allocated 00478 * from the head of the chain. 00479 * 00480 * @note MUST NOT be called on a packet queue (Not verified to work yet). 00481 * @note the reference counter of a pbuf equals the number of pointers 00482 * that refer to the pbuf (or into the pbuf). 00483 * 00484 * @internal examples: 00485 * 00486 * Assuming existing chains a->b->c with the following reference 00487 * counts, calling pbuf_free(a) results in: 00488 * 00489 * 1->2->3 becomes ...1->3 00490 * 3->3->3 becomes 2->3->3 00491 * 1->1->2 becomes ......1 00492 * 2->1->1 becomes 1->1->1 00493 * 1->1->1 becomes ....... 00494 * 00495 */ 00496 u8_t 00497 pbuf_free(struct pbuf *p) 00498 { 00499 u16_t type; 00500 struct pbuf *q; 00501 u8_t count; 00502 00503 if (p == NULL) { 00504 LWIP_ASSERT("p != NULL", p != NULL); 00505 /* if assertions are disabled, proceed with debug output */ 00506 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); 00507 return 0; 00508 } 00509 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); 00510 00511 PERF_START; 00512 00513 LWIP_ASSERT("pbuf_free: sane type", 00514 p->type == PBUF_RAM || p->type == PBUF_ROM || 00515 p->type == PBUF_REF || p->type == PBUF_POOL); 00516 00517 count = 0; 00518 /* de-allocate all consecutive pbufs from the head of the chain that 00519 * obtain a zero reference count after decrementing*/ 00520 while (p != NULL) { 00521 u16_t ref; 00522 SYS_ARCH_DECL_PROTECT(old_level); 00523 /* Since decrementing ref cannot be guaranteed to be a single machine operation 00524 * we must protect it. We put the new ref into a local variable to prevent 00525 * further protection. */ 00526 SYS_ARCH_PROTECT(old_level); 00527 /* all pbufs in a chain are referenced at least once */ 00528 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); 00529 /* decrease reference count (number of pointers to pbuf) */ 00530 ref = --(p->ref); 00531 SYS_ARCH_UNPROTECT(old_level); 00532 /* this pbuf is no longer referenced to? */ 00533 if (ref == 0) { 00534 /* remember next pbuf in chain for next iteration */ 00535 q = p->next; 00536 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); 00537 type = p->type; 00538 /* is this a pbuf from the pool? */ 00539 if (type == PBUF_POOL) { 00540 memp_free(MEMP_PBUF_POOL, p); 00541 /* is this a ROM or RAM referencing pbuf? */ 00542 } else if (type == PBUF_ROM || type == PBUF_REF) { 00543 memp_free(MEMP_PBUF, p); 00544 /* type == PBUF_RAM */ 00545 } else { 00546 mem_free(p); 00547 } 00548 count++; 00549 /* proceed to next pbuf */ 00550 p = q; 00551 /* p->ref > 0, this pbuf is still referenced to */ 00552 /* (and so the remaining pbufs in chain as well) */ 00553 } else { 00554 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); 00555 /* stop walking through the chain */ 00556 p = NULL; 00557 } 00558 } 00559 PERF_STOP("pbuf_free"); 00560 /* return number of de-allocated pbufs */ 00561 return count; 00562 } 00563 00564 /** 00565 * Count number of pbufs in a chain 00566 * 00567 * @param p first pbuf of chain 00568 * @return the number of pbufs in a chain 00569 */ 00570 00571 u8_t 00572 pbuf_clen(struct pbuf *p) 00573 { 00574 u8_t len; 00575 00576 len = 0; 00577 while (p != NULL) { 00578 ++len; 00579 p = p->next; 00580 } 00581 return len; 00582 } 00583 00584 /** 00585 * Increment the reference count of the pbuf. 00586 * 00587 * @param p pbuf to increase reference counter of 00588 * 00589 */ 00590 void 00591 pbuf_ref(struct pbuf *p) 00592 { 00593 SYS_ARCH_DECL_PROTECT(old_level); 00594 /* pbuf given? */ 00595 if (p != NULL) { 00596 SYS_ARCH_PROTECT(old_level); 00597 ++(p->ref); 00598 SYS_ARCH_UNPROTECT(old_level); 00599 } 00600 } 00601 00602 /** 00603 * Concatenate two pbufs (each may be a pbuf chain) and take over 00604 * the caller's reference of the tail pbuf. 00605 * 00606 * @note The caller MAY NOT reference the tail pbuf afterwards. 00607 * Use pbuf_chain() for that purpose. 00608 * 00609 * @see pbuf_chain() 00610 */ 00611 00612 void 00613 pbuf_cat(struct pbuf *h, struct pbuf *t) 00614 { 00615 struct pbuf *p; 00616 00617 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", 00618 ((h != NULL) && (t != NULL)), return;); 00619 00620 /* proceed to last pbuf of chain */ 00621 for (p = h; p->next != NULL; p = p->next) { 00622 /* add total length of second chain to all totals of first chain */ 00623 p->tot_len += t->tot_len; 00624 } 00625 /* { p is last pbuf of first h chain, p->next == NULL } */ 00626 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); 00627 LWIP_ASSERT("p->next == NULL", p->next == NULL); 00628 /* add total length of second chain to last pbuf total of first chain */ 00629 p->tot_len += t->tot_len; 00630 /* chain last pbuf of head (p) with first of tail (t) */ 00631 p->next = t; 00632 /* p->next now references t, but the caller will drop its reference to t, 00633 * so netto there is no change to the reference count of t. 00634 */ 00635 } 00636 00637 /** 00638 * Chain two pbufs (or pbuf chains) together. 00639 * 00640 * The caller MUST call pbuf_free(t) once it has stopped 00641 * using it. Use pbuf_cat() instead if you no longer use t. 00642 * 00643 * @param h head pbuf (chain) 00644 * @param t tail pbuf (chain) 00645 * @note The pbufs MUST belong to the same packet. 00646 * @note MAY NOT be called on a packet queue. 00647 * 00648 * The ->tot_len fields of all pbufs of the head chain are adjusted. 00649 * The ->next field of the last pbuf of the head chain is adjusted. 00650 * The ->ref field of the first pbuf of the tail chain is adjusted. 00651 * 00652 */ 00653 void 00654 pbuf_chain(struct pbuf *h, struct pbuf *t) 00655 { 00656 pbuf_cat(h, t); 00657 /* t is now referenced by h */ 00658 pbuf_ref(t); 00659 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); 00660 } 00661 00662 /** 00663 * Dechains the first pbuf from its succeeding pbufs in the chain. 00664 * 00665 * Makes p->tot_len field equal to p->len. 00666 * @param p pbuf to dechain 00667 * @return remainder of the pbuf chain, or NULL if it was de-allocated. 00668 * @note May not be called on a packet queue. 00669 */ 00670 struct pbuf * 00671 pbuf_dechain(struct pbuf *p) 00672 { 00673 struct pbuf *q; 00674 u8_t tail_gone = 1; 00675 /* tail */ 00676 q = p->next; 00677 /* pbuf has successor in chain? */ 00678 if (q != NULL) { 00679 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00680 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); 00681 /* enforce invariant if assertion is disabled */ 00682 q->tot_len = p->tot_len - p->len; 00683 /* decouple pbuf from remainder */ 00684 p->next = NULL; 00685 /* total length of pbuf p is its own length only */ 00686 p->tot_len = p->len; 00687 /* q is no longer referenced by p, free it */ 00688 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); 00689 tail_gone = pbuf_free(q); 00690 if (tail_gone > 0) { 00691 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, 00692 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); 00693 } 00694 /* return remaining tail or NULL if deallocated */ 00695 } 00696 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00697 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); 00698 return ((tail_gone > 0) ? NULL : q); 00699 } 00700 00701 /** 00702 * 00703 * Create PBUF_RAM copies of pbufs. 00704 * 00705 * Used to queue packets on behalf of the lwIP stack, such as 00706 * ARP based queueing. 00707 * 00708 * @note You MUST explicitly use p = pbuf_take(p); 00709 * 00710 * @note Only one packet is copied, no packet queue! 00711 * 00712 * @param p_to pbuf destination of the copy 00713 * @param p_from pbuf source of the copy 00714 * 00715 * @return ERR_OK if pbuf was copied 00716 * ERR_ARG if one of the pbufs is NULL or p_to is not big 00717 * enough to hold p_from 00718 */ 00719 err_t 00720 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) 00721 { 00722 u16_t offset_to=0, offset_from=0, len; 00723 00724 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n", 00725 (void*)p_to, (void*)p_from)); 00726 00727 /* is the target big enough to hold the source? */ 00728 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && 00729 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); 00730 00731 /* iterate through pbuf chain */ 00732 do 00733 { 00734 LWIP_ASSERT("p_to != NULL", p_to != NULL); 00735 /* copy one part of the original chain */ 00736 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { 00737 /* complete current p_from fits into current p_to */ 00738 len = p_from->len - offset_from; 00739 } else { 00740 /* current p_from does not fit into current p_to */ 00741 len = p_to->len - offset_to; 00742 } 00743 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); 00744 offset_to += len; 00745 offset_from += len; 00746 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); 00747 if (offset_to == p_to->len) { 00748 /* on to next p_to (if any) */ 00749 offset_to = 0; 00750 p_to = p_to->next; 00751 } 00752 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); 00753 if (offset_from >= p_from->len) { 00754 /* on to next p_from (if any) */ 00755 offset_from = 0; 00756 p_from = p_from->next; 00757 } 00758 00759 if((p_from != NULL) && (p_from->len == p_from->tot_len)) { 00760 /* don't copy more than one packet! */ 00761 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00762 (p_from->next == NULL), return ERR_VAL;); 00763 } 00764 if((p_to != NULL) && (p_to->len == p_to->tot_len)) { 00765 /* don't copy more than one packet! */ 00766 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00767 (p_to->next == NULL), return ERR_VAL;); 00768 } 00769 } while (p_from); 00770 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n")); 00771 return ERR_OK; 00772 } 00773 00774 /** 00775 * Copy (part of) the contents of a packet buffer 00776 * to an application supplied buffer. 00777 * 00778 * @param buf the pbuf from which to copy data 00779 * @param dataptr the application supplied buffer 00780 * @param len length of data to copy (dataptr must be big enough). No more 00781 * than buf->tot_len will be copied, irrespective of len 00782 * @param offset offset into the packet buffer from where to begin copying len bytes 00783 * @return the number of bytes copied, or 0 on failure 00784 */ 00785 u16_t 00786 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) 00787 { 00788 struct pbuf *p; 00789 u16_t left; 00790 u16_t buf_copy_len; 00791 u16_t copied_total = 0; 00792 00793 LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;); 00794 LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); 00795 00796 left = 0; 00797 00798 if((buf == NULL) || (dataptr == NULL)) { 00799 return 0; 00800 } 00801 00802 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00803 for(p = buf; len != 0 && p != NULL; p = p->next) { 00804 if ((offset != 0) && (offset >= p->len)) { 00805 /* don't copy from this buffer -> on to the next */ 00806 offset -= p->len; 00807 } else { 00808 /* copy from this buffer. maybe only partially. */ 00809 buf_copy_len = p->len - offset; 00810 if (buf_copy_len > len) 00811 buf_copy_len = len; 00812 /* copy the necessary parts of the buffer */ 00813 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); 00814 copied_total += buf_copy_len; 00815 left += buf_copy_len; 00816 len -= buf_copy_len; 00817 offset = 0; 00818 } 00819 } 00820 return copied_total; 00821 }
Generated on Tue Jul 12 2022 19:24:05 by
1.7.2