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