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