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