![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.
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 00077 #include <string.h> 00078 00079 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) 00080 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically 00081 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ 00082 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) 00083 00084 #if !TCP_QUEUE_OOSEQ || NO_SYS 00085 #define PBUF_POOL_IS_EMPTY() 00086 #else /* !TCP_QUEUE_OOSEQ || NO_SYS */ 00087 /** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ 00088 #ifndef PBUF_POOL_FREE_OOSEQ 00089 #define PBUF_POOL_FREE_OOSEQ 1 00090 #endif /* PBUF_POOL_FREE_OOSEQ */ 00091 00092 #if PBUF_POOL_FREE_OOSEQ 00093 #include "lwip/tcpip.h" 00094 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() 00095 static u8_t pbuf_free_ooseq_queued; 00096 /** 00097 * Attempt to reclaim some memory from queued out-of-sequence TCP segments 00098 * if we run out of pool pbufs. It's better to give priority to new packets 00099 * if we're running out. 00100 * 00101 * This must be done in the correct thread context therefore this function 00102 * can only be used with NO_SYS=0 and through tcpip_callback. 00103 */ 00104 static void 00105 pbuf_free_ooseq(void* arg) 00106 { 00107 struct tcp_pcb* pcb; 00108 SYS_ARCH_DECL_PROTECT(old_level); 00109 LWIP_UNUSED_ARG(arg); 00110 00111 SYS_ARCH_PROTECT(old_level); 00112 pbuf_free_ooseq_queued = 0; 00113 SYS_ARCH_UNPROTECT(old_level); 00114 00115 for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { 00116 if (NULL != pcb->ooseq) { 00117 /** Free the ooseq pbufs of one PCB only */ 00118 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); 00119 tcp_segs_free(pcb->ooseq); 00120 pcb->ooseq = NULL; 00121 return; 00122 } 00123 } 00124 } 00125 00126 /** Queue a call to pbuf_free_ooseq if not already queued. */ 00127 static void 00128 pbuf_pool_is_empty(void) 00129 { 00130 u8_t queued; 00131 SYS_ARCH_DECL_PROTECT(old_level); 00132 00133 SYS_ARCH_PROTECT(old_level); 00134 queued = pbuf_free_ooseq_queued; 00135 pbuf_free_ooseq_queued = 1; 00136 SYS_ARCH_UNPROTECT(old_level); 00137 00138 if(!queued) { 00139 /* queue a call to pbuf_free_ooseq if not already queued */ 00140 if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) { 00141 SYS_ARCH_PROTECT(old_level); 00142 pbuf_free_ooseq_queued = 0; 00143 SYS_ARCH_UNPROTECT(old_level); 00144 } 00145 } 00146 } 00147 #endif /* PBUF_POOL_FREE_OOSEQ */ 00148 #endif /* !TCP_QUEUE_OOSEQ || NO_SYS */ 00149 00150 /** 00151 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). 00152 * 00153 * The actual memory allocated for the pbuf is determined by the 00154 * layer at which the pbuf is allocated and the requested size 00155 * (from the size parameter). 00156 * 00157 * @param layer flag to define header size 00158 * @param length size of the pbuf's payload 00159 * @param type this parameter decides how and where the pbuf 00160 * should be allocated as follows: 00161 * 00162 * - PBUF_RAM: buffer memory for pbuf is allocated as one large 00163 * chunk. This includes protocol headers as well. 00164 * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for 00165 * protocol headers. Additional headers must be prepended 00166 * by allocating another pbuf and chain in to the front of 00167 * the ROM pbuf. It is assumed that the memory used is really 00168 * similar to ROM in that it is immutable and will not be 00169 * changed. Memory which is dynamic should generally not 00170 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. 00171 * - PBUF_REF: no buffer memory is allocated for the pbuf, even for 00172 * protocol headers. It is assumed that the pbuf is only 00173 * being used in a single thread. If the pbuf gets queued, 00174 * then pbuf_take should be called to copy the buffer. 00175 * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from 00176 * the pbuf pool that is allocated during pbuf_init(). 00177 * 00178 * @return the allocated pbuf. If multiple pbufs where allocated, this 00179 * is the first pbuf of a pbuf chain. 00180 */ 00181 struct pbuf * 00182 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) 00183 { 00184 struct pbuf *p, *q, *r; 00185 u16_t offset; 00186 s32_t rem_len; /* remaining length */ 00187 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); 00188 00189 /* determine header offset */ 00190 offset = 0; 00191 switch (layer) { 00192 case PBUF_TRANSPORT: 00193 /* add room for transport (often TCP) layer header */ 00194 offset += PBUF_TRANSPORT_HLEN; 00195 /* FALLTHROUGH */ 00196 case PBUF_IP: 00197 /* add room for IP layer header */ 00198 offset += PBUF_IP_HLEN; 00199 /* FALLTHROUGH */ 00200 case PBUF_LINK: 00201 /* add room for link layer header */ 00202 offset += PBUF_LINK_HLEN; 00203 break; 00204 case PBUF_RAW: 00205 break; 00206 default: 00207 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); 00208 return NULL; 00209 } 00210 00211 switch (type) { 00212 case PBUF_POOL: 00213 /* allocate head of pbuf chain into p */ 00214 p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); 00215 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); 00216 if (p == NULL) { 00217 PBUF_POOL_IS_EMPTY(); 00218 return NULL; 00219 } 00220 p->type = type; 00221 p->next = NULL; 00222 00223 /* make the payload pointer point 'offset' bytes into pbuf data memory */ 00224 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); 00225 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", 00226 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00227 /* the total length of the pbuf chain is the requested size */ 00228 p->tot_len = length; 00229 /* set the length of the first pbuf in the chain */ 00230 p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); 00231 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", 00232 ((u8_t*)p->payload + p->len <= 00233 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); 00234 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", 00235 (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); 00236 /* set reference count (needed here in case we fail) */ 00237 p->ref = 1; 00238 00239 /* now allocate the tail of the pbuf chain */ 00240 00241 /* remember first pbuf for linkage in next iteration */ 00242 r = p; 00243 /* remaining length to be allocated */ 00244 rem_len = length - p->len; 00245 /* any remaining pbufs to be allocated? */ 00246 while (rem_len > 0) { 00247 q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); 00248 if (q == NULL) { 00249 PBUF_POOL_IS_EMPTY(); 00250 /* free chain so far allocated */ 00251 pbuf_free(p); 00252 /* bail out unsuccesfully */ 00253 return NULL; 00254 } 00255 q->type = type; 00256 q->flags = 0; 00257 q->next = NULL; 00258 /* make previous pbuf point to this pbuf */ 00259 r->next = q; 00260 /* set total length of this pbuf and next in chain */ 00261 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); 00262 q->tot_len = (u16_t)rem_len; 00263 /* this pbuf length is pool size, unless smaller sized tail */ 00264 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); 00265 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); 00266 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", 00267 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); 00268 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", 00269 ((u8_t*)p->payload + p->len <= 00270 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); 00271 q->ref = 1; 00272 /* calculate remaining length to be allocated */ 00273 rem_len -= q->len; 00274 /* remember this pbuf for linkage in next iteration */ 00275 r = q; 00276 } 00277 /* end of chain */ 00278 /*r->next = NULL;*/ 00279 00280 break; 00281 case PBUF_RAM: 00282 /* If pbuf is to be allocated in RAM, allocate memory for it. */ 00283 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); 00284 if (p == NULL) { 00285 return NULL; 00286 } 00287 /* Set up internal structure of the pbuf. */ 00288 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); 00289 p->len = p->tot_len = length; 00290 p->next = NULL; 00291 p->type = type; 00292 00293 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", 00294 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); 00295 break; 00296 /* pbuf references existing (non-volatile static constant) ROM payload? */ 00297 case PBUF_ROM: 00298 /* pbuf references existing (externally allocated) RAM payload? */ 00299 case PBUF_REF: 00300 /* only allocate memory for the pbuf structure */ 00301 p = (struct pbuf *)memp_malloc(MEMP_PBUF); 00302 if (p == NULL) { 00303 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00304 ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", 00305 (type == PBUF_ROM) ? "ROM" : "REF")); 00306 return NULL; 00307 } 00308 /* caller must set this field properly, afterwards */ 00309 p->payload = NULL; 00310 p->len = p->tot_len = length; 00311 p->next = NULL; 00312 p->type = type; 00313 break; 00314 default: 00315 LWIP_ASSERT("pbuf_alloc: erroneous type", 0); 00316 return NULL; 00317 } 00318 /* set reference count */ 00319 p->ref = 1; 00320 /* set flags */ 00321 p->flags = 0; 00322 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); 00323 return p; 00324 } 00325 00326 00327 /** 00328 * Shrink a pbuf chain to a desired length. 00329 * 00330 * @param p pbuf to shrink. 00331 * @param new_len desired new length of pbuf chain 00332 * 00333 * Depending on the desired length, the first few pbufs in a chain might 00334 * be skipped and left unchanged. The new last pbuf in the chain will be 00335 * resized, and any remaining pbufs will be freed. 00336 * 00337 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. 00338 * @note May not be called on a packet queue. 00339 * 00340 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). 00341 */ 00342 void 00343 pbuf_realloc(struct pbuf *p, u16_t new_len) 00344 { 00345 struct pbuf *q; 00346 u16_t rem_len; /* remaining length */ 00347 s32_t grow; 00348 00349 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); 00350 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || 00351 p->type == PBUF_ROM || 00352 p->type == PBUF_RAM || 00353 p->type == PBUF_REF); 00354 00355 /* desired length larger than current length? */ 00356 if (new_len >= p->tot_len) { 00357 /* enlarging not yet supported */ 00358 return; 00359 } 00360 00361 /* the pbuf chain grows by (new_len - p->tot_len) bytes 00362 * (which may be negative in case of shrinking) */ 00363 grow = new_len - p->tot_len; 00364 00365 /* first, step over any pbufs that should remain in the chain */ 00366 rem_len = new_len; 00367 q = p; 00368 /* should this pbuf be kept? */ 00369 while (rem_len > q->len) { 00370 /* decrease remaining length by pbuf length */ 00371 rem_len -= q->len; 00372 /* decrease total length indicator */ 00373 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); 00374 q->tot_len += (u16_t)grow; 00375 /* proceed to next pbuf in chain */ 00376 q = q->next; 00377 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); 00378 } 00379 /* we have now reached the new last pbuf (in q) */ 00380 /* rem_len == desired length for pbuf q */ 00381 00382 /* shrink allocated memory for PBUF_RAM */ 00383 /* (other types merely adjust their length fields */ 00384 if ((q->type == PBUF_RAM) && (rem_len != q->len)) { 00385 /* reallocate and adjust the length of the pbuf that will be split */ 00386 q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); 00387 LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); 00388 } 00389 /* adjust length fields for new last pbuf */ 00390 q->len = rem_len; 00391 q->tot_len = q->len; 00392 00393 /* any remaining pbufs in chain? */ 00394 if (q->next != NULL) { 00395 /* free remaining pbufs in chain */ 00396 pbuf_free(q->next); 00397 } 00398 /* q is last packet in chain */ 00399 q->next = NULL; 00400 00401 } 00402 00403 /** 00404 * Adjusts the payload pointer to hide or reveal headers in the payload. 00405 * 00406 * Adjusts the ->payload pointer so that space for a header 00407 * (dis)appears in the pbuf payload. 00408 * 00409 * The ->payload, ->tot_len and ->len fields are adjusted. 00410 * 00411 * @param p pbuf to change the header size. 00412 * @param header_size_increment Number of bytes to increment header size which 00413 * increases the size of the pbuf. New space is on the front. 00414 * (Using a negative value decreases the header size.) 00415 * If hdr_size_inc is 0, this function does nothing and returns succesful. 00416 * 00417 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so 00418 * the call will fail. A check is made that the increase in header size does 00419 * not move the payload pointer in front of the start of the buffer. 00420 * @return non-zero on failure, zero on success. 00421 * 00422 */ 00423 u8_t 00424 pbuf_header(struct pbuf *p, s16_t header_size_increment) 00425 { 00426 u16_t type; 00427 void *payload; 00428 u16_t increment_magnitude; 00429 00430 LWIP_ASSERT("p != NULL", p != NULL); 00431 if ((header_size_increment == 0) || (p == NULL)) 00432 return 0; 00433 00434 if (header_size_increment < 0){ 00435 increment_magnitude = -header_size_increment; 00436 /* Check that we aren't going to move off the end of the pbuf */ 00437 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); 00438 } else { 00439 increment_magnitude = header_size_increment; 00440 #if 0 00441 /* Can't assert these as some callers speculatively call 00442 pbuf_header() to see if it's OK. Will return 1 below instead. */ 00443 /* Check that we've got the correct type of pbuf to work with */ 00444 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", 00445 p->type == PBUF_RAM || p->type == PBUF_POOL); 00446 /* Check that we aren't going to move off the beginning of the pbuf */ 00447 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", 00448 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); 00449 #endif 00450 } 00451 00452 type = p->type; 00453 /* remember current payload pointer */ 00454 payload = p->payload; 00455 00456 /* pbuf types containing payloads? */ 00457 if (type == PBUF_RAM || type == PBUF_POOL) { 00458 /* set new payload pointer */ 00459 p->payload = (u8_t *)p->payload - header_size_increment; 00460 /* boundary check fails? */ 00461 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { 00462 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00463 ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", 00464 (void *)p->payload, (void *)(p + 1))); 00465 /* restore old payload pointer */ 00466 p->payload = payload; 00467 /* bail out unsuccesfully */ 00468 return 1; 00469 } 00470 /* pbuf types refering to external payloads? */ 00471 } else if (type == PBUF_REF || type == PBUF_ROM) { 00472 /* hide a header in the payload? */ 00473 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { 00474 /* increase payload pointer */ 00475 p->payload = (u8_t *)p->payload - header_size_increment; 00476 } else { 00477 /* cannot expand payload to front (yet!) 00478 * bail out unsuccesfully */ 00479 return 1; 00480 } 00481 } 00482 else { 00483 /* Unknown type */ 00484 LWIP_ASSERT("bad pbuf type", 0); 00485 return 1; 00486 } 00487 /* modify pbuf length fields */ 00488 p->len += header_size_increment; 00489 p->tot_len += header_size_increment; 00490 00491 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", 00492 (void *)payload, (void *)p->payload, header_size_increment)); 00493 00494 return 0; 00495 } 00496 00497 /** 00498 * Dereference a pbuf chain or queue and deallocate any no-longer-used 00499 * pbufs at the head of this chain or queue. 00500 * 00501 * Decrements the pbuf reference count. If it reaches zero, the pbuf is 00502 * deallocated. 00503 * 00504 * For a pbuf chain, this is repeated for each pbuf in the chain, 00505 * up to the first pbuf which has a non-zero reference count after 00506 * decrementing. So, when all reference counts are one, the whole 00507 * chain is free'd. 00508 * 00509 * @param p The pbuf (chain) to be dereferenced. 00510 * 00511 * @return the number of pbufs that were de-allocated 00512 * from the head of the chain. 00513 * 00514 * @note MUST NOT be called on a packet queue (Not verified to work yet). 00515 * @note the reference counter of a pbuf equals the number of pointers 00516 * that refer to the pbuf (or into the pbuf). 00517 * 00518 * @internal examples: 00519 * 00520 * Assuming existing chains a->b->c with the following reference 00521 * counts, calling pbuf_free(a) results in: 00522 * 00523 * 1->2->3 becomes ...1->3 00524 * 3->3->3 becomes 2->3->3 00525 * 1->1->2 becomes ......1 00526 * 2->1->1 becomes 1->1->1 00527 * 1->1->1 becomes ....... 00528 * 00529 */ 00530 u8_t 00531 pbuf_free(struct pbuf *p) 00532 { 00533 u16_t type; 00534 struct pbuf *q; 00535 u8_t count; 00536 00537 if (p == NULL) { 00538 LWIP_ASSERT("p != NULL", p != NULL); 00539 /* if assertions are disabled, proceed with debug output */ 00540 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 00541 ("pbuf_free(p == NULL) was called.\n")); 00542 return 0; 00543 } 00544 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); 00545 00546 PERF_START; 00547 00548 LWIP_ASSERT("pbuf_free: sane type", 00549 p->type == PBUF_RAM || p->type == PBUF_ROM || 00550 p->type == PBUF_REF || p->type == PBUF_POOL); 00551 00552 count = 0; 00553 /* de-allocate all consecutive pbufs from the head of the chain that 00554 * obtain a zero reference count after decrementing*/ 00555 while (p != NULL) { 00556 u16_t ref; 00557 SYS_ARCH_DECL_PROTECT(old_level); 00558 /* Since decrementing ref cannot be guaranteed to be a single machine operation 00559 * we must protect it. We put the new ref into a local variable to prevent 00560 * further protection. */ 00561 SYS_ARCH_PROTECT(old_level); 00562 /* all pbufs in a chain are referenced at least once */ 00563 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); 00564 /* decrease reference count (number of pointers to pbuf) */ 00565 ref = --(p->ref); 00566 SYS_ARCH_UNPROTECT(old_level); 00567 /* this pbuf is no longer referenced to? */ 00568 if (ref == 0) { 00569 /* remember next pbuf in chain for next iteration */ 00570 q = p->next; 00571 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); 00572 type = p->type; 00573 /* is this a pbuf from the pool? */ 00574 if (type == PBUF_POOL) { 00575 memp_free(MEMP_PBUF_POOL, p); 00576 /* is this a ROM or RAM referencing pbuf? */ 00577 } else if (type == PBUF_ROM || type == PBUF_REF) { 00578 memp_free(MEMP_PBUF, p); 00579 /* type == PBUF_RAM */ 00580 } else { 00581 mem_free(p); 00582 } 00583 count++; 00584 /* proceed to next pbuf */ 00585 p = q; 00586 /* p->ref > 0, this pbuf is still referenced to */ 00587 /* (and so the remaining pbufs in chain as well) */ 00588 } else { 00589 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); 00590 /* stop walking through the chain */ 00591 p = NULL; 00592 } 00593 } 00594 PERF_STOP("pbuf_free"); 00595 /* return number of de-allocated pbufs */ 00596 return count; 00597 } 00598 00599 /** 00600 * Count number of pbufs in a chain 00601 * 00602 * @param p first pbuf of chain 00603 * @return the number of pbufs in a chain 00604 */ 00605 00606 u8_t 00607 pbuf_clen(struct pbuf *p) 00608 { 00609 u8_t len; 00610 00611 len = 0; 00612 while (p != NULL) { 00613 ++len; 00614 p = p->next; 00615 } 00616 return len; 00617 } 00618 00619 /** 00620 * Increment the reference count of the pbuf. 00621 * 00622 * @param p pbuf to increase reference counter of 00623 * 00624 */ 00625 void 00626 pbuf_ref(struct pbuf *p) 00627 { 00628 SYS_ARCH_DECL_PROTECT(old_level); 00629 /* pbuf given? */ 00630 if (p != NULL) { 00631 SYS_ARCH_PROTECT(old_level); 00632 ++(p->ref); 00633 SYS_ARCH_UNPROTECT(old_level); 00634 } 00635 } 00636 00637 /** 00638 * Concatenate two pbufs (each may be a pbuf chain) and take over 00639 * the caller's reference of the tail pbuf. 00640 * 00641 * @note The caller MAY NOT reference the tail pbuf afterwards. 00642 * Use pbuf_chain() for that purpose. 00643 * 00644 * @see pbuf_chain() 00645 */ 00646 00647 void 00648 pbuf_cat(struct pbuf *h, struct pbuf *t) 00649 { 00650 struct pbuf *p; 00651 00652 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", 00653 ((h != NULL) && (t != NULL)), return;); 00654 00655 /* proceed to last pbuf of chain */ 00656 for (p = h; p->next != NULL; p = p->next) { 00657 /* add total length of second chain to all totals of first chain */ 00658 p->tot_len += t->tot_len; 00659 } 00660 /* { p is last pbuf of first h chain, p->next == NULL } */ 00661 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); 00662 LWIP_ASSERT("p->next == NULL", p->next == NULL); 00663 /* add total length of second chain to last pbuf total of first chain */ 00664 p->tot_len += t->tot_len; 00665 /* chain last pbuf of head (p) with first of tail (t) */ 00666 p->next = t; 00667 /* p->next now references t, but the caller will drop its reference to t, 00668 * so netto there is no change to the reference count of t. 00669 */ 00670 } 00671 00672 /** 00673 * Chain two pbufs (or pbuf chains) together. 00674 * 00675 * The caller MUST call pbuf_free(t) once it has stopped 00676 * using it. Use pbuf_cat() instead if you no longer use t. 00677 * 00678 * @param h head pbuf (chain) 00679 * @param t tail pbuf (chain) 00680 * @note The pbufs MUST belong to the same packet. 00681 * @note MAY NOT be called on a packet queue. 00682 * 00683 * The ->tot_len fields of all pbufs of the head chain are adjusted. 00684 * The ->next field of the last pbuf of the head chain is adjusted. 00685 * The ->ref field of the first pbuf of the tail chain is adjusted. 00686 * 00687 */ 00688 void 00689 pbuf_chain(struct pbuf *h, struct pbuf *t) 00690 { 00691 pbuf_cat(h, t); 00692 /* t is now referenced by h */ 00693 pbuf_ref(t); 00694 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); 00695 } 00696 00697 /** 00698 * Dechains the first pbuf from its succeeding pbufs in the chain. 00699 * 00700 * Makes p->tot_len field equal to p->len. 00701 * @param p pbuf to dechain 00702 * @return remainder of the pbuf chain, or NULL if it was de-allocated. 00703 * @note May not be called on a packet queue. 00704 */ 00705 struct pbuf * 00706 pbuf_dechain(struct pbuf *p) 00707 { 00708 struct pbuf *q; 00709 u8_t tail_gone = 1; 00710 /* tail */ 00711 q = p->next; 00712 /* pbuf has successor in chain? */ 00713 if (q != NULL) { 00714 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00715 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); 00716 /* enforce invariant if assertion is disabled */ 00717 q->tot_len = p->tot_len - p->len; 00718 /* decouple pbuf from remainder */ 00719 p->next = NULL; 00720 /* total length of pbuf p is its own length only */ 00721 p->tot_len = p->len; 00722 /* q is no longer referenced by p, free it */ 00723 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); 00724 tail_gone = pbuf_free(q); 00725 if (tail_gone > 0) { 00726 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, 00727 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); 00728 } 00729 /* return remaining tail or NULL if deallocated */ 00730 } 00731 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ 00732 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); 00733 return ((tail_gone > 0) ? NULL : q); 00734 } 00735 00736 /** 00737 * 00738 * Create PBUF_RAM copies of pbufs. 00739 * 00740 * Used to queue packets on behalf of the lwIP stack, such as 00741 * ARP based queueing. 00742 * 00743 * @note You MUST explicitly use p = pbuf_take(p); 00744 * 00745 * @note Only one packet is copied, no packet queue! 00746 * 00747 * @param p_to pbuf destination of the copy 00748 * @param p_from pbuf source of the copy 00749 * 00750 * @return ERR_OK if pbuf was copied 00751 * ERR_ARG if one of the pbufs is NULL or p_to is not big 00752 * enough to hold p_from 00753 */ 00754 err_t 00755 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) 00756 { 00757 u16_t offset_to=0, offset_from=0, len; 00758 00759 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", 00760 (void*)p_to, (void*)p_from)); 00761 00762 /* is the target big enough to hold the source? */ 00763 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && 00764 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); 00765 00766 /* iterate through pbuf chain */ 00767 do 00768 { 00769 LWIP_ASSERT("p_to != NULL", p_to != NULL); 00770 /* copy one part of the original chain */ 00771 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { 00772 /* complete current p_from fits into current p_to */ 00773 len = p_from->len - offset_from; 00774 } else { 00775 /* current p_from does not fit into current p_to */ 00776 len = p_to->len - offset_to; 00777 } 00778 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); 00779 offset_to += len; 00780 offset_from += len; 00781 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); 00782 if (offset_to == p_to->len) { 00783 /* on to next p_to (if any) */ 00784 offset_to = 0; 00785 p_to = p_to->next; 00786 } 00787 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); 00788 if (offset_from >= p_from->len) { 00789 /* on to next p_from (if any) */ 00790 offset_from = 0; 00791 p_from = p_from->next; 00792 } 00793 00794 if((p_from != NULL) && (p_from->len == p_from->tot_len)) { 00795 /* don't copy more than one packet! */ 00796 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00797 (p_from->next == NULL), return ERR_VAL;); 00798 } 00799 if((p_to != NULL) && (p_to->len == p_to->tot_len)) { 00800 /* don't copy more than one packet! */ 00801 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", 00802 (p_to->next == NULL), return ERR_VAL;); 00803 } 00804 } while (p_from); 00805 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); 00806 return ERR_OK; 00807 } 00808 00809 /** 00810 * Copy (part of) the contents of a packet buffer 00811 * to an application supplied buffer. 00812 * 00813 * @param buf the pbuf from which to copy data 00814 * @param dataptr the application supplied buffer 00815 * @param len length of data to copy (dataptr must be big enough). No more 00816 * than buf->tot_len will be copied, irrespective of len 00817 * @param offset offset into the packet buffer from where to begin copying len bytes 00818 * @return the number of bytes copied, or 0 on failure 00819 */ 00820 u16_t 00821 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) 00822 { 00823 struct pbuf *p; 00824 u16_t left; 00825 u16_t buf_copy_len; 00826 u16_t copied_total = 0; 00827 00828 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); 00829 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); 00830 00831 left = 0; 00832 00833 if((buf == NULL) || (dataptr == NULL)) { 00834 return 0; 00835 } 00836 00837 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00838 for(p = buf; len != 0 && p != NULL; p = p->next) { 00839 if ((offset != 0) && (offset >= p->len)) { 00840 /* don't copy from this buffer -> on to the next */ 00841 offset -= p->len; 00842 } else { 00843 /* copy from this buffer. maybe only partially. */ 00844 buf_copy_len = p->len - offset; 00845 if (buf_copy_len > len) 00846 buf_copy_len = len; 00847 /* copy the necessary parts of the buffer */ 00848 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); 00849 copied_total += buf_copy_len; 00850 left += buf_copy_len; 00851 len -= buf_copy_len; 00852 offset = 0; 00853 } 00854 } 00855 return copied_total; 00856 } 00857 00858 /** 00859 * Copy application supplied data into a pbuf. 00860 * This function can only be used to copy the equivalent of buf->tot_len data. 00861 * 00862 * @param buf pbuf to fill with data 00863 * @param dataptr application supplied data buffer 00864 * @param len length of the application supplied data buffer 00865 * 00866 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough 00867 */ 00868 err_t 00869 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) 00870 { 00871 struct pbuf *p; 00872 u16_t buf_copy_len; 00873 u16_t total_copy_len = len; 00874 u16_t copied_total = 0; 00875 00876 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); 00877 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); 00878 00879 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { 00880 return ERR_ARG; 00881 } 00882 00883 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 00884 for(p = buf; total_copy_len != 0; p = p->next) { 00885 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); 00886 buf_copy_len = total_copy_len; 00887 if (buf_copy_len > p->len) { 00888 /* this pbuf cannot hold all remaining data */ 00889 buf_copy_len = p->len; 00890 } 00891 /* copy the necessary parts of the buffer */ 00892 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); 00893 total_copy_len -= buf_copy_len; 00894 copied_total += buf_copy_len; 00895 } 00896 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); 00897 return ERR_OK; 00898 } 00899 00900 /** 00901 * Creates a single pbuf out of a queue of pbufs. 00902 * 00903 * @remark: The source pbuf 'p' is not freed by this function because that can 00904 * be illegal in some places! 00905 * 00906 * @param p the source pbuf 00907 * @param layer pbuf_layer of the new pbuf 00908 * 00909 * @return a new, single pbuf (p->next is NULL) 00910 * or the old pbuf if allocation fails 00911 */ 00912 struct pbuf* 00913 pbuf_coalesce(struct pbuf *p, pbuf_layer layer) 00914 { 00915 struct pbuf *q; 00916 err_t err; 00917 if (p->next == NULL) { 00918 return p; 00919 } 00920 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); 00921 if (q == NULL) { 00922 /* @todo: what do we do now? */ 00923 return p; 00924 } 00925 err = pbuf_copy(q, p); 00926 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); 00927 pbuf_free(p); 00928 return q; 00929 }
Generated on Tue Jul 12 2022 21:10:26 by
![doxygen](doxygen.png)