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 lwip 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 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 = (void *)((u8_t *)payload_mem + offset); 00380 } else { 00381 p->pbuf.payload = NULL; 00382 } 00383 p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; 00384 p->pbuf.len = p->pbuf.tot_len = length; 00385 p->pbuf.type = type; 00386 p->pbuf.ref = 1; 00387 return &p->pbuf; 00388 } 00389 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ 00390 00391 /** 00392 * Shrink a pbuf chain to a desired length. 00393 * 00394 * @param p pbuf to shrink. 00395 * @param new_len desired new length of pbuf chain 00396 * 00397 * Depending on the desired length, the first few pbufs in a chain might 00398 * be skipped and left unchanged. The new last pbuf in the chain will be 00399 * resized, and any remaining pbufs will be freed. 00400 * 00401 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. 00402 * @note May not be called on a packet queue. 00403 * 00404 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). 00405 */ 00406 void 00407 pbuf_realloc(struct pbuf *p, u16_t new_len) 00408 { 00409 struct pbuf *q; 00410 u16_t rem_len; /* remaining length */ 00411 s32_t grow; 00412 00413 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); 00414 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || 00415 p->type == PBUF_ROM || 00416 p->type == PBUF_RAM || 00417 p->type == PBUF_REF); 00418 00419 /* desired length larger than current length? */ 00420 if (new_len >= p->tot_len) { 00421 /* enlarging not yet supported */ 00422 return; 00423 } 00424 00425 /* the pbuf chain grows by (new_len - p->tot_len) bytes 00426 * (which may be negative in case of shrinking) */ 00427 grow = new_len - p->tot_len; 00428 00429 /* first, step over any pbufs that should remain in the chain */ 00430 rem_len = new_len; 00431 q = p; 00432 /* should this pbuf be kept? */ 00433 while (rem_len > q->len) { 00434 /* decrease remaining length by pbuf length */ 00435 rem_len -= q->len; 00436 /* decrease total length indicator */ 00437 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); 00438 q->tot_len += (u16_t)grow; 00439 /* proceed to next pbuf in chain */ 00440 q = q->next; 00441 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); 00442 } 00443 /* we have now reached the new last pbuf (in q) */ 00444 /* rem_len == desired length for pbuf q */ 00445 00446 /* shrink allocated memory for PBUF_RAM */ 00447 /* (other types merely adjust their length fields */ 00448 if ((q->type == PBUF_RAM) && (rem_len != q->len)) { 00449 /* reallocate and adjust the length of the pbuf that will be split */ 00450 q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); 00451 LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); 00452 } 00453 /* adjust length fields for new last pbuf */ 00454 q->len = rem_len; 00455 q->tot_len = q->len; 00456 00457 /* any remaining pbufs in chain? */ 00458 if (q->next != NULL) { 00459 /* free remaining pbufs in chain */ 00460 pbuf_free(q->next); 00461 } 00462 /* q is last packet in chain */ 00463 q->next = NULL; 00464 00465 } 00466 00467 /** 00468 * Adjusts the payload pointer to hide or reveal headers in the payload. 00469 * 00470 * Adjusts the ->payload pointer so that space for a header 00471 * (dis)appears in the pbuf payload. 00472 * 00473 * The ->payload, ->tot_len and ->len fields are adjusted. 00474 * 00475 * @param p pbuf to change the header size. 00476 * @param header_size_increment Number of bytes to increment header size which 00477 * increases the size of the pbuf. New space is on the front. 00478 * (Using a negative value decreases the header size.) 00479 * If hdr_size_inc is 0, this function does nothing and returns succesful. 00480 * 00481 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00482 * the call will fail. A check is made that the increase in header size does 00483 * not move the payload pointer in front of the start of the buffer. 00484 * @return non-zero on failure, zero on success. 00485 * 00486 */ 00487 u8_t 00488 pbuf_header(struct pbuf *p, s16_t header_size_increment) 00489 { 00490 u16_t type; 00491 void *payload; 00492 u16_t increment_magnitude; 00493 00494 LWIP_ASSERT("p != NULL", p != NULL); 00495 if ((header_size_increment == 0) || (p == NULL)) { 00496 return 0; 00497 } 00498 00499 if (header_size_increment < 0){ 00500 increment_magnitude = -header_size_increment; 00501 /* Check that we aren't going to move off the end of the pbuf */ 00502 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); 00503 } else { 00504 increment_magnitude = header_size_increment; 00505 #if 0 00506 /* Can't assert these as some callers speculatively call 00507 pbuf_header() to see if it's OK. Will return 1 below instead. */ 00508 /* Check that we've got the correct type of pbuf to work with */ 00509 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 00510 p->type == PBUF_RAM || p->type == PBUF_POOL); 00511 /* Check that we aren't going to move off the beginning of the pbuf */ 00512 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", 00513 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); 00514 #endif 00515 } 00516 00517 type = p->type; 00518 /* remember current payload pointer */ 00519 payload = p->payload; 00520 00521 /* pbuf types containing payloads? */ 00522 if (type == PBUF_RAM || type == PBUF_POOL) { 00523 /* set new payload pointer */ 00524 p->payload = (u8_t *)p->payload - header_size_increment; 00525 /* boundary check fails? */ 00526 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { 00527 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00528 ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", 00529 (void *)p->payload, (void *)(p + 1))); 00530 /* restore old payload pointer */ 00531 p->payload = payload; 00532 /* bail out unsuccesfully */ 00533 return 1; 00534 } 00535 /* pbuf types refering to external payloads? */ 00536 } else if (type == PBUF_REF || type == PBUF_ROM) { 00537 /* hide a header in the payload? */ 00538 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { 00539 /* increase payload pointer */ 00540 p->payload = (u8_t *)p->payload - header_size_increment; 00541 } else { 00542 /* cannot expand payload to front (yet!) 00543 * bail out unsuccesfully */ 00544 return 1; 00545 } 00546 } else { 00547 /* Unknown type */ 00548 LWIP_ASSERT("bad pbuf type", 0); 00549 return 1; 00550 } 00551 /* modify pbuf length fields */ 00552 p->len += header_size_increment; 00553 p->tot_len += header_size_increment; 00554 00555 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", 00556 (void *)payload, (void *)p->payload, header_size_increment)); 00557 00558 return 0; 00559 } 00560 00561 /** 00562 * Dereference a pbuf chain or queue and deallocate any no-longer-used 00563 * pbufs at the head of this chain or queue. 00564 * 00565 * Decrements the pbuf reference count. If it reaches zero, the pbuf is 00566 * deallocated. 00567 * 00568 * For a pbuf chain, this is repeated for each pbuf in the chain, 00569 * up to the first pbuf which has a non-zero reference count after 00570 * decrementing. So, when all reference counts are one, the whole 00571 * chain is free'd. 00572 * 00573 * @param p The pbuf (chain) to be dereferenced. 00574 * 00575 * @return the number of pbufs that were de-allocated 00576 * from the head of the chain. 00577 * 00578 * @note MUST NOT be called on a packet queue (Not verified to work yet). 00579 * @note the reference counter of a pbuf equals the number of pointers 00580 * that refer to the pbuf (or into the pbuf). 00581 * 00582 * @internal examples: 00583 * 00584 * Assuming existing chains a->b->c with the following reference 00585 * counts, calling pbuf_free(a) results in: 00586 * 00587 * 1->2->3 becomes ...1->3 00588 * 3->3->3 becomes 2->3->3 00589 * 1->1->2 becomes ......1 00590 * 2->1->1 becomes 1->1->1 00591 * 1->1->1 becomes ....... 00592 * 00593 */ 00594 u8_t 00595 pbuf_free(struct pbuf *p) 00596 { 00597 u16_t type; 00598 struct pbuf *q; 00599 u8_t count; 00600 00601 if (p == NULL) { 00602 LWIP_ASSERT("p != NULL", p != NULL); 00603 /* if assertions are disabled, proceed with debug output */ 00604 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00605 ("pbuf_free(p == NULL) was called.\n")); 00606 return 0; 00607 } 00608 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); 00609 00610 PERF_START; 00611 00612 LWIP_ASSERT("pbuf_free: sane type", 00613 p->type == PBUF_RAM || p->type == PBUF_ROM || 00614 p->type == PBUF_REF || p->type == PBUF_POOL); 00615 00616 count = 0; 00617 /* de-allocate all consecutive pbufs from the head of the chain that 00618 * obtain a zero reference count after decrementing*/ 00619 while (p != NULL) { 00620 u16_t ref; 00621 SYS_ARCH_DECL_PROTECT(old_level); 00622 /* Since decrementing ref cannot be guaranteed to be a single machine operation 00623 * we must protect it. We put the new ref into a local variable to prevent 00624 * further protection. */ 00625 SYS_ARCH_PROTECT(old_level); 00626 /* all pbufs in a chain are referenced at least once */ 00627 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); 00628 /* decrease reference count (number of pointers to pbuf) */ 00629 ref = --(p->ref); 00630 SYS_ARCH_UNPROTECT(old_level); 00631 /* this pbuf is no longer referenced to? */ 00632 if (ref == 0) { 00633 /* remember next pbuf in chain for next iteration */ 00634 q = p->next; 00635 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); 00636 type = p->type; 00637 #if LWIP_SUPPORT_CUSTOM_PBUF 00638 /* is this a custom pbuf? */ 00639 if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { 00640 struct pbuf_custom *pc = (struct pbuf_custom*)p; 00641 LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); 00642 pc->custom_free_function(p); 00643 } else 00644 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ 00645 { 00646 /* is this a pbuf from the pool? */ 00647 if (type == PBUF_POOL) { 00648 memp_free(MEMP_PBUF_POOL, p); 00649 /* is this a ROM or RAM referencing pbuf? */ 00650 } else if (type == PBUF_ROM || type == PBUF_REF) { 00651 memp_free(MEMP_PBUF, p); 00652 /* type == PBUF_RAM */ 00653 } else { 00654 mem_free(p); 00655 } 00656 } 00657 count++; 00658 /* proceed to next pbuf */ 00659 p = q; 00660 /* p->ref > 0, this pbuf is still referenced to */ 00661 /* (and so the remaining pbufs in chain as well) */ 00662 } else { 00663 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); 00664 /* stop walking through the chain */ 00665 p = NULL; 00666 } 00667 } 00668 PERF_STOP("pbuf_free"); 00669 /* return number of de-allocated pbufs */ 00670 return count; 00671 } 00672 00673 /** 00674 * Count number of pbufs in a chain 00675 * 00676 * @param p first pbuf of chain 00677 * @return the number of pbufs in a chain 00678 */ 00679 00680 u8_t 00681 pbuf_clen(struct pbuf *p) 00682 { 00683 u8_t len; 00684 00685 len = 0; 00686 while (p != NULL) { 00687 ++len; 00688 p = p->next; 00689 } 00690 return len; 00691 } 00692 00693 /** 00694 * Increment the reference count of the pbuf. 00695 * 00696 * @param p pbuf to increase reference counter of 00697 * 00698 */ 00699 void 00700 pbuf_ref(struct pbuf *p) 00701 { 00702 SYS_ARCH_DECL_PROTECT(old_level); 00703 /* pbuf given? */ 00704 if (p != NULL) { 00705 SYS_ARCH_PROTECT(old_level); 00706 ++(p->ref); 00707 SYS_ARCH_UNPROTECT(old_level); 00708 } 00709 } 00710 00711 /** 00712 * Concatenate two pbufs (each may be a pbuf chain) and take over 00713 * the caller's reference of the tail pbuf. 00714 * 00715 * @note The caller MAY NOT reference the tail pbuf afterwards. 00716 * Use pbuf_chain() for that purpose. 00717 * 00718 * @see pbuf_chain() 00719 */ 00720 00721 void 00722 pbuf_cat(struct pbuf *h, struct pbuf *t) 00723 { 00724 struct pbuf *p; 00725 00726 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", 00727 ((h != NULL) && (t != NULL)), return;); 00728 00729 /* proceed to last pbuf of chain */ 00730 for (p = h; p->next != NULL; p = p->next) { 00731 /* add total length of second chain to all totals of first chain */ 00732 p->tot_len += t->tot_len; 00733 } 00734 /* { p is last pbuf of first h chain, p->next == NULL } */ 00735 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); 00736 LWIP_ASSERT("p->next == NULL", p->next == NULL); 00737 /* add total length of second chain to last pbuf total of first chain */ 00738 p->tot_len += t->tot_len; 00739 /* chain last pbuf of head (p) with first of tail (t) */ 00740 p->next = t; 00741 /* p->next now references t, but the caller will drop its reference to t, 00742 * so netto there is no change to the reference count of t. 00743 */ 00744 } 00745 00746 /** 00747 * Chain two pbufs (or pbuf chains) together. 00748 * 00749 * The caller MUST call pbuf_free(t) once it has stopped 00750 * using it. Use pbuf_cat() instead if you no longer use t. 00751 * 00752 * @param h head pbuf (chain) 00753 * @param t tail pbuf (chain) 00754 * @note The pbufs MUST belong to the same packet. 00755 * @note MAY NOT be called on a packet queue. 00756 * 00757 * The ->tot_len fields of all pbufs of the head chain are adjusted. 00758 * The ->next field of the last pbuf of the head chain is adjusted. 00759 * The ->ref field of the first pbuf of the tail chain is adjusted. 00760 * 00761 */ 00762 void 00763 pbuf_chain(struct pbuf *h, struct pbuf *t) 00764 { 00765 pbuf_cat(h, t); 00766 /* t is now referenced by h */ 00767 pbuf_ref(t); 00768 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); 00769 } 00770 00771 /** 00772 * Dechains the first pbuf from its succeeding pbufs in the chain. 00773 * 00774 * Makes p->tot_len field equal to p->len. 00775 * @param p pbuf to dechain 00776 * @return remainder of the pbuf chain, or NULL if it was de-allocated. 00777 * @note May not be called on a packet queue. 00778 */ 00779 struct pbuf * 00780 pbuf_dechain(struct pbuf *p) 00781 { 00782 struct pbuf *q; 00783 u8_t tail_gone = 1; 00784 /* tail */ 00785 q = p->next; 00786 /* pbuf has successor in chain? */ 00787 if (q != NULL) { 00788 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00789 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); 00790 /* enforce invariant if assertion is disabled */ 00791 q->tot_len = p->tot_len - p->len; 00792 /* decouple pbuf from remainder */ 00793 p->next = NULL; 00794 /* total length of pbuf p is its own length only */ 00795 p->tot_len = p->len; 00796 /* q is no longer referenced by p, free it */ 00797 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); 00798 tail_gone = pbuf_free(q); 00799 if (tail_gone > 0) { 00800 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, 00801 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); 00802 } 00803 /* return remaining tail or NULL if deallocated */ 00804 } 00805 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00806 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); 00807 return ((tail_gone > 0) ? NULL : q); 00808 } 00809 00810 /** 00811 * 00812 * Create PBUF_RAM copies of pbufs. 00813 * 00814 * Used to queue packets on behalf of the lwIP stack, such as 00815 * ARP based queueing. 00816 * 00817 * @note You MUST explicitly use p = pbuf_take(p); 00818 * 00819 * @note Only one packet is copied, no packet queue! 00820 * 00821 * @param p_to pbuf destination of the copy 00822 * @param p_from pbuf source of the copy 00823 * 00824 * @return ERR_OK if pbuf was copied 00825 * ERR_ARG if one of the pbufs is NULL or p_to is not big 00826 * enough to hold p_from 00827 */ 00828 err_t 00829 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) 00830 { 00831 u16_t offset_to=0, offset_from=0, len; 00832 00833 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", 00834 (void*)p_to, (void*)p_from)); 00835 00836 /* is the target big enough to hold the source? */ 00837 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && 00838 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); 00839 00840 /* iterate through pbuf chain */ 00841 do 00842 { 00843 LWIP_ASSERT("p_to != NULL", p_to != NULL); 00844 /* copy one part of the original chain */ 00845 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { 00846 /* complete current p_from fits into current p_to */ 00847 len = p_from->len - offset_from; 00848 } else { 00849 /* current p_from does not fit into current p_to */ 00850 len = p_to->len - offset_to; 00851 } 00852 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); 00853 offset_to += len; 00854 offset_from += len; 00855 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); 00856 if (offset_to == p_to->len) { 00857 /* on to next p_to (if any) */ 00858 offset_to = 0; 00859 p_to = p_to->next; 00860 } 00861 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); 00862 if (offset_from >= p_from->len) { 00863 /* on to next p_from (if any) */ 00864 offset_from = 0; 00865 p_from = p_from->next; 00866 } 00867 00868 if((p_from != NULL) && (p_from->len == p_from->tot_len)) { 00869 /* don't copy more than one packet! */ 00870 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00871 (p_from->next == NULL), return ERR_VAL;); 00872 } 00873 if((p_to != NULL) && (p_to->len == p_to->tot_len)) { 00874 /* don't copy more than one packet! */ 00875 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00876 (p_to->next == NULL), return ERR_VAL;); 00877 } 00878 } while (p_from); 00879 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); 00880 return ERR_OK; 00881 } 00882 00883 /** 00884 * Copy (part of) the contents of a packet buffer 00885 * to an application supplied buffer. 00886 * 00887 * @param buf the pbuf from which to copy data 00888 * @param dataptr the application supplied buffer 00889 * @param len length of data to copy (dataptr must be big enough). No more 00890 * than buf->tot_len will be copied, irrespective of len 00891 * @param offset offset into the packet buffer from where to begin copying len bytes 00892 * @return the number of bytes copied, or 0 on failure 00893 */ 00894 u16_t 00895 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) 00896 { 00897 struct pbuf *p; 00898 u16_t left; 00899 u16_t buf_copy_len; 00900 u16_t copied_total = 0; 00901 00902 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); 00903 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); 00904 00905 left = 0; 00906 00907 if((buf == NULL) || (dataptr == NULL)) { 00908 return 0; 00909 } 00910 00911 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00912 for(p = buf; len != 0 && p != NULL; p = p->next) { 00913 if ((offset != 0) && (offset >= p->len)) { 00914 /* don't copy from this buffer -> on to the next */ 00915 offset -= p->len; 00916 } else { 00917 /* copy from this buffer. maybe only partially. */ 00918 buf_copy_len = p->len - offset; 00919 if (buf_copy_len > len) 00920 buf_copy_len = len; 00921 /* copy the necessary parts of the buffer */ 00922 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); 00923 copied_total += buf_copy_len; 00924 left += buf_copy_len; 00925 len -= buf_copy_len; 00926 offset = 0; 00927 } 00928 } 00929 return copied_total; 00930 } 00931 00932 /** 00933 * Copy application supplied data into a pbuf. 00934 * This function can only be used to copy the equivalent of buf->tot_len data. 00935 * 00936 * @param buf pbuf to fill with data 00937 * @param dataptr application supplied data buffer 00938 * @param len length of the application supplied data buffer 00939 * 00940 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough 00941 */ 00942 err_t 00943 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) 00944 { 00945 struct pbuf *p; 00946 u16_t buf_copy_len; 00947 u16_t total_copy_len = len; 00948 u16_t copied_total = 0; 00949 00950 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); 00951 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); 00952 00953 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { 00954 return ERR_ARG; 00955 } 00956 00957 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00958 for(p = buf; total_copy_len != 0; p = p->next) { 00959 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); 00960 buf_copy_len = total_copy_len; 00961 if (buf_copy_len > p->len) { 00962 /* this pbuf cannot hold all remaining data */ 00963 buf_copy_len = p->len; 00964 } 00965 /* copy the necessary parts of the buffer */ 00966 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); 00967 total_copy_len -= buf_copy_len; 00968 copied_total += buf_copy_len; 00969 } 00970 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); 00971 return ERR_OK; 00972 } 00973 00974 /** 00975 * Creates a single pbuf out of a queue of pbufs. 00976 * 00977 * @remark: Either the source pbuf 'p' is freed by this function or the original 00978 * pbuf 'p' is returned, therefore the caller has to check the result! 00979 * 00980 * @param p the source pbuf 00981 * @param layer pbuf_layer of the new pbuf 00982 * 00983 * @return a new, single pbuf (p->next is NULL) 00984 * or the old pbuf if allocation fails 00985 */ 00986 struct pbuf* 00987 pbuf_coalesce(struct pbuf *p, pbuf_layer layer) 00988 { 00989 struct pbuf *q; 00990 err_t err; 00991 if (p->next == NULL) { 00992 return p; 00993 } 00994 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); 00995 if (q == NULL) { 00996 /* @todo: what do we do now? */ 00997 return p; 00998 } 00999 err = pbuf_copy(q, p); 01000 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); 01001 /* next line references err variable even if LWIP_ASSERT is ignored. */ 01002 (void)err; 01003 pbuf_free(p); 01004 return q; 01005 } 01006 01007 #if LWIP_CHECKSUM_ON_COPY 01008 /** 01009 * Copies data into a single pbuf (*not* into a pbuf queue!) and updates 01010 * the checksum while copying 01011 * 01012 * @param p the pbuf to copy data into 01013 * @param start_offset offset of p->payload where to copy the data to 01014 * @param dataptr data to copy into the pbuf 01015 * @param len length of data to copy into the pbuf 01016 * @param chksum pointer to the checksum which is updated 01017 * @return ERR_OK if successful, another error if the data does not fit 01018 * within the (first) pbuf (no pbuf queues!) 01019 */ 01020 err_t 01021 pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, 01022 u16_t len, u16_t *chksum) 01023 { 01024 u32_t acc; 01025 u16_t copy_chksum; 01026 char *dst_ptr; 01027 LWIP_ASSERT("p != NULL", p != NULL); 01028 LWIP_ASSERT("dataptr != NULL", dataptr != NULL); 01029 LWIP_ASSERT("chksum != NULL", chksum != NULL); 01030 LWIP_ASSERT("len != 0", len != 0); 01031 01032 if ((start_offset >= p->len) || (start_offset + len > p->len)) { 01033 return ERR_ARG; 01034 } 01035 01036 dst_ptr = ((char*)p->payload) + start_offset; 01037 copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); 01038 if ((start_offset & 1) != 0) { 01039 copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); 01040 } 01041 acc = *chksum; 01042 acc += copy_chksum; 01043 *chksum = FOLD_U32T(acc); 01044 return ERR_OK; 01045 } 01046 #endif /* LWIP_CHECKSUM_ON_COPY */ 01047 01048 /** Get one byte from the specified position in a pbuf 01049 * WARNING: returns zero for offset >= p->tot_len 01050 * 01051 * @param p pbuf to parse 01052 * @param offset offset into p of the byte to return 01053 * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len 01054 */ 01055 u8_t 01056 pbuf_get_at(struct pbuf* p, u16_t offset) 01057 { 01058 u16_t copy_from = offset; 01059 struct pbuf* q = p; 01060 01061 /* get the correct pbuf */ 01062 while ((q != NULL) && (q->len <= copy_from)) { 01063 copy_from -= q->len; 01064 q = q->next; 01065 } 01066 /* return requested data if pbuf is OK */ 01067 if ((q != NULL) && (q->len > copy_from)) { 01068 return ((u8_t*)q->payload)[copy_from]; 01069 } 01070 return 0; 01071 } 01072 01073 /** Compare pbuf contents at specified offset with memory s2, both of length n 01074 * 01075 * @param p pbuf to compare 01076 * @param offset offset into p at wich to start comparing 01077 * @param s2 buffer to compare 01078 * @param n length of buffer to compare 01079 * @return zero if equal, nonzero otherwise 01080 * (0xffff if p is too short, diffoffset+1 otherwise) 01081 */ 01082 u16_t 01083 pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) 01084 { 01085 u16_t start = offset; 01086 struct pbuf* q = p; 01087 01088 /* get the correct pbuf */ 01089 while ((q != NULL) && (q->len <= start)) { 01090 start -= q->len; 01091 q = q->next; 01092 } 01093 /* return requested data if pbuf is OK */ 01094 if ((q != NULL) && (q->len > start)) { 01095 u16_t i; 01096 for(i = 0; i < n; i++) { 01097 u8_t a = pbuf_get_at(q, start + i); 01098 u8_t b = ((u8_t*)s2)[i]; 01099 if (a != b) { 01100 return i+1; 01101 } 01102 } 01103 return 0; 01104 } 01105 return 0xffff; 01106 } 01107 01108 /** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset 01109 * start_offset. 01110 * 01111 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as 01112 * return value 'not found' 01113 * @param mem search for the contents of this buffer 01114 * @param mem_len length of 'mem' 01115 * @param start_offset offset into p at which to start searching 01116 * @return 0xFFFF if substr was not found in p or the index where it was found 01117 */ 01118 u16_t 01119 pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) 01120 { 01121 u16_t i; 01122 u16_t max = p->tot_len - mem_len; 01123 if (p->tot_len >= mem_len + start_offset) { 01124 for(i = start_offset; i <= max; ) { 01125 u16_t plus = pbuf_memcmp(p, i, mem, mem_len); 01126 if (plus == 0) { 01127 return i; 01128 } else { 01129 i += plus; 01130 } 01131 } 01132 } 01133 return 0xFFFF; 01134 } 01135 01136 /** Find occurrence of substr with length substr_len in pbuf p, start at offset 01137 * start_offset 01138 * WARNING: in contrast to strstr(), this one does not stop at the first \0 in 01139 * the pbuf/source string! 01140 * 01141 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as 01142 * return value 'not found' 01143 * @param substr string to search for in p, maximum length is 0xFFFE 01144 * @return 0xFFFF if substr was not found in p or the index where it was found 01145 */ 01146 u16_t 01147 pbuf_strstr(struct pbuf* p, const char* substr) 01148 { 01149 size_t substr_len; 01150 if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { 01151 return 0xFFFF; 01152 } 01153 substr_len = strlen(substr); 01154 if (substr_len >= 0xFFFF) { 01155 return 0xFFFF; 01156 } 01157 return pbuf_memfind(p, substr, (u16_t)substr_len, 0); 01158 }
Generated on Tue Jul 12 2022 11:29:37 by
