lwip-1.4.1 (partial)
Embed:
(wiki syntax)
Show/hide line numbers
pbuf.c
Go to the documentation of this file.
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 09:48:37 by 1.7.2