ReactOS 0.4.15-dev-7788-g1ad9096
pbuf.c
Go to the documentation of this file.
1
32/*
33 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without modification,
37 * are permitted provided that the following conditions are met:
38 *
39 * 1. Redistributions of source code must retain the above copyright notice,
40 * this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright notice,
42 * this list of conditions and the following disclaimer in the documentation
43 * and/or other materials provided with the distribution.
44 * 3. The name of the author may not be used to endorse or promote products
45 * derived from this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
50 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
52 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
55 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
56 * OF SUCH DAMAGE.
57 *
58 * This file is part of the lwIP TCP/IP stack.
59 *
60 * Author: Adam Dunkels <adam@sics.se>
61 *
62 */
63
64#include "lwip/opt.h"
65
66#include "lwip/stats.h"
67#include "lwip/def.h"
68#include "lwip/mem.h"
69#include "lwip/memp.h"
70#include "lwip/pbuf.h"
71#include "lwip/sys.h"
72#include "arch/perf.h"
73#if LWIP_TCP && TCP_QUEUE_OOSEQ
74#include "lwip/tcp_impl.h"
75#endif
76#if LWIP_CHECKSUM_ON_COPY
77#include "lwip/inet_chksum.h"
78#endif
79
80#include <string.h>
81
82#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
83/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
84 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
85#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
86
87#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ
88#define PBUF_POOL_IS_EMPTY()
89#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
90
91#if !NO_SYS
92#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
93#include "lwip/tcpip.h"
94#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \
95 if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
96 SYS_ARCH_PROTECT(old_level); \
97 pbuf_free_ooseq_pending = 0; \
98 SYS_ARCH_UNPROTECT(old_level); \
99 } } while(0)
100#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
101#endif /* !NO_SYS */
102
103volatile u8_t pbuf_free_ooseq_pending;
104#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
105
114#if !NO_SYS
115static
116#endif /* !NO_SYS */
117void
118pbuf_free_ooseq(void)
119{
120 struct tcp_pcb* pcb;
121 SYS_ARCH_DECL_PROTECT(old_level);
122
123 SYS_ARCH_PROTECT(old_level);
124 pbuf_free_ooseq_pending = 0;
125 SYS_ARCH_UNPROTECT(old_level);
126
127 for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
128 if (NULL != pcb->ooseq) {
130 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
131 tcp_segs_free(pcb->ooseq);
132 pcb->ooseq = NULL;
133 return;
134 }
135 }
136}
137
138#if !NO_SYS
142static void
143pbuf_free_ooseq_callback(void *arg)
144{
146 pbuf_free_ooseq();
147}
148#endif /* !NO_SYS */
149
151static void
152pbuf_pool_is_empty(void)
153{
154#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
155 SYS_ARCH_DECL_PROTECT(old_level);
156 SYS_ARCH_PROTECT(old_level);
157 pbuf_free_ooseq_pending = 1;
158 SYS_ARCH_UNPROTECT(old_level);
159#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
160 u8_t queued;
161 SYS_ARCH_DECL_PROTECT(old_level);
162 SYS_ARCH_PROTECT(old_level);
163 queued = pbuf_free_ooseq_pending;
164 pbuf_free_ooseq_pending = 1;
165 SYS_ARCH_UNPROTECT(old_level);
166
167 if(!queued) {
168 /* queue a call to pbuf_free_ooseq if not already queued */
169 PBUF_POOL_FREE_OOSEQ_QUEUE_CALL();
170 }
171#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
172}
173#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
174
206struct pbuf *
208{
209 struct pbuf *p, *q, *r;
211 s32_t rem_len; /* remaining length */
212 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
213
214 /* determine header offset */
215 switch (layer) {
216 case PBUF_TRANSPORT:
217 /* add room for transport (often TCP) layer header */
219 break;
220 case PBUF_IP:
221 /* add room for IP layer header */
223 break;
224 case PBUF_LINK:
225 /* add room for link layer header */
227 break;
228 case PBUF_RAW:
229 offset = 0;
230 break;
231 default:
232 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
233 return NULL;
234 }
235
236 switch (type) {
237 case PBUF_POOL:
238 /* allocate head of pbuf chain into p */
239 p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
240 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
241 if (p == NULL) {
243 return NULL;
244 }
245 p->type = type;
246 p->next = NULL;
247
248 /* make the payload pointer point 'offset' bytes into pbuf data memory */
249 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
250 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
251 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
252 /* the total length of the pbuf chain is the requested size */
253 p->tot_len = length;
254 /* set the length of the first pbuf in the chain */
256 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
257 ((u8_t*)p->payload + p->len <=
259 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
261 /* set reference count (needed here in case we fail) */
262 p->ref = 1;
263
264 /* now allocate the tail of the pbuf chain */
265
266 /* remember first pbuf for linkage in next iteration */
267 r = p;
268 /* remaining length to be allocated */
269 rem_len = length - p->len;
270 /* any remaining pbufs to be allocated? */
271 while (rem_len > 0) {
272 q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
273 if (q == NULL) {
275 /* free chain so far allocated */
276 pbuf_free(p);
277 /* bail out unsuccesfully */
278 return NULL;
279 }
280 q->type = type;
281 q->flags = 0;
282 q->next = NULL;
283 /* make previous pbuf point to this pbuf */
284 r->next = q;
285 /* set total length of this pbuf and next in chain */
286 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
287 q->tot_len = (u16_t)rem_len;
288 /* this pbuf length is pool size, unless smaller sized tail */
289 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
290 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
291 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
292 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
293 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
294 ((u8_t*)p->payload + p->len <=
296 q->ref = 1;
297 /* calculate remaining length to be allocated */
298 rem_len -= q->len;
299 /* remember this pbuf for linkage in next iteration */
300 r = q;
301 }
302 /* end of chain */
303 /*r->next = NULL;*/
304
305 break;
306 case PBUF_RAM:
307 /* If pbuf is to be allocated in RAM, allocate memory for it. */
309 if (p == NULL) {
310 return NULL;
311 }
312 /* Set up internal structure of the pbuf. */
313 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
314 p->len = p->tot_len = length;
315 p->next = NULL;
316 p->type = type;
317
318 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
319 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
320 break;
321 /* pbuf references existing (non-volatile static constant) ROM payload? */
322 case PBUF_ROM:
323 /* pbuf references existing (externally allocated) RAM payload? */
324 case PBUF_REF:
325 /* only allocate memory for the pbuf structure */
326 p = (struct pbuf *)memp_malloc(MEMP_PBUF);
327 if (p == NULL) {
329 ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
330 (type == PBUF_ROM) ? "ROM" : "REF"));
331 return NULL;
332 }
333 /* caller must set this field properly, afterwards */
334 p->payload = NULL;
335 p->len = p->tot_len = length;
336 p->next = NULL;
337 p->type = type;
338 break;
339 default:
340 LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
341 return NULL;
342 }
343 /* set reference count */
344 p->ref = 1;
345 /* set flags */
346 p->flags = 0;
347 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
348 return p;
349}
350
351#if LWIP_SUPPORT_CUSTOM_PBUF
366struct pbuf*
367pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
368 void *payload_mem, u16_t payload_mem_len)
369{
371 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
372
373 /* determine header offset */
374 switch (l) {
375 case PBUF_TRANSPORT:
376 /* add room for transport (often TCP) layer header */
378 break;
379 case PBUF_IP:
380 /* add room for IP layer header */
382 break;
383 case PBUF_LINK:
384 /* add room for link layer header */
386 break;
387 case PBUF_RAW:
388 offset = 0;
389 break;
390 default:
391 LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
392 return NULL;
393 }
394
395 if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) {
396 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
397 return NULL;
398 }
399
400 p->pbuf.next = NULL;
401 if (payload_mem != NULL) {
402 p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset);
403 } else {
404 p->pbuf.payload = NULL;
405 }
406 p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
407 p->pbuf.len = p->pbuf.tot_len = length;
408 p->pbuf.type = type;
409 p->pbuf.ref = 1;
410 return &p->pbuf;
411}
412#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
413
429void
430pbuf_realloc(struct pbuf *p, u16_t new_len)
431{
432 struct pbuf *q;
433 u16_t rem_len; /* remaining length */
434 s32_t grow;
435
436 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
437 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
438 p->type == PBUF_ROM ||
439 p->type == PBUF_RAM ||
440 p->type == PBUF_REF);
441
442 /* desired length larger than current length? */
443 if (new_len >= p->tot_len) {
444 /* enlarging not yet supported */
445 return;
446 }
447
448 /* the pbuf chain grows by (new_len - p->tot_len) bytes
449 * (which may be negative in case of shrinking) */
450 grow = new_len - p->tot_len;
451
452 /* first, step over any pbufs that should remain in the chain */
453 rem_len = new_len;
454 q = p;
455 /* should this pbuf be kept? */
456 while (rem_len > q->len) {
457 /* decrease remaining length by pbuf length */
458 rem_len -= q->len;
459 /* decrease total length indicator */
460 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
461 q->tot_len += (u16_t)grow;
462 /* proceed to next pbuf in chain */
463 q = q->next;
464 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
465 }
466 /* we have now reached the new last pbuf (in q) */
467 /* rem_len == desired length for pbuf q */
468
469 /* shrink allocated memory for PBUF_RAM */
470 /* (other types merely adjust their length fields */
471 if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
472 /* reallocate and adjust the length of the pbuf that will be split */
473 q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
474 LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
475 }
476 /* adjust length fields for new last pbuf */
477 q->len = rem_len;
478 q->tot_len = q->len;
479
480 /* any remaining pbufs in chain? */
481 if (q->next != NULL) {
482 /* free remaining pbufs in chain */
483 pbuf_free(q->next);
484 }
485 /* q is last packet in chain */
486 q->next = NULL;
487
488}
489
510u8_t
511pbuf_header(struct pbuf *p, s16_t header_size_increment)
512{
513 u16_t type;
514 void *payload;
515 u16_t increment_magnitude;
516
517 LWIP_ASSERT("p != NULL", p != NULL);
518 if ((header_size_increment == 0) || (p == NULL)) {
519 return 0;
520 }
521
522 if (header_size_increment < 0){
523 increment_magnitude = -header_size_increment;
524 /* Check that we aren't going to move off the end of the pbuf */
525 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
526 } else {
527 increment_magnitude = header_size_increment;
528#if 0
529 /* Can't assert these as some callers speculatively call
530 pbuf_header() to see if it's OK. Will return 1 below instead. */
531 /* Check that we've got the correct type of pbuf to work with */
532 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
533 p->type == PBUF_RAM || p->type == PBUF_POOL);
534 /* Check that we aren't going to move off the beginning of the pbuf */
535 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
536 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
537#endif
538 }
539
540 type = p->type;
541 /* remember current payload pointer */
542 payload = p->payload;
543
544 /* pbuf types containing payloads? */
545 if (type == PBUF_RAM || type == PBUF_POOL) {
546 /* set new payload pointer */
547 p->payload = (u8_t *)p->payload - header_size_increment;
548 /* boundary check fails? */
549 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
551 ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
552 (void *)p->payload, (void *)(p + 1)));
553 /* restore old payload pointer */
554 p->payload = payload;
555 /* bail out unsuccesfully */
556 return 1;
557 }
558 /* pbuf types refering to external payloads? */
559 } else if (type == PBUF_REF || type == PBUF_ROM) {
560 /* hide a header in the payload? */
561 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
562 /* increase payload pointer */
563 p->payload = (u8_t *)p->payload - header_size_increment;
564 } else {
565 /* cannot expand payload to front (yet!)
566 * bail out unsuccesfully */
567 return 1;
568 }
569 } else {
570 /* Unknown type */
571 LWIP_ASSERT("bad pbuf type", 0);
572 return 1;
573 }
574 /* modify pbuf length fields */
575 p->len += header_size_increment;
576 p->tot_len += header_size_increment;
577
578 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
579 (void *)payload, (void *)p->payload, header_size_increment));
580
581 return 0;
582}
583
617u8_t
619{
620 u16_t type;
621 struct pbuf *q;
622 u8_t count;
623
624 if (p == NULL) {
625 LWIP_ASSERT("p != NULL", p != NULL);
626 /* if assertions are disabled, proceed with debug output */
628 ("pbuf_free(p == NULL) was called.\n"));
629 return 0;
630 }
631 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
632
634
635 LWIP_ASSERT("pbuf_free: sane type",
636 p->type == PBUF_RAM || p->type == PBUF_ROM ||
637 p->type == PBUF_REF || p->type == PBUF_POOL);
638
639 count = 0;
640 /* de-allocate all consecutive pbufs from the head of the chain that
641 * obtain a zero reference count after decrementing*/
642 while (p != NULL) {
643 u16_t ref;
644 SYS_ARCH_DECL_PROTECT(old_level);
645 /* Since decrementing ref cannot be guaranteed to be a single machine operation
646 * we must protect it. We put the new ref into a local variable to prevent
647 * further protection. */
648 SYS_ARCH_PROTECT(old_level);
649 /* all pbufs in a chain are referenced at least once */
650 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
651 /* decrease reference count (number of pointers to pbuf) */
652 ref = --(p->ref);
653 SYS_ARCH_UNPROTECT(old_level);
654 /* this pbuf is no longer referenced to? */
655 if (ref == 0) {
656 /* remember next pbuf in chain for next iteration */
657 q = p->next;
658 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
659 type = p->type;
660#if LWIP_SUPPORT_CUSTOM_PBUF
661 /* is this a custom pbuf? */
662 if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
663 struct pbuf_custom *pc = (struct pbuf_custom*)p;
664 LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
665 pc->custom_free_function(p);
666 } else
667#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
668 {
669 /* is this a pbuf from the pool? */
670 if (type == PBUF_POOL) {
671 memp_free(MEMP_PBUF_POOL, p);
672 /* is this a ROM or RAM referencing pbuf? */
673 } else if (type == PBUF_ROM || type == PBUF_REF) {
674 memp_free(MEMP_PBUF, p);
675 /* type == PBUF_RAM */
676 } else {
677 mem_free(p);
678 }
679 }
680 count++;
681 /* proceed to next pbuf */
682 p = q;
683 /* p->ref > 0, this pbuf is still referenced to */
684 /* (and so the remaining pbufs in chain as well) */
685 } else {
686 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
687 /* stop walking through the chain */
688 p = NULL;
689 }
690 }
691 PERF_STOP("pbuf_free");
692 /* return number of de-allocated pbufs */
693 return count;
694}
695
703u8_t
705{
706 u8_t len;
707
708 len = 0;
709 while (p != NULL) {
710 ++len;
711 p = p->next;
712 }
713 return len;
714}
715
722void
724{
725 SYS_ARCH_DECL_PROTECT(old_level);
726 /* pbuf given? */
727 if (p != NULL) {
728 SYS_ARCH_PROTECT(old_level);
729 ++(p->ref);
730 SYS_ARCH_UNPROTECT(old_level);
731 }
732}
733
744void
745pbuf_cat(struct pbuf *h, struct pbuf *t)
746{
747 struct pbuf *p;
748
749 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
750 ((h != NULL) && (t != NULL)), return;);
751
752 /* proceed to last pbuf of chain */
753 for (p = h; p->next != NULL; p = p->next) {
754 /* add total length of second chain to all totals of first chain */
755 p->tot_len += t->tot_len;
756 }
757 /* { p is last pbuf of first h chain, p->next == NULL } */
758 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
759 LWIP_ASSERT("p->next == NULL", p->next == NULL);
760 /* add total length of second chain to last pbuf total of first chain */
761 p->tot_len += t->tot_len;
762 /* chain last pbuf of head (p) with first of tail (t) */
763 p->next = t;
764 /* p->next now references t, but the caller will drop its reference to t,
765 * so netto there is no change to the reference count of t.
766 */
767}
768
785void
786pbuf_chain(struct pbuf *h, struct pbuf *t)
787{
788 pbuf_cat(h, t);
789 /* t is now referenced by h */
790 pbuf_ref(t);
791 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
792}
793
802struct pbuf *
804{
805 struct pbuf *q;
806 u8_t tail_gone = 1;
807 /* tail */
808 q = p->next;
809 /* pbuf has successor in chain? */
810 if (q != NULL) {
811 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
812 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
813 /* enforce invariant if assertion is disabled */
814 q->tot_len = p->tot_len - p->len;
815 /* decouple pbuf from remainder */
816 p->next = NULL;
817 /* total length of pbuf p is its own length only */
818 p->tot_len = p->len;
819 /* q is no longer referenced by p, free it */
820 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
821 tail_gone = pbuf_free(q);
822 if (tail_gone > 0) {
824 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
825 }
826 /* return remaining tail or NULL if deallocated */
827 }
828 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
829 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
830 return ((tail_gone > 0) ? NULL : q);
831}
832
851err_t
852pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
853{
854 u16_t offset_to=0, offset_from=0, len;
855
856 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
857 (void*)p_to, (void*)p_from));
858
859 /* is the target big enough to hold the source? */
860 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
861 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
862
863 /* iterate through pbuf chain */
864 do
865 {
866 /* copy one part of the original chain */
867 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
868 /* complete current p_from fits into current p_to */
869 len = p_from->len - offset_from;
870 } else {
871 /* current p_from does not fit into current p_to */
872 len = p_to->len - offset_to;
873 }
874 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
875 offset_to += len;
876 offset_from += len;
877 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
878 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
879 if (offset_from >= p_from->len) {
880 /* on to next p_from (if any) */
881 offset_from = 0;
882 p_from = p_from->next;
883 }
884 if (offset_to == p_to->len) {
885 /* on to next p_to (if any) */
886 offset_to = 0;
887 p_to = p_to->next;
888 LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;);
889 }
890
891 if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
892 /* don't copy more than one packet! */
893 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
894 (p_from->next == NULL), return ERR_VAL;);
895 }
896 if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
897 /* don't copy more than one packet! */
898 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
899 (p_to->next == NULL), return ERR_VAL;);
900 }
901 } while (p_from);
902 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
903 return ERR_OK;
904}
905
917u16_t
919{
920 struct pbuf *p;
921 u16_t left;
922 u16_t buf_copy_len;
923 u16_t copied_total = 0;
924
925 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
926 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
927
928 left = 0;
929
930 if((buf == NULL) || (dataptr == NULL)) {
931 return 0;
932 }
933
934 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
935 for(p = buf; len != 0 && p != NULL; p = p->next) {
936 if ((offset != 0) && (offset >= p->len)) {
937 /* don't copy from this buffer -> on to the next */
938 offset -= p->len;
939 } else {
940 /* copy from this buffer. maybe only partially. */
941 buf_copy_len = p->len - offset;
942 if (buf_copy_len > len)
943 buf_copy_len = len;
944 /* copy the necessary parts of the buffer */
945 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
946 copied_total += buf_copy_len;
947 left += buf_copy_len;
948 len -= buf_copy_len;
949 offset = 0;
950 }
951 }
952 return copied_total;
953}
954
965err_t
966pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
967{
968 struct pbuf *p;
969 u16_t buf_copy_len;
970 u16_t total_copy_len = len;
971 u16_t copied_total = 0;
972
973 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
974 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
975
976 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
977 return ERR_ARG;
978 }
979
980 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
981 for(p = buf; total_copy_len != 0; p = p->next) {
982 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
983 buf_copy_len = total_copy_len;
984 if (buf_copy_len > p->len) {
985 /* this pbuf cannot hold all remaining data */
986 buf_copy_len = p->len;
987 }
988 /* copy the necessary parts of the buffer */
989 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
990 total_copy_len -= buf_copy_len;
991 copied_total += buf_copy_len;
992 }
993 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
994 return ERR_OK;
995}
996
1009struct pbuf*
1011{
1012 struct pbuf *q;
1013 err_t err;
1014 if (p->next == NULL) {
1015 return p;
1016 }
1017 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
1018 if (q == NULL) {
1019 /* @todo: what do we do now? */
1020 return p;
1021 }
1022 err = pbuf_copy(q, p);
1023 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
1024 pbuf_free(p);
1025 return q;
1026}
1027
1028#if LWIP_CHECKSUM_ON_COPY
1041err_t
1042pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
1044{
1045 u32_t acc;
1046 u16_t copy_chksum;
1047 char *dst_ptr;
1048 LWIP_ASSERT("p != NULL", p != NULL);
1049 LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
1050 LWIP_ASSERT("chksum != NULL", chksum != NULL);
1051 LWIP_ASSERT("len != 0", len != 0);
1052
1053 if ((start_offset >= p->len) || (start_offset + len > p->len)) {
1054 return ERR_ARG;
1055 }
1056
1057 dst_ptr = ((char*)p->payload) + start_offset;
1058 copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
1059 if ((start_offset & 1) != 0) {
1060 copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
1061 }
1062 acc = *chksum;
1063 acc += copy_chksum;
1064 *chksum = FOLD_U32T(acc);
1065 return ERR_OK;
1066}
1067#endif /* LWIP_CHECKSUM_ON_COPY */
1068
1076u8_t
1078{
1079 u16_t copy_from = offset;
1080 struct pbuf* q = p;
1081
1082 /* get the correct pbuf */
1083 while ((q != NULL) && (q->len <= copy_from)) {
1084 copy_from -= q->len;
1085 q = q->next;
1086 }
1087 /* return requested data if pbuf is OK */
1088 if ((q != NULL) && (q->len > copy_from)) {
1089 return ((u8_t*)q->payload)[copy_from];
1090 }
1091 return 0;
1092}
1093
1103u16_t
1104pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
1105{
1106 u16_t start = offset;
1107 struct pbuf* q = p;
1108
1109 /* get the correct pbuf */
1110 while ((q != NULL) && (q->len <= start)) {
1111 start -= q->len;
1112 q = q->next;
1113 }
1114 /* return requested data if pbuf is OK */
1115 if ((q != NULL) && (q->len > start)) {
1116 u16_t i;
1117 for(i = 0; i < n; i++) {
1118 u8_t a = pbuf_get_at(q, start + i);
1119 u8_t b = ((u8_t*)s2)[i];
1120 if (a != b) {
1121 return i+1;
1122 }
1123 }
1124 return 0;
1125 }
1126 return 0xffff;
1127}
1128
1139u16_t
1140pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
1141{
1142 u16_t i;
1143 u16_t max = p->tot_len - mem_len;
1144 if (p->tot_len >= mem_len + start_offset) {
1145 for(i = start_offset; i <= max; ) {
1146 u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
1147 if (plus == 0) {
1148 return i;
1149 } else {
1150 i += plus;
1151 }
1152 }
1153 }
1154 return 0xFFFF;
1155}
1156
1167u16_t
1168pbuf_strstr(struct pbuf* p, const char* substr)
1169{
1170 size_t substr_len;
1171 if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
1172 return 0xFFFF;
1173 }
1174 substr_len = strlen(substr);
1175 if (substr_len >= 0xFFFF) {
1176 return 0xFFFF;
1177 }
1178 return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
1179}
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:73
r l[0]
Definition: byte_order.h:168
#define MEM_ALIGNMENT
Definition: d3d9_helpers.c:15
#define LWIP_MIN(x, y)
Definition: def.h:44
#define mem_free(ptr, bsize)
Definition: types.h:124
#define NULL
Definition: types.h:112
#define SYS_ARCH_UNPROTECT(lev)
Definition: cc.h:56
signed short s16_t
Definition: cc.h:29
#define SYS_ARCH_PROTECT(lev)
Definition: cc.h:55
#define mem_trim(_m_, _s_)
Definition: cc.h:20
#define SYS_ARCH_DECL_PROTECT(lev)
Definition: cc.h:54
#define U16_F
Definition: cc.h:36
ULONG_PTR mem_ptr_t
Definition: cc.h:33
signed long s32_t
Definition: cc.h:30
#define S16_F
Definition: cc.h:37
unsigned long u32_t
Definition: cc.h:25
unsigned char u8_t
Definition: cc.h:23
unsigned short u16_t
Definition: cc.h:24
void * mem_malloc(mem_size_t size)
Definition: mem.c:494
#define LWIP_DBG_LEVEL_SERIOUS
Definition: debug.h:47
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:95
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:46
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:74
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:66
#define LWIP_DBG_TRACE
Definition: debug.h:57
#define ERR_ARG
Definition: err.h:70
#define ERR_OK
Definition: err.h:52
#define ERR_VAL
Definition: err.h:58
s8_t err_t
Definition: err.h:47
#define LWIP_MEM_ALIGN(addr)
Definition: mem.h:116
#define LWIP_MEM_ALIGN_SIZE(size)
Definition: mem.h:101
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble t
Definition: gl.h:2047
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLdouble n
Definition: glext.h:7729
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLint left
Definition: glext.h:7726
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLuint GLint GLint layer
Definition: glext.h:7007
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLintptr offset
Definition: glext.h:5920
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define PBUF_DEBUG
Definition: lwipopts.h:125
static u32_t chksum(void *dataptr, u16_t len)
Definition: inet6.c:55
#define SWAP_BYTES_IN_WORD(w)
Definition: inet_chksum.h:47
#define FOLD_U32T(u)
Definition: inet_chksum.h:53
static substr_t substr(const WCHAR *str, size_t len)
Definition: internet.h:203
int const JOCTET * dataptr
Definition: jpeglib.h:1031
if(dx< 0)
Definition: linetemp.h:194
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
void * memp_malloc(memp_t type)
Definition: memp.c:390
void memp_free(memp_t type, void *mem)
Definition: memp.c:435
struct S2 s2
#define PBUF_LINK_HLEN
Definition: opt.h:1095
struct pbuf * pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
Definition: pbuf.c:1010
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:511
#define PBUF_POOL_BUFSIZE_ALIGNED
Definition: pbuf.c:85
void pbuf_realloc(struct pbuf *p, u16_t new_len)
Definition: pbuf.c:430
void pbuf_ref(struct pbuf *p)
Definition: pbuf.c:723
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:745
void pbuf_chain(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:786
#define SIZEOF_STRUCT_PBUF
Definition: pbuf.c:82
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:207
u8_t pbuf_clen(struct pbuf *p)
Definition: pbuf.c:704
u16_t pbuf_memcmp(struct pbuf *p, u16_t offset, const void *s2, u16_t n)
Definition: pbuf.c:1104
u8_t pbuf_get_at(struct pbuf *p, u16_t offset)
Definition: pbuf.c:1077
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:918
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:618
u16_t pbuf_memfind(struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset)
Definition: pbuf.c:1140
struct pbuf * pbuf_dechain(struct pbuf *p)
Definition: pbuf.c:803
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
Definition: pbuf.c:966
u16_t pbuf_strstr(struct pbuf *p, const char *substr)
Definition: pbuf.c:1168
#define PBUF_POOL_IS_EMPTY()
Definition: pbuf.c:88
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
Definition: pbuf.c:852
#define PBUF_IP_HLEN
Definition: pbuf.h:48
pbuf_type
Definition: pbuf.h:57
@ PBUF_ROM
Definition: pbuf.h:59
@ PBUF_RAM
Definition: pbuf.h:58
@ PBUF_REF
Definition: pbuf.h:60
@ PBUF_POOL
Definition: pbuf.h:61
pbuf_layer
Definition: pbuf.h:50
@ PBUF_RAW
Definition: pbuf.h:54
@ PBUF_TRANSPORT
Definition: pbuf.h:51
@ PBUF_LINK
Definition: pbuf.h:53
@ PBUF_IP
Definition: pbuf.h:52
#define PBUF_FLAG_IS_CUSTOM
Definition: pbuf.h:69
#define PBUF_TRANSPORT_HLEN
Definition: pbuf.h:47
#define PERF_START
Definition: perf.h:3
#define PERF_STOP
Definition: perf.h:4
#define err(...)
struct define * next
Definition: compiler.c:65
Definition: mem.c:156
Definition: pbuf.h:79
u16_t ref
Definition: pbuf.h:109
u16_t tot_len
Definition: pbuf.h:93
struct pbuf * next
Definition: pbuf.h:81
u16_t len
Definition: pbuf.h:96
void * payload
Definition: pbuf.h:84
Definition: send.c:48
#define max(a, b)
Definition: svc.c:63