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