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