Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_pbuf.c
00001 /** 00002 * @file 00003 * Packet buffer management 00004 */ 00005 00006 /** 00007 * @defgroup pbuf Packet buffers (PBUF) 00008 * @ingroup infrastructure 00009 * 00010 * Packets are built from the pbuf data structure. It supports dynamic 00011 * memory allocation for packet contents or can reference externally 00012 * managed packet contents both in RAM and ROM. Quick allocation for 00013 * incoming packets is provided through pools with fixed sized pbufs. 00014 * 00015 * A packet may span over multiple pbufs, chained as a singly linked 00016 * list. This is called a "pbuf chain". 00017 * 00018 * Multiple packets may be queued, also using this singly linked list. 00019 * This is called a "packet queue". 00020 * 00021 * So, a packet queue consists of one or more pbuf chains, each of 00022 * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE 00023 * NOT SUPPORTED!!! Use helper structs to queue multiple packets. 00024 * 00025 * The differences between a pbuf chain and a packet queue are very 00026 * precise but subtle. 00027 * 00028 * The last pbuf of a packet has a ->tot_len field that equals the 00029 * ->len field. It can be found by traversing the list. If the last 00030 * pbuf of a packet has a ->next field other than NULL, more packets 00031 * are on the queue. 00032 * 00033 * Therefore, looping through a pbuf of a single packet, has an 00034 * loop end condition (tot_len == p->len), NOT (next == NULL). 00035 * 00036 * Example of custom pbuf usage: @ref zerocopyrx 00037 */ 00038 00039 /* 00040 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00041 * All rights reserved. 00042 * 00043 * Redistribution and use in source and binary forms, with or without modification, 00044 * are permitted provided that the following conditions are met: 00045 * 00046 * 1. Redistributions of source code must retain the above copyright notice, 00047 * this list of conditions and the following disclaimer. 00048 * 2. Redistributions in binary form must reproduce the above copyright notice, 00049 * this list of conditions and the following disclaimer in the documentation 00050 * and/or other materials provided with the distribution. 00051 * 3. The name of the author may not be used to endorse or promote products 00052 * derived from this software without specific prior written permission. 00053 * 00054 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00055 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00056 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00057 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00058 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00059 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00060 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00061 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00062 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00063 * OF SUCH DAMAGE. 00064 * 00065 * This file is part of the lwIP TCP/IP stack. 00066 * 00067 * Author: Adam Dunkels <adam@sics.se> 00068 * 00069 */ 00070 00071 #include "lwip/opt.h" 00072 00073 #include "lwip/pbuf.h" 00074 #include "lwip/stats.h" 00075 #include "lwip/def.h" 00076 #include "lwip/mem.h" 00077 #include "lwip/memp.h" 00078 #include "lwip/sys.h" 00079 #include "lwip/netif.h" 00080 #if LWIP_TCP && TCP_QUEUE_OOSEQ 00081 #include "lwip/priv/tcp_priv.h" 00082 #endif 00083 #if LWIP_CHECKSUM_ON_COPY 00084 #include "lwip/inet_chksum.h" 00085 #endif 00086 #include "string.h" 00087 00088 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) 00089 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically 00090 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ 00091 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) 00092 00093 static const struct pbuf * 00094 pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset); 00095 00096 #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ 00097 #define PBUF_POOL_IS_EMPTY() 00098 #else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ 00099 00100 #if !NO_SYS 00101 #ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL 00102 #include "lwip/tcpip.h" 00103 #define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ 00104 if (tcpip_try_callback(pbuf_free_ooseq_callback, NULL) != ERR_OK) { \ 00105 SYS_ARCH_PROTECT(old_level); \ 00106 pbuf_free_ooseq_pending = 0; \ 00107 SYS_ARCH_UNPROTECT(old_level); \ 00108 } } while(0) 00109 #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ 00110 #endif /* !NO_SYS */ 00111 00112 volatile u8_t pbuf_free_ooseq_pending; 00113 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() 00114 00115 /** 00116 * Attempt to reclaim some memory from queued out-of-sequence TCP segments 00117 * if we run out of pool pbufs. It's better to give priority to new packets 00118 * if we're running out. 00119 * 00120 * This must be done in the correct thread context therefore this function 00121 * can only be used with NO_SYS=0 and through tcpip_callback. 00122 */ 00123 #if !NO_SYS 00124 static 00125 #endif /* !NO_SYS */ 00126 void 00127 pbuf_free_ooseq(void) 00128 { 00129 struct tcp_pcb *pcb; 00130 SYS_ARCH_SET(pbuf_free_ooseq_pending, 0); 00131 00132 for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { 00133 if (pcb->ooseq != NULL) { 00134 /** Free the ooseq pbufs of one PCB only */ 00135 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); 00136 tcp_free_ooseq(pcb); 00137 return; 00138 } 00139 } 00140 } 00141 00142 #if !NO_SYS 00143 /** 00144 * Just a callback function for tcpip_callback() that calls pbuf_free_ooseq(). 00145 */ 00146 static void 00147 pbuf_free_ooseq_callback(void *arg) 00148 { 00149 LWIP_UNUSED_ARG(arg); 00150 pbuf_free_ooseq(); 00151 } 00152 #endif /* !NO_SYS */ 00153 00154 /** Queue a call to pbuf_free_ooseq if not already queued. */ 00155 static void 00156 pbuf_pool_is_empty(void) 00157 { 00158 #ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL 00159 SYS_ARCH_SET(pbuf_free_ooseq_pending, 1); 00160 #else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ 00161 u8_t queued; 00162 SYS_ARCH_DECL_PROTECT(old_level); 00163 SYS_ARCH_PROTECT(old_level); 00164 queued = pbuf_free_ooseq_pending; 00165 pbuf_free_ooseq_pending = 1; 00166 SYS_ARCH_UNPROTECT(old_level); 00167 00168 if (!queued) { 00169 /* queue a call to pbuf_free_ooseq if not already queued */ 00170 PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); 00171 } 00172 #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ 00173 } 00174 #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ 00175 00176 /* Initialize members of struct pbuf after allocation */ 00177 static void 00178 pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags) 00179 { 00180 p->next = NULL; 00181 p->payload = payload; 00182 p->tot_len = tot_len; 00183 p->len = len; 00184 p->type_internal = (u8_t)type; 00185 p->flags = flags; 00186 p->ref = 1; 00187 p->if_idx = NETIF_NO_INDEX; 00188 } 00189 00190 /** 00191 * @ingroup pbuf 00192 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). 00193 * 00194 * The actual memory allocated for the pbuf is determined by the 00195 * layer at which the pbuf is allocated and the requested size 00196 * (from the size parameter). 00197 * 00198 * @param layer header size 00199 * @param length size of the pbuf's payload 00200 * @param type this parameter decides how and where the pbuf 00201 * should be allocated as follows: 00202 * 00203 * - PBUF_RAM: buffer memory for pbuf is allocated as one large 00204 * chunk. This includes protocol headers as well. 00205 * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for 00206 * protocol headers. Additional headers must be prepended 00207 * by allocating another pbuf and chain in to the front of 00208 * the ROM pbuf. It is assumed that the memory used is really 00209 * similar to ROM in that it is immutable and will not be 00210 * changed. Memory which is dynamic should generally not 00211 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. 00212 * - PBUF_REF: no buffer memory is allocated for the pbuf, even for 00213 * protocol headers. It is assumed that the pbuf is only 00214 * being used in a single thread. If the pbuf gets queued, 00215 * then pbuf_take should be called to copy the buffer. 00216 * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from 00217 * the pbuf pool that is allocated during pbuf_init(). 00218 * 00219 * @return the allocated pbuf. If multiple pbufs where allocated, this 00220 * is the first pbuf of a pbuf chain. 00221 */ 00222 struct pbuf * 00223 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) 00224 { 00225 struct pbuf *p; 00226 u16_t offset = (u16_t)layer; 00227 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); 00228 00229 switch (type) { 00230 case PBUF_REF: /* fall through */ 00231 case PBUF_ROM: 00232 p = pbuf_alloc_reference(NULL, length, type); 00233 break; 00234 case PBUF_POOL: { 00235 struct pbuf *q, *last; 00236 u16_t rem_len; /* remaining length */ 00237 p = NULL; 00238 last = NULL; 00239 rem_len = length; 00240 do { 00241 u16_t qlen; 00242 q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); 00243 if (q == NULL) { 00244 PBUF_POOL_IS_EMPTY(); 00245 /* free chain so far allocated */ 00246 if (p) { 00247 pbuf_free(p); 00248 } 00249 /* bail out unsuccessfully */ 00250 return NULL; 00251 } 00252 qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); 00253 pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), 00254 rem_len, qlen, type, 0); 00255 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", 00256 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); 00257 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", 00258 (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); 00259 if (p == NULL) { 00260 /* allocated head of pbuf chain (into p) */ 00261 p = q; 00262 } else { 00263 /* make previous pbuf point to this pbuf */ 00264 last->next = q; 00265 } 00266 last = q; 00267 rem_len = (u16_t)(rem_len - qlen); 00268 offset = 0; 00269 } while (rem_len > 0); 00270 break; 00271 } 00272 case PBUF_RAM: { 00273 u16_t payload_len = (u16_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length)); 00274 mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len); 00275 00276 /* bug #50040: Check for integer overflow when calculating alloc_len */ 00277 if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) || 00278 (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) { 00279 return NULL; 00280 } 00281 00282 /* If pbuf is to be allocated in RAM, allocate memory for it. */ 00283 p = (struct pbuf *)mem_malloc(alloc_len); 00284 if (p == NULL) { 00285 return NULL; 00286 } 00287 pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), 00288 length, length, type, 0); 00289 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", 00290 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00291 break; 00292 } 00293 default: 00294 LWIP_ASSERT("pbuf_alloc: erroneous type", 0); 00295 return NULL; 00296 } 00297 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); 00298 return p; 00299 } 00300 00301 /** 00302 * @ingroup pbuf 00303 * Allocates a pbuf for referenced data. 00304 * Referenced data can be volatile (PBUF_REF) or long-lived (PBUF_ROM). 00305 * 00306 * The actual memory allocated for the pbuf is determined by the 00307 * layer at which the pbuf is allocated and the requested size 00308 * (from the size parameter). 00309 * 00310 * @param payload referenced payload 00311 * @param length size of the pbuf's payload 00312 * @param type this parameter decides how and where the pbuf 00313 * should be allocated as follows: 00314 * 00315 * - PBUF_ROM: It is assumed that the memory used is really 00316 * similar to ROM in that it is immutable and will not be 00317 * changed. Memory which is dynamic should generally not 00318 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. 00319 * - PBUF_REF: It is assumed that the pbuf is only 00320 * being used in a single thread. If the pbuf gets queued, 00321 * then pbuf_take should be called to copy the buffer. 00322 * 00323 * @return the allocated pbuf. 00324 */ 00325 struct pbuf * 00326 pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type) 00327 { 00328 struct pbuf *p; 00329 LWIP_ASSERT("invalid pbuf_type", (type == PBUF_REF) || (type == PBUF_ROM)); 00330 /* only allocate memory for the pbuf structure */ 00331 p = (struct pbuf *)memp_malloc(MEMP_PBUF); 00332 if (p == NULL) { 00333 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00334 ("pbuf_alloc_reference: Could not allocate MEMP_PBUF for PBUF_%s.\n", 00335 (type == PBUF_ROM) ? "ROM" : "REF")); 00336 return NULL; 00337 } 00338 pbuf_init_alloced_pbuf(p, payload, length, length, type, 0); 00339 return p; 00340 } 00341 00342 00343 #if LWIP_SUPPORT_CUSTOM_PBUF 00344 /** 00345 * @ingroup pbuf 00346 * Initialize a custom pbuf (already allocated). 00347 * Example of custom pbuf usage: @ref zerocopyrx 00348 * 00349 * @param l header size 00350 * @param length size of the pbuf's payload 00351 * @param type type of the pbuf (only used to treat the pbuf accordingly, as 00352 * this function allocates no memory) 00353 * @param p pointer to the custom pbuf to initialize (already allocated) 00354 * @param payload_mem pointer to the buffer that is used for payload and headers, 00355 * must be at least big enough to hold 'length' plus the header size, 00356 * may be NULL if set later. 00357 * ATTENTION: The caller is responsible for correct alignment of this buffer!! 00358 * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least 00359 * big enough to hold 'length' plus the header size 00360 */ 00361 struct pbuf * 00362 pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, 00363 void *payload_mem, u16_t payload_mem_len) 00364 { 00365 u16_t offset = (u16_t)l; 00366 void *payload; 00367 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); 00368 00369 if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { 00370 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); 00371 return NULL; 00372 } 00373 00374 if (payload_mem != NULL) { 00375 payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); 00376 } else { 00377 payload = NULL; 00378 } 00379 pbuf_init_alloced_pbuf(&p->pbuf, payload, length, length, type, PBUF_FLAG_IS_CUSTOM); 00380 return &p->pbuf; 00381 } 00382 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ 00383 00384 /** 00385 * @ingroup pbuf 00386 * Shrink a pbuf chain to a desired length. 00387 * 00388 * @param p pbuf to shrink. 00389 * @param new_len desired new length of pbuf chain 00390 * 00391 * Depending on the desired length, the first few pbufs in a chain might 00392 * be skipped and left unchanged. The new last pbuf in the chain will be 00393 * resized, and any remaining pbufs will be freed. 00394 * 00395 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. 00396 * @note May not be called on a packet queue. 00397 * 00398 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). 00399 */ 00400 void 00401 pbuf_realloc(struct pbuf *p, u16_t new_len) 00402 { 00403 struct pbuf *q; 00404 u16_t rem_len; /* remaining length */ 00405 u16_t shrink; 00406 00407 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); 00408 00409 /* desired length larger than current length? */ 00410 if (new_len >= p->tot_len) { 00411 /* enlarging not yet supported */ 00412 return; 00413 } 00414 00415 /* the pbuf chain grows by (new_len - p->tot_len) bytes 00416 * (which may be negative in case of shrinking) */ 00417 shrink = (u16_t)(p->tot_len - new_len); 00418 00419 /* first, step over any pbufs that should remain in the chain */ 00420 rem_len = new_len; 00421 q = p; 00422 /* should this pbuf be kept? */ 00423 while (rem_len > q->len) { 00424 /* decrease remaining length by pbuf length */ 00425 rem_len = (u16_t)(rem_len - q->len); 00426 /* decrease total length indicator */ 00427 q->tot_len = (u16_t)(q->tot_len - shrink); 00428 /* proceed to next pbuf in chain */ 00429 q = q->next; 00430 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); 00431 } 00432 /* we have now reached the new last pbuf (in q) */ 00433 /* rem_len == desired length for pbuf q */ 00434 00435 /* shrink allocated memory for PBUF_RAM */ 00436 /* (other types merely adjust their length fields */ 00437 if (pbuf_match_allocsrc(q, PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) && (rem_len != q->len) 00438 #if LWIP_SUPPORT_CUSTOM_PBUF 00439 && ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0) 00440 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ 00441 ) { 00442 /* reallocate and adjust the length of the pbuf that will be split */ 00443 q = (struct pbuf *)mem_trim(q, (mem_size_t)(((u8_t *)q->payload - (u8_t *)q) + rem_len)); 00444 LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); 00445 } 00446 /* adjust length fields for new last pbuf */ 00447 q->len = rem_len; 00448 q->tot_len = q->len; 00449 00450 /* any remaining pbufs in chain? */ 00451 if (q->next != NULL) { 00452 /* free remaining pbufs in chain */ 00453 pbuf_free(q->next); 00454 } 00455 /* q is last packet in chain */ 00456 q->next = NULL; 00457 00458 } 00459 00460 /** 00461 * Adjusts the payload pointer to reveal headers in the payload. 00462 * @see pbuf_add_header. 00463 * 00464 * @param p pbuf to change the header size. 00465 * @param header_size_increment Number of bytes to increment header size. 00466 * @param force Allow 'header_size_increment > 0' for PBUF_REF/PBUF_ROM types 00467 * 00468 * @return non-zero on failure, zero on success. 00469 * 00470 */ 00471 static u8_t 00472 pbuf_add_header_impl(struct pbuf *p, size_t header_size_increment, u8_t force) 00473 { 00474 u16_t type_internal; 00475 void *payload; 00476 u16_t increment_magnitude; 00477 00478 LWIP_ASSERT("p != NULL", p != NULL); 00479 if ((p == NULL) || (header_size_increment > 0xFFFF)) { 00480 return 1; 00481 } 00482 if (header_size_increment == 0) { 00483 return 0; 00484 } 00485 00486 increment_magnitude = (u16_t)header_size_increment; 00487 /* Do not allow tot_len to wrap as a result. */ 00488 if ((u16_t)(increment_magnitude + p->tot_len) < increment_magnitude) { 00489 return 1; 00490 } 00491 00492 type_internal = p->type_internal; 00493 00494 /* pbuf types containing payloads? */ 00495 if (type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS) { 00496 /* set new payload pointer */ 00497 payload = (u8_t *)p->payload - header_size_increment; 00498 /* boundary check fails? */ 00499 if ((u8_t *)payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { 00500 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, 00501 ("pbuf_add_header: failed as %p < %p (not enough space for new header size)\n", 00502 (void *)payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF))); 00503 /* bail out unsuccessfully */ 00504 return 1; 00505 } 00506 /* pbuf types referring to external payloads? */ 00507 } else { 00508 /* hide a header in the payload? */ 00509 if (force) { 00510 payload = (u8_t *)p->payload - header_size_increment; 00511 } else { 00512 /* cannot expand payload to front (yet!) 00513 * bail out unsuccessfully */ 00514 return 1; 00515 } 00516 } 00517 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_add_header: old %p new %p (%"U16_F")\n", 00518 (void *)p->payload, (void *)payload, increment_magnitude)); 00519 00520 /* modify pbuf fields */ 00521 p->payload = payload; 00522 p->len = (u16_t)(p->len + increment_magnitude); 00523 p->tot_len = (u16_t)(p->tot_len + increment_magnitude); 00524 00525 00526 return 0; 00527 } 00528 00529 /** 00530 * Adjusts the payload pointer to reveal headers in the payload. 00531 * 00532 * Adjusts the ->payload pointer so that space for a header 00533 * appears in the pbuf payload. 00534 * 00535 * The ->payload, ->tot_len and ->len fields are adjusted. 00536 * 00537 * @param p pbuf to change the header size. 00538 * @param header_size_increment Number of bytes to increment header size which 00539 * increases the size of the pbuf. New space is on the front. 00540 * If header_size_increment is 0, this function does nothing and returns successful. 00541 * 00542 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00543 * the call will fail. A check is made that the increase in header size does 00544 * not move the payload pointer in front of the start of the buffer. 00545 * 00546 * @return non-zero on failure, zero on success. 00547 * 00548 */ 00549 u8_t 00550 pbuf_add_header(struct pbuf *p, size_t header_size_increment) 00551 { 00552 return pbuf_add_header_impl(p, header_size_increment, 0); 00553 } 00554 00555 /** 00556 * Same as @ref pbuf_add_header but does not check if 'header_size > 0' is allowed. 00557 * This is used internally only, to allow PBUF_REF for RX. 00558 */ 00559 u8_t 00560 pbuf_add_header_force(struct pbuf *p, size_t header_size_increment) 00561 { 00562 return pbuf_add_header_impl(p, header_size_increment, 1); 00563 } 00564 00565 /** 00566 * Adjusts the payload pointer to hide headers in the payload. 00567 * 00568 * Adjusts the ->payload pointer so that space for a header 00569 * disappears in the pbuf payload. 00570 * 00571 * The ->payload, ->tot_len and ->len fields are adjusted. 00572 * 00573 * @param p pbuf to change the header size. 00574 * @param header_size_decrement Number of bytes to decrement header size which 00575 * decreases the size of the pbuf. 00576 * If header_size_decrement is 0, this function does nothing and returns successful. 00577 * @return non-zero on failure, zero on success. 00578 * 00579 */ 00580 u8_t 00581 pbuf_remove_header(struct pbuf *p, size_t header_size_decrement) 00582 { 00583 void *payload; 00584 u16_t increment_magnitude; 00585 00586 LWIP_ASSERT("p != NULL", p != NULL); 00587 if ((p == NULL) || (header_size_decrement > 0xFFFF)) { 00588 return 1; 00589 } 00590 if (header_size_decrement == 0) { 00591 return 0; 00592 } 00593 00594 increment_magnitude = (u16_t)header_size_decrement; 00595 /* Check that we aren't going to move off the end of the pbuf */ 00596 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); 00597 00598 /* remember current payload pointer */ 00599 payload = p->payload; 00600 LWIP_UNUSED_ARG(payload); /* only used in LWIP_DEBUGF below */ 00601 00602 /* increase payload pointer (guarded by length check above) */ 00603 p->payload = (u8_t *)p->payload + header_size_decrement; 00604 /* modify pbuf length fields */ 00605 p->len = (u16_t)(p->len - increment_magnitude); 00606 p->tot_len = (u16_t)(p->tot_len - increment_magnitude); 00607 00608 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_remove_header: old %p new %p (%"U16_F")\n", 00609 (void *)payload, (void *)p->payload, increment_magnitude)); 00610 00611 return 0; 00612 } 00613 00614 static u8_t 00615 pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force) 00616 { 00617 if (header_size_increment < 0) { 00618 return pbuf_remove_header(p, (size_t) - header_size_increment); 00619 } else { 00620 return pbuf_add_header_impl(p, (size_t)header_size_increment, force); 00621 } 00622 } 00623 00624 /** 00625 * Adjusts the payload pointer to hide or reveal headers in the payload. 00626 * 00627 * Adjusts the ->payload pointer so that space for a header 00628 * (dis)appears in the pbuf payload. 00629 * 00630 * The ->payload, ->tot_len and ->len fields are adjusted. 00631 * 00632 * @param p pbuf to change the header size. 00633 * @param header_size_increment Number of bytes to increment header size which 00634 * increases the size of the pbuf. New space is on the front. 00635 * (Using a negative value decreases the header size.) 00636 * If header_size_increment is 0, this function does nothing and returns successful. 00637 * 00638 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00639 * the call will fail. A check is made that the increase in header size does 00640 * not move the payload pointer in front of the start of the buffer. 00641 * @return non-zero on failure, zero on success. 00642 * 00643 */ 00644 u8_t 00645 pbuf_header(struct pbuf *p, s16_t header_size_increment) 00646 { 00647 return pbuf_header_impl(p, header_size_increment, 0); 00648 } 00649 00650 /** 00651 * Same as pbuf_header but does not check if 'header_size > 0' is allowed. 00652 * This is used internally only, to allow PBUF_REF for RX. 00653 */ 00654 u8_t 00655 pbuf_header_force(struct pbuf *p, s16_t header_size_increment) 00656 { 00657 return pbuf_header_impl(p, header_size_increment, 1); 00658 } 00659 00660 /** Similar to pbuf_header(-size) but de-refs header pbufs for (size >= p->len) 00661 * 00662 * @param q pbufs to operate on 00663 * @param size The number of bytes to remove from the beginning of the pbuf list. 00664 * While size >= p->len, pbufs are freed. 00665 * ATTENTION: this is the opposite direction as @ref pbuf_header, but 00666 * takes an u16_t not s16_t! 00667 * @return the new head pbuf 00668 */ 00669 struct pbuf * 00670 pbuf_free_header(struct pbuf *q, u16_t size) 00671 { 00672 struct pbuf *p = q; 00673 u16_t free_left = size; 00674 while (free_left && p) { 00675 if (free_left >= p->len) { 00676 struct pbuf *f = p; 00677 free_left = (u16_t)(free_left - p->len); 00678 p = p->next; 00679 f->next = 0; 00680 pbuf_free(f); 00681 } else { 00682 pbuf_remove_header(p, free_left); 00683 free_left = 0; 00684 } 00685 } 00686 return p; 00687 } 00688 00689 /** 00690 * @ingroup pbuf 00691 * Dereference a pbuf chain or queue and deallocate any no-longer-used 00692 * pbufs at the head of this chain or queue. 00693 * 00694 * Decrements the pbuf reference count. If it reaches zero, the pbuf is 00695 * deallocated. 00696 * 00697 * For a pbuf chain, this is repeated for each pbuf in the chain, 00698 * up to the first pbuf which has a non-zero reference count after 00699 * decrementing. So, when all reference counts are one, the whole 00700 * chain is free'd. 00701 * 00702 * @param p The pbuf (chain) to be dereferenced. 00703 * 00704 * @return the number of pbufs that were de-allocated 00705 * from the head of the chain. 00706 * 00707 * @note MUST NOT be called on a packet queue (Not verified to work yet). 00708 * @note the reference counter of a pbuf equals the number of pointers 00709 * that refer to the pbuf (or into the pbuf). 00710 * 00711 * @internal examples: 00712 * 00713 * Assuming existing chains a->b->c with the following reference 00714 * counts, calling pbuf_free(a) results in: 00715 * 00716 * 1->2->3 becomes ...1->3 00717 * 3->3->3 becomes 2->3->3 00718 * 1->1->2 becomes ......1 00719 * 2->1->1 becomes 1->1->1 00720 * 1->1->1 becomes ....... 00721 * 00722 */ 00723 u8_t 00724 pbuf_free(struct pbuf *p) 00725 { 00726 u8_t alloc_src; 00727 struct pbuf *q; 00728 u8_t count; 00729 00730 if (p == NULL) { 00731 LWIP_ASSERT("p != NULL", p != NULL); 00732 /* if assertions are disabled, proceed with debug output */ 00733 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00734 ("pbuf_free(p == NULL) was called.\n")); 00735 return 0; 00736 } 00737 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); 00738 00739 PERF_START; 00740 00741 count = 0; 00742 /* de-allocate all consecutive pbufs from the head of the chain that 00743 * obtain a zero reference count after decrementing*/ 00744 while (p != NULL) { 00745 LWIP_PBUF_REF_T ref; 00746 SYS_ARCH_DECL_PROTECT(old_level); 00747 /* Since decrementing ref cannot be guaranteed to be a single machine operation 00748 * we must protect it. We put the new ref into a local variable to prevent 00749 * further protection. */ 00750 SYS_ARCH_PROTECT(old_level); 00751 /* all pbufs in a chain are referenced at least once */ 00752 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); 00753 /* decrease reference count (number of pointers to pbuf) */ 00754 ref = --(p->ref); 00755 SYS_ARCH_UNPROTECT(old_level); 00756 /* this pbuf is no longer referenced to? */ 00757 if (ref == 0) { 00758 /* remember next pbuf in chain for next iteration */ 00759 q = p->next; 00760 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); 00761 alloc_src = pbuf_get_allocsrc(p); 00762 #if LWIP_SUPPORT_CUSTOM_PBUF 00763 /* is this a custom pbuf? */ 00764 if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { 00765 struct pbuf_custom *pc = (struct pbuf_custom *)p; 00766 LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); 00767 pc->custom_free_function(p); 00768 } else 00769 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ 00770 { 00771 /* is this a pbuf from the pool? */ 00772 if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) { 00773 memp_free(MEMP_PBUF_POOL, p); 00774 /* is this a ROM or RAM referencing pbuf? */ 00775 } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF) { 00776 memp_free(MEMP_PBUF, p); 00777 /* type == PBUF_RAM */ 00778 } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) { 00779 mem_free(p); 00780 } else { 00781 /* @todo: support freeing other types */ 00782 LWIP_ASSERT("invalid pbuf type", 0); 00783 } 00784 } 00785 count++; 00786 /* proceed to next pbuf */ 00787 p = q; 00788 /* p->ref > 0, this pbuf is still referenced to */ 00789 /* (and so the remaining pbufs in chain as well) */ 00790 } else { 00791 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)ref)); 00792 /* stop walking through the chain */ 00793 p = NULL; 00794 } 00795 } 00796 PERF_STOP("pbuf_free"); 00797 /* return number of de-allocated pbufs */ 00798 return count; 00799 } 00800 00801 /** 00802 * Count number of pbufs in a chain 00803 * 00804 * @param p first pbuf of chain 00805 * @return the number of pbufs in a chain 00806 */ 00807 u16_t 00808 pbuf_clen(const struct pbuf *p) 00809 { 00810 u16_t len; 00811 00812 len = 0; 00813 while (p != NULL) { 00814 ++len; 00815 p = p->next; 00816 } 00817 return len; 00818 } 00819 00820 /** 00821 * @ingroup pbuf 00822 * Increment the reference count of the pbuf. 00823 * 00824 * @param p pbuf to increase reference counter of 00825 * 00826 */ 00827 void 00828 pbuf_ref(struct pbuf *p) 00829 { 00830 /* pbuf given? */ 00831 if (p != NULL) { 00832 SYS_ARCH_SET(p->ref, (LWIP_PBUF_REF_T)(p->ref + 1)); 00833 LWIP_ASSERT("pbuf ref overflow", p->ref > 0); 00834 } 00835 } 00836 00837 /** 00838 * @ingroup pbuf 00839 * Concatenate two pbufs (each may be a pbuf chain) and take over 00840 * the caller's reference of the tail pbuf. 00841 * 00842 * @note The caller MAY NOT reference the tail pbuf afterwards. 00843 * Use pbuf_chain() for that purpose. 00844 * 00845 * This function explicitly does not check for tot_len overflow to prevent 00846 * failing to queue too long pbufs. This can produce invalid pbufs, so 00847 * handle with care! 00848 * 00849 * @see pbuf_chain() 00850 */ 00851 void 00852 pbuf_cat(struct pbuf *h, struct pbuf *t) 00853 { 00854 struct pbuf *p; 00855 00856 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", 00857 ((h != NULL) && (t != NULL)), return;); 00858 00859 /* proceed to last pbuf of chain */ 00860 for (p = h; p->next != NULL; p = p->next) { 00861 /* add total length of second chain to all totals of first chain */ 00862 p->tot_len = (u16_t)(p->tot_len + t->tot_len); 00863 } 00864 /* { p is last pbuf of first h chain, p->next == NULL } */ 00865 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); 00866 LWIP_ASSERT("p->next == NULL", p->next == NULL); 00867 /* add total length of second chain to last pbuf total of first chain */ 00868 p->tot_len = (u16_t)(p->tot_len + t->tot_len); 00869 /* chain last pbuf of head (p) with first of tail (t) */ 00870 p->next = t; 00871 /* p->next now references t, but the caller will drop its reference to t, 00872 * so netto there is no change to the reference count of t. 00873 */ 00874 } 00875 00876 /** 00877 * @ingroup pbuf 00878 * Chain two pbufs (or pbuf chains) together. 00879 * 00880 * The caller MUST call pbuf_free(t) once it has stopped 00881 * using it. Use pbuf_cat() instead if you no longer use t. 00882 * 00883 * @param h head pbuf (chain) 00884 * @param t tail pbuf (chain) 00885 * @note The pbufs MUST belong to the same packet. 00886 * @note MAY NOT be called on a packet queue. 00887 * 00888 * The ->tot_len fields of all pbufs of the head chain are adjusted. 00889 * The ->next field of the last pbuf of the head chain is adjusted. 00890 * The ->ref field of the first pbuf of the tail chain is adjusted. 00891 * 00892 */ 00893 void 00894 pbuf_chain(struct pbuf *h, struct pbuf *t) 00895 { 00896 pbuf_cat(h, t); 00897 /* t is now referenced by h */ 00898 pbuf_ref(t); 00899 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); 00900 } 00901 00902 /** 00903 * Dechains the first pbuf from its succeeding pbufs in the chain. 00904 * 00905 * Makes p->tot_len field equal to p->len. 00906 * @param p pbuf to dechain 00907 * @return remainder of the pbuf chain, or NULL if it was de-allocated. 00908 * @note May not be called on a packet queue. 00909 */ 00910 struct pbuf * 00911 pbuf_dechain(struct pbuf *p) 00912 { 00913 struct pbuf *q; 00914 u8_t tail_gone = 1; 00915 /* tail */ 00916 q = p->next; 00917 /* pbuf has successor in chain? */ 00918 if (q != NULL) { 00919 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00920 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); 00921 /* enforce invariant if assertion is disabled */ 00922 q->tot_len = (u16_t)(p->tot_len - p->len); 00923 /* decouple pbuf from remainder */ 00924 p->next = NULL; 00925 /* total length of pbuf p is its own length only */ 00926 p->tot_len = p->len; 00927 /* q is no longer referenced by p, free it */ 00928 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); 00929 tail_gone = pbuf_free(q); 00930 if (tail_gone > 0) { 00931 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, 00932 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); 00933 } 00934 /* return remaining tail or NULL if deallocated */ 00935 } 00936 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00937 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); 00938 return ((tail_gone > 0) ? NULL : q); 00939 } 00940 00941 /** 00942 * @ingroup pbuf 00943 * Create PBUF_RAM copies of pbufs. 00944 * 00945 * Used to queue packets on behalf of the lwIP stack, such as 00946 * ARP based queueing. 00947 * 00948 * @note You MUST explicitly use p = pbuf_take(p); 00949 * 00950 * @note Only one packet is copied, no packet queue! 00951 * 00952 * @param p_to pbuf destination of the copy 00953 * @param p_from pbuf source of the copy 00954 * 00955 * @return ERR_OK if pbuf was copied 00956 * ERR_ARG if one of the pbufs is NULL or p_to is not big 00957 * enough to hold p_from 00958 */ 00959 err_t 00960 pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from) 00961 { 00962 size_t offset_to = 0, offset_from = 0, len; 00963 00964 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", 00965 (const void *)p_to, (const void *)p_from)); 00966 00967 /* is the target big enough to hold the source? */ 00968 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && 00969 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); 00970 00971 /* iterate through pbuf chain */ 00972 do { 00973 /* copy one part of the original chain */ 00974 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { 00975 /* complete current p_from fits into current p_to */ 00976 len = p_from->len - offset_from; 00977 } else { 00978 /* current p_from does not fit into current p_to */ 00979 len = p_to->len - offset_to; 00980 } 00981 MEMCPY((u8_t *)p_to->payload + offset_to, (u8_t *)p_from->payload + offset_from, len); 00982 offset_to += len; 00983 offset_from += len; 00984 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); 00985 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); 00986 if (offset_from >= p_from->len) { 00987 /* on to next p_from (if any) */ 00988 offset_from = 0; 00989 p_from = p_from->next; 00990 } 00991 if (offset_to == p_to->len) { 00992 /* on to next p_to (if any) */ 00993 offset_to = 0; 00994 p_to = p_to->next; 00995 LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL), return ERR_ARG;); 00996 } 00997 00998 if ((p_from != NULL) && (p_from->len == p_from->tot_len)) { 00999 /* don't copy more than one packet! */ 01000 LWIP_ERROR("pbuf_copy() does not allow packet queues!", 01001 (p_from->next == NULL), return ERR_VAL;); 01002 } 01003 if ((p_to != NULL) && (p_to->len == p_to->tot_len)) { 01004 /* don't copy more than one packet! */ 01005 LWIP_ERROR("pbuf_copy() does not allow packet queues!", 01006 (p_to->next == NULL), return ERR_VAL;); 01007 } 01008 } while (p_from); 01009 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); 01010 return ERR_OK; 01011 } 01012 01013 /** 01014 * @ingroup pbuf 01015 * Copy (part of) the contents of a packet buffer 01016 * to an application supplied buffer. 01017 * 01018 * @param buf the pbuf from which to copy data 01019 * @param dataptr the application supplied buffer 01020 * @param len length of data to copy (dataptr must be big enough). No more 01021 * than buf->tot_len will be copied, irrespective of len 01022 * @param offset offset into the packet buffer from where to begin copying len bytes 01023 * @return the number of bytes copied, or 0 on failure 01024 */ 01025 u16_t 01026 pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) 01027 { 01028 const struct pbuf *p; 01029 u16_t left = 0; 01030 u16_t buf_copy_len; 01031 u16_t copied_total = 0; 01032 01033 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); 01034 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); 01035 01036 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 01037 for (p = buf; len != 0 && p != NULL; p = p->next) { 01038 if ((offset != 0) && (offset >= p->len)) { 01039 /* don't copy from this buffer -> on to the next */ 01040 offset = (u16_t)(offset - p->len); 01041 } else { 01042 /* copy from this buffer. maybe only partially. */ 01043 buf_copy_len = (u16_t)(p->len - offset); 01044 if (buf_copy_len > len) { 01045 buf_copy_len = len; 01046 } 01047 /* copy the necessary parts of the buffer */ 01048 MEMCPY(&((char *)dataptr)[left], &((char *)p->payload)[offset], buf_copy_len); 01049 copied_total = (u16_t)(copied_total + buf_copy_len); 01050 left = (u16_t)(left + buf_copy_len); 01051 len = (u16_t)(len - buf_copy_len); 01052 offset = 0; 01053 } 01054 } 01055 return copied_total; 01056 } 01057 01058 /** 01059 * @ingroup pbuf 01060 * Get part of a pbuf's payload as contiguous memory. The returned memory is 01061 * either a pointer into the pbuf's payload or, if split over multiple pbufs, 01062 * a copy into the user-supplied buffer. 01063 * 01064 * @param p the pbuf from which to copy data 01065 * @param buffer the application supplied buffer 01066 * @param bufsize size of the application supplied buffer 01067 * @param len length of data to copy (dataptr must be big enough). No more 01068 * than buf->tot_len will be copied, irrespective of len 01069 * @param offset offset into the packet buffer from where to begin copying len bytes 01070 * @return the number of bytes copied, or 0 on failure 01071 */ 01072 void * 01073 pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) 01074 { 01075 const struct pbuf *q; 01076 u16_t out_offset; 01077 01078 LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;); 01079 LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;); 01080 LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;); 01081 01082 q = pbuf_skip_const(p, offset, &out_offset); 01083 if (q != NULL) { 01084 if (q->len >= (out_offset + len)) { 01085 /* all data in this pbuf, return zero-copy */ 01086 return (u8_t *)q->payload + out_offset; 01087 } 01088 /* need to copy */ 01089 if (pbuf_copy_partial(q, buffer, len, out_offset) != len) { 01090 /* copying failed: pbuf is too short */ 01091 return NULL; 01092 } 01093 return buffer; 01094 } 01095 /* pbuf is too short (offset does not fit in) */ 01096 return NULL; 01097 } 01098 01099 #if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE 01100 /** 01101 * This method modifies a 'pbuf chain', so that its total length is 01102 * smaller than 64K. The remainder of the original pbuf chain is stored 01103 * in *rest. 01104 * This function never creates new pbufs, but splits an existing chain 01105 * in two parts. The tot_len of the modified packet queue will likely be 01106 * smaller than 64K. 01107 * 'packet queues' are not supported by this function. 01108 * 01109 * @param p the pbuf queue to be split 01110 * @param rest pointer to store the remainder (after the first 64K) 01111 */ 01112 void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) 01113 { 01114 *rest = NULL; 01115 if ((p != NULL) && (p->next != NULL)) { 01116 u16_t tot_len_front = p->len; 01117 struct pbuf *i = p; 01118 struct pbuf *r = p->next; 01119 01120 /* continue until the total length (summed up as u16_t) overflows */ 01121 while ((r != NULL) && ((u16_t)(tot_len_front + r->len) >= tot_len_front)) { 01122 tot_len_front = (u16_t)(tot_len_front + r->len); 01123 i = r; 01124 r = r->next; 01125 } 01126 /* i now points to last packet of the first segment. Set next 01127 pointer to NULL */ 01128 i->next = NULL; 01129 01130 if (r != NULL) { 01131 /* Update the tot_len field in the first part */ 01132 for (i = p; i != NULL; i = i->next) { 01133 i->tot_len = (u16_t)(i->tot_len - r->tot_len); 01134 LWIP_ASSERT("tot_len/len mismatch in last pbuf", 01135 (i->next != NULL) || (i->tot_len == i->len)); 01136 } 01137 if (p->flags & PBUF_FLAG_TCP_FIN) { 01138 r->flags |= PBUF_FLAG_TCP_FIN; 01139 } 01140 01141 /* tot_len field in rest does not need modifications */ 01142 /* reference counters do not need modifications */ 01143 *rest = r; 01144 } 01145 } 01146 } 01147 #endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ 01148 01149 /* Actual implementation of pbuf_skip() but returning const pointer... */ 01150 static const struct pbuf * 01151 pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset) 01152 { 01153 u16_t offset_left = in_offset; 01154 const struct pbuf *q = in; 01155 01156 /* get the correct pbuf */ 01157 while ((q != NULL) && (q->len <= offset_left)) { 01158 offset_left = (u16_t)(offset_left - q->len); 01159 q = q->next; 01160 } 01161 if (out_offset != NULL) { 01162 *out_offset = offset_left; 01163 } 01164 return q; 01165 } 01166 01167 /** 01168 * @ingroup pbuf 01169 * Skip a number of bytes at the start of a pbuf 01170 * 01171 * @param in input pbuf 01172 * @param in_offset offset to skip 01173 * @param out_offset resulting offset in the returned pbuf 01174 * @return the pbuf in the queue where the offset is 01175 */ 01176 struct pbuf * 01177 pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset) 01178 { 01179 const struct pbuf *out = pbuf_skip_const(in, in_offset, out_offset); 01180 return LWIP_CONST_CAST(struct pbuf *, out); 01181 } 01182 01183 /** 01184 * @ingroup pbuf 01185 * Copy application supplied data into a pbuf. 01186 * This function can only be used to copy the equivalent of buf->tot_len data. 01187 * 01188 * @param buf pbuf to fill with data 01189 * @param dataptr application supplied data buffer 01190 * @param len length of the application supplied data buffer 01191 * 01192 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough 01193 */ 01194 err_t 01195 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) 01196 { 01197 struct pbuf *p; 01198 size_t buf_copy_len; 01199 size_t total_copy_len = len; 01200 size_t copied_total = 0; 01201 01202 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;); 01203 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;); 01204 LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;); 01205 01206 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { 01207 return ERR_ARG; 01208 } 01209 01210 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 01211 for (p = buf; total_copy_len != 0; p = p->next) { 01212 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); 01213 buf_copy_len = total_copy_len; 01214 if (buf_copy_len > p->len) { 01215 /* this pbuf cannot hold all remaining data */ 01216 buf_copy_len = p->len; 01217 } 01218 /* copy the necessary parts of the buffer */ 01219 MEMCPY(p->payload, &((const char *)dataptr)[copied_total], buf_copy_len); 01220 total_copy_len -= buf_copy_len; 01221 copied_total += buf_copy_len; 01222 } 01223 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); 01224 return ERR_OK; 01225 } 01226 01227 /** 01228 * @ingroup pbuf 01229 * Same as pbuf_take() but puts data at an offset 01230 * 01231 * @param buf pbuf to fill with data 01232 * @param dataptr application supplied data buffer 01233 * @param len length of the application supplied data buffer 01234 * @param offset offset in pbuf where to copy dataptr to 01235 * 01236 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough 01237 */ 01238 err_t 01239 pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset) 01240 { 01241 u16_t target_offset; 01242 struct pbuf *q = pbuf_skip(buf, offset, &target_offset); 01243 01244 /* return requested data if pbuf is OK */ 01245 if ((q != NULL) && (q->tot_len >= target_offset + len)) { 01246 u16_t remaining_len = len; 01247 const u8_t *src_ptr = (const u8_t *)dataptr; 01248 /* copy the part that goes into the first pbuf */ 01249 u16_t first_copy_len; 01250 LWIP_ASSERT("check pbuf_skip result", target_offset < q->len); 01251 first_copy_len = (u16_t)LWIP_MIN(q->len - target_offset, len); 01252 MEMCPY(((u8_t *)q->payload) + target_offset, dataptr, first_copy_len); 01253 remaining_len = (u16_t)(remaining_len - first_copy_len); 01254 src_ptr += first_copy_len; 01255 if (remaining_len > 0) { 01256 return pbuf_take(q->next, src_ptr, remaining_len); 01257 } 01258 return ERR_OK; 01259 } 01260 return ERR_MEM; 01261 } 01262 01263 /** 01264 * @ingroup pbuf 01265 * Creates a single pbuf out of a queue of pbufs. 01266 * 01267 * @remark: Either the source pbuf 'p' is freed by this function or the original 01268 * pbuf 'p' is returned, therefore the caller has to check the result! 01269 * 01270 * @param p the source pbuf 01271 * @param layer pbuf_layer of the new pbuf 01272 * 01273 * @return a new, single pbuf (p->next is NULL) 01274 * or the old pbuf if allocation fails 01275 */ 01276 struct pbuf * 01277 pbuf_coalesce(struct pbuf *p, pbuf_layer layer) 01278 { 01279 struct pbuf *q; 01280 if (p->next == NULL) { 01281 return p; 01282 } 01283 q = pbuf_clone(layer, PBUF_RAM, p); 01284 if (q == NULL) { 01285 /* @todo: what do we do now? */ 01286 return p; 01287 } 01288 pbuf_free(p); 01289 return q; 01290 } 01291 01292 /** 01293 * @ingroup pbuf 01294 * Allocates a new pbuf of same length (via pbuf_alloc()) and copies the source 01295 * pbuf into this new pbuf (using pbuf_copy()). 01296 * 01297 * @param layer pbuf_layer of the new pbuf 01298 * @param type this parameter decides how and where the pbuf should be allocated 01299 * (@see pbuf_alloc()) 01300 * @param p the source pbuf 01301 * 01302 * @return a new pbuf or NULL if allocation fails 01303 */ 01304 struct pbuf * 01305 pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p) 01306 { 01307 struct pbuf *q; 01308 err_t err; 01309 q = pbuf_alloc(layer, p->tot_len, type); 01310 if (q == NULL) { 01311 return NULL; 01312 } 01313 err = pbuf_copy(q, p); 01314 LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ 01315 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); 01316 return q; 01317 } 01318 01319 #if LWIP_CHECKSUM_ON_COPY 01320 /** 01321 * Copies data into a single pbuf (*not* into a pbuf queue!) and updates 01322 * the checksum while copying 01323 * 01324 * @param p the pbuf to copy data into 01325 * @param start_offset offset of p->payload where to copy the data to 01326 * @param dataptr data to copy into the pbuf 01327 * @param len length of data to copy into the pbuf 01328 * @param chksum pointer to the checksum which is updated 01329 * @return ERR_OK if successful, another error if the data does not fit 01330 * within the (first) pbuf (no pbuf queues!) 01331 */ 01332 err_t 01333 pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, 01334 u16_t len, u16_t *chksum) 01335 { 01336 u32_t acc; 01337 u16_t copy_chksum; 01338 char *dst_ptr; 01339 LWIP_ASSERT("p != NULL", p != NULL); 01340 LWIP_ASSERT("dataptr != NULL", dataptr != NULL); 01341 LWIP_ASSERT("chksum != NULL", chksum != NULL); 01342 LWIP_ASSERT("len != 0", len != 0); 01343 01344 if ((start_offset >= p->len) || (start_offset + len > p->len)) { 01345 return ERR_ARG; 01346 } 01347 01348 dst_ptr = ((char *)p->payload) + start_offset; 01349 copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); 01350 if ((start_offset & 1) != 0) { 01351 copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); 01352 } 01353 acc = *chksum; 01354 acc += copy_chksum; 01355 *chksum = FOLD_U32T(acc); 01356 return ERR_OK; 01357 } 01358 #endif /* LWIP_CHECKSUM_ON_COPY */ 01359 01360 /** 01361 * @ingroup pbuf 01362 * Get one byte from the specified position in a pbuf 01363 * WARNING: returns zero for offset >= p->tot_len 01364 * 01365 * @param p pbuf to parse 01366 * @param offset offset into p of the byte to return 01367 * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len 01368 */ 01369 u8_t 01370 pbuf_get_at(const struct pbuf *p, u16_t offset) 01371 { 01372 int ret = pbuf_try_get_at(p, offset); 01373 if (ret >= 0) { 01374 return (u8_t)ret; 01375 } 01376 return 0; 01377 } 01378 01379 /** 01380 * @ingroup pbuf 01381 * Get one byte from the specified position in a pbuf 01382 * 01383 * @param p pbuf to parse 01384 * @param offset offset into p of the byte to return 01385 * @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len 01386 */ 01387 int 01388 pbuf_try_get_at(const struct pbuf *p, u16_t offset) 01389 { 01390 u16_t q_idx; 01391 const struct pbuf *q = pbuf_skip_const(p, offset, &q_idx); 01392 01393 /* return requested data if pbuf is OK */ 01394 if ((q != NULL) && (q->len > q_idx)) { 01395 return ((u8_t *)q->payload)[q_idx]; 01396 } 01397 return -1; 01398 } 01399 01400 /** 01401 * @ingroup pbuf 01402 * Put one byte to the specified position in a pbuf 01403 * WARNING: silently ignores offset >= p->tot_len 01404 * 01405 * @param p pbuf to fill 01406 * @param offset offset into p of the byte to write 01407 * @param data byte to write at an offset into p 01408 */ 01409 void 01410 pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data) 01411 { 01412 u16_t q_idx; 01413 struct pbuf *q = pbuf_skip(p, offset, &q_idx); 01414 01415 /* write requested data if pbuf is OK */ 01416 if ((q != NULL) && (q->len > q_idx)) { 01417 ((u8_t *)q->payload)[q_idx] = data; 01418 } 01419 } 01420 01421 /** 01422 * @ingroup pbuf 01423 * Compare pbuf contents at specified offset with memory s2, both of length n 01424 * 01425 * @param p pbuf to compare 01426 * @param offset offset into p at which to start comparing 01427 * @param s2 buffer to compare 01428 * @param n length of buffer to compare 01429 * @return zero if equal, nonzero otherwise 01430 * (0xffff if p is too short, diffoffset+1 otherwise) 01431 */ 01432 u16_t 01433 pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n) 01434 { 01435 u16_t start = offset; 01436 const struct pbuf *q = p; 01437 u16_t i; 01438 01439 /* pbuf long enough to perform check? */ 01440 if (p->tot_len < (offset + n)) { 01441 return 0xffff; 01442 } 01443 01444 /* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */ 01445 while ((q != NULL) && (q->len <= start)) { 01446 start = (u16_t)(start - q->len); 01447 q = q->next; 01448 } 01449 01450 /* return requested data if pbuf is OK */ 01451 for (i = 0; i < n; i++) { 01452 /* We know pbuf_get_at() succeeds because of p->tot_len check above. */ 01453 u8_t a = pbuf_get_at(q, (u16_t)(start + i)); 01454 u8_t b = ((const u8_t *)s2)[i]; 01455 if (a != b) { 01456 return (u16_t)LWIP_MIN(i + 1, 0xFFFF); 01457 } 01458 } 01459 return 0; 01460 } 01461 01462 /** 01463 * @ingroup pbuf 01464 * Find occurrence of mem (with length mem_len) in pbuf p, starting at offset 01465 * start_offset. 01466 * 01467 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as 01468 * return value 'not found' 01469 * @param mem search for the contents of this buffer 01470 * @param mem_len length of 'mem' 01471 * @param start_offset offset into p at which to start searching 01472 * @return 0xFFFF if substr was not found in p or the index where it was found 01473 */ 01474 u16_t 01475 pbuf_memfind(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset) 01476 { 01477 u16_t i; 01478 u16_t max_cmp_start = (u16_t)(p->tot_len - mem_len); 01479 if (p->tot_len >= mem_len + start_offset) { 01480 for (i = start_offset; i <= max_cmp_start; i++) { 01481 u16_t plus = pbuf_memcmp(p, i, mem, mem_len); 01482 if (plus == 0) { 01483 return i; 01484 } 01485 } 01486 } 01487 return 0xFFFF; 01488 } 01489 01490 /** 01491 * Find occurrence of substr with length substr_len in pbuf p, start at offset 01492 * start_offset 01493 * WARNING: in contrast to strstr(), this one does not stop at the first \0 in 01494 * the pbuf/source string! 01495 * 01496 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as 01497 * return value 'not found' 01498 * @param substr string to search for in p, maximum length is 0xFFFE 01499 * @return 0xFFFF if substr was not found in p or the index where it was found 01500 */ 01501 u16_t 01502 pbuf_strstr(const struct pbuf *p, const char *substr) 01503 { 01504 size_t substr_len; 01505 if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { 01506 return 0xFFFF; 01507 } 01508 substr_len = strlen(substr); 01509 if (substr_len >= 0xFFFF) { 01510 return 0xFFFF; 01511 } 01512 return pbuf_memfind(p, substr, (u16_t)substr_len, 0); 01513 }
Generated on Tue Jul 12 2022 13:54:29 by
