My fork of the HTTPServer (working)
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.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