Warning, cross-references for /kernel/lwip/core/pbuf.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 #include "lwip/opt.h"
0065
0066 #include "lwip/stats.h"
0067 #include "lwip/def.h"
0068 #include "lwip/mem.h"
0069 #include "lwip/memp.h"
0070 #include "lwip/pbuf.h"
0071 #include "lwip/sys.h"
0072 #include "arch/perf.h"
0073 #if TCP_QUEUE_OOSEQ
0074 #include "lwip/tcp.h"
0075 #endif
0076
0077 #include <string.h>
0078
0079 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
0080
0081
0082 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
0083
0084 #if !TCP_QUEUE_OOSEQ || NO_SYS
0085 #define PBUF_POOL_IS_EMPTY()
0086 #else
0087
0088 #ifndef PBUF_POOL_FREE_OOSEQ
0089 #define PBUF_POOL_FREE_OOSEQ 1
0090 #endif
0091
0092 #if PBUF_POOL_FREE_OOSEQ
0093 #include "lwip/tcpip.h"
0094 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
0095 static u8_t pbuf_free_ooseq_queued;
0096
0097
0098
0099
0100
0101
0102
0103
0104 static void
0105 pbuf_free_ooseq(void* arg)
0106 {
0107 struct tcp_pcb* pcb;
0108 SYS_ARCH_DECL_PROTECT(old_level);
0109 LWIP_UNUSED_ARG(arg);
0110
0111 SYS_ARCH_PROTECT(old_level);
0112 pbuf_free_ooseq_queued = 0;
0113 SYS_ARCH_UNPROTECT(old_level);
0114
0115 for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
0116 if (NULL != pcb->ooseq) {
0117
0118 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
0119 tcp_segs_free(pcb->ooseq);
0120 pcb->ooseq = NULL;
0121 return;
0122 }
0123 }
0124 }
0125
0126
0127 static void
0128 pbuf_pool_is_empty(void)
0129 {
0130 u8_t queued;
0131 SYS_ARCH_DECL_PROTECT(old_level);
0132
0133 SYS_ARCH_PROTECT(old_level);
0134 queued = pbuf_free_ooseq_queued;
0135 pbuf_free_ooseq_queued = 1;
0136 SYS_ARCH_UNPROTECT(old_level);
0137
0138 if(!queued) {
0139
0140 if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
0141 SYS_ARCH_PROTECT(old_level);
0142 pbuf_free_ooseq_queued = 0;
0143 SYS_ARCH_UNPROTECT(old_level);
0144 }
0145 }
0146 }
0147 #endif
0148 #endif
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 struct pbuf *
0182 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
0183 {
0184 struct pbuf *p, *q, *r;
0185 u16_t offset;
0186 s32_t rem_len;
0187 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
0188
0189
0190 offset = 0;
0191 switch (layer) {
0192 case PBUF_TRANSPORT:
0193
0194 offset += PBUF_TRANSPORT_HLEN;
0195
0196 case PBUF_IP:
0197
0198 offset += PBUF_IP_HLEN;
0199
0200 case PBUF_LINK:
0201
0202 offset += PBUF_LINK_HLEN;
0203 break;
0204 case PBUF_RAW:
0205 break;
0206 default:
0207 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
0208 return NULL;
0209 }
0210
0211 switch (type) {
0212 case PBUF_POOL:
0213
0214 p = memp_malloc(MEMP_PBUF_POOL);
0215 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
0216 if (p == NULL) {
0217 PBUF_POOL_IS_EMPTY();
0218 return NULL;
0219 }
0220 p->type = type;
0221 p->next = NULL;
0222
0223
0224 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
0225 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
0226 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
0227
0228 p->tot_len = length;
0229
0230 p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
0231 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
0232 ((u8_t*)p->payload + p->len <=
0233 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
0234 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
0235 (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
0236
0237 p->ref = 1;
0238
0239
0240
0241
0242 r = p;
0243
0244 rem_len = length - p->len;
0245
0246 while (rem_len > 0) {
0247 q = memp_malloc(MEMP_PBUF_POOL);
0248 if (q == NULL) {
0249 PBUF_POOL_IS_EMPTY();
0250
0251 pbuf_free(p);
0252
0253 return NULL;
0254 }
0255 q->type = type;
0256 q->flags = 0;
0257 q->next = NULL;
0258
0259 r->next = q;
0260
0261 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
0262 q->tot_len = (u16_t)rem_len;
0263
0264 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
0265 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
0266 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
0267 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
0268 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
0269 ((u8_t*)p->payload + p->len <=
0270 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
0271 q->ref = 1;
0272
0273 rem_len -= q->len;
0274
0275 r = q;
0276 }
0277
0278
0279
0280 break;
0281 case PBUF_RAM:
0282
0283 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
0284 if (p == NULL) {
0285 return NULL;
0286 }
0287
0288 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
0289 p->len = p->tot_len = length;
0290 p->next = NULL;
0291 p->type = type;
0292
0293 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
0294 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
0295 break;
0296
0297 case PBUF_ROM:
0298
0299 case PBUF_REF:
0300
0301 p = memp_malloc(MEMP_PBUF);
0302 if (p == NULL) {
0303 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
0304 ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
0305 (type == PBUF_ROM) ? "ROM" : "REF"));
0306 return NULL;
0307 }
0308
0309 p->payload = NULL;
0310 p->len = p->tot_len = length;
0311 p->next = NULL;
0312 p->type = type;
0313 break;
0314 default:
0315 LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
0316 return NULL;
0317 }
0318
0319 p->ref = 1;
0320
0321 p->flags = 0;
0322 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
0323 return p;
0324 }
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 void
0343 pbuf_realloc(struct pbuf *p, u16_t new_len)
0344 {
0345 struct pbuf *q;
0346 u16_t rem_len;
0347 s32_t grow;
0348
0349 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
0350 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
0351 p->type == PBUF_ROM ||
0352 p->type == PBUF_RAM ||
0353 p->type == PBUF_REF);
0354
0355
0356 if (new_len >= p->tot_len) {
0357
0358 return;
0359 }
0360
0361
0362
0363 grow = new_len - p->tot_len;
0364
0365
0366 rem_len = new_len;
0367 q = p;
0368
0369 while (rem_len > q->len) {
0370
0371 rem_len -= q->len;
0372
0373 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
0374 q->tot_len += (u16_t)grow;
0375
0376 q = q->next;
0377 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
0378 }
0379
0380
0381
0382
0383
0384 if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
0385
0386 q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
0387 LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
0388 }
0389
0390 q->len = rem_len;
0391 q->tot_len = q->len;
0392
0393
0394 if (q->next != NULL) {
0395
0396 pbuf_free(q->next);
0397 }
0398
0399 q->next = NULL;
0400
0401 }
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 u8_t
0424 pbuf_header(struct pbuf *p, s16_t header_size_increment)
0425 {
0426 u16_t type;
0427 void *payload;
0428 u16_t increment_magnitude;
0429
0430 LWIP_ASSERT("p != NULL", p != NULL);
0431 if ((header_size_increment == 0) || (p == NULL))
0432 return 0;
0433
0434 if (header_size_increment < 0){
0435 increment_magnitude = -header_size_increment;
0436
0437 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
0438 } else {
0439 increment_magnitude = header_size_increment;
0440 #if 0
0441
0442
0443
0444 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
0445 p->type == PBUF_RAM || p->type == PBUF_POOL);
0446
0447 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
0448 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
0449 #endif
0450 }
0451
0452 type = p->type;
0453
0454 payload = p->payload;
0455
0456
0457 if (type == PBUF_RAM || type == PBUF_POOL) {
0458
0459 p->payload = (u8_t *)p->payload - header_size_increment;
0460
0461 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
0462 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
0463 ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
0464 (void *)p->payload, (void *)(p + 1)));
0465
0466 p->payload = payload;
0467
0468 return 1;
0469 }
0470
0471 } else if (type == PBUF_REF || type == PBUF_ROM) {
0472
0473 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
0474
0475 p->payload = (u8_t *)p->payload - header_size_increment;
0476 } else {
0477
0478
0479 return 1;
0480 }
0481 }
0482 else {
0483
0484 LWIP_ASSERT("bad pbuf type", 0);
0485 return 1;
0486 }
0487
0488 p->len += header_size_increment;
0489 p->tot_len += header_size_increment;
0490
0491 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
0492 (void *)payload, (void *)p->payload, header_size_increment));
0493
0494 return 0;
0495 }
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530 u8_t
0531 pbuf_free(struct pbuf *p)
0532 {
0533 u16_t type;
0534 struct pbuf *q;
0535 u8_t count;
0536
0537 if (p == NULL) {
0538 LWIP_ASSERT("p != NULL", p != NULL);
0539
0540 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
0541 ("pbuf_free(p == NULL) was called.\n"));
0542 return 0;
0543 }
0544 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
0545
0546 PERF_START;
0547
0548 LWIP_ASSERT("pbuf_free: sane type",
0549 p->type == PBUF_RAM || p->type == PBUF_ROM ||
0550 p->type == PBUF_REF || p->type == PBUF_POOL);
0551
0552 count = 0;
0553
0554
0555 while (p != NULL) {
0556 u16_t ref;
0557 SYS_ARCH_DECL_PROTECT(old_level);
0558
0559
0560
0561 SYS_ARCH_PROTECT(old_level);
0562
0563 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
0564
0565 ref = --(p->ref);
0566 SYS_ARCH_UNPROTECT(old_level);
0567
0568 if (ref == 0) {
0569
0570 q = p->next;
0571 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
0572 type = p->type;
0573
0574 if (type == PBUF_POOL) {
0575 memp_free(MEMP_PBUF_POOL, p);
0576
0577 } else if (type == PBUF_ROM || type == PBUF_REF) {
0578 memp_free(MEMP_PBUF, p);
0579
0580 } else {
0581 mem_free(p);
0582 }
0583 count++;
0584
0585 p = q;
0586
0587
0588 } else {
0589 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
0590
0591 p = NULL;
0592 }
0593 }
0594 PERF_STOP("pbuf_free");
0595
0596 return count;
0597 }
0598
0599
0600
0601
0602
0603
0604
0605
0606 u8_t
0607 pbuf_clen(struct pbuf *p)
0608 {
0609 u8_t len;
0610
0611 len = 0;
0612 while (p != NULL) {
0613 ++len;
0614 p = p->next;
0615 }
0616 return len;
0617 }
0618
0619
0620
0621
0622
0623
0624
0625 void
0626 pbuf_ref(struct pbuf *p)
0627 {
0628 SYS_ARCH_DECL_PROTECT(old_level);
0629
0630 if (p != NULL) {
0631 SYS_ARCH_PROTECT(old_level);
0632 ++(p->ref);
0633 SYS_ARCH_UNPROTECT(old_level);
0634 }
0635 }
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647 void
0648 pbuf_cat(struct pbuf *h, struct pbuf *t)
0649 {
0650 struct pbuf *p;
0651
0652 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
0653 ((h != NULL) && (t != NULL)), return;);
0654
0655
0656 for (p = h; p->next != NULL; p = p->next) {
0657
0658 p->tot_len += t->tot_len;
0659 }
0660
0661 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
0662 LWIP_ASSERT("p->next == NULL", p->next == NULL);
0663
0664 p->tot_len += t->tot_len;
0665
0666 p->next = t;
0667
0668
0669
0670 }
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688 void
0689 pbuf_chain(struct pbuf *h, struct pbuf *t)
0690 {
0691 pbuf_cat(h, t);
0692
0693 pbuf_ref(t);
0694 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
0695 }
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705 struct pbuf *
0706 pbuf_dechain(struct pbuf *p)
0707 {
0708 struct pbuf *q;
0709 u8_t tail_gone = 1;
0710
0711 q = p->next;
0712
0713 if (q != NULL) {
0714
0715 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
0716
0717 q->tot_len = p->tot_len - p->len;
0718
0719 p->next = NULL;
0720
0721 p->tot_len = p->len;
0722
0723 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
0724 tail_gone = pbuf_free(q);
0725 if (tail_gone > 0) {
0726 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
0727 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
0728 }
0729
0730 }
0731
0732 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
0733 return ((tail_gone > 0) ? NULL : q);
0734 }
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754 err_t
0755 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
0756 {
0757 u16_t offset_to=0, offset_from=0, len;
0758
0759 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
0760 (void*)p_to, (void*)p_from));
0761
0762
0763 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
0764 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
0765
0766
0767 do
0768 {
0769 LWIP_ASSERT("p_to != NULL", p_to != NULL);
0770
0771 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
0772
0773 len = p_from->len - offset_from;
0774 } else {
0775
0776 len = p_to->len - offset_to;
0777 }
0778 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
0779 offset_to += len;
0780 offset_from += len;
0781 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
0782 if (offset_to == p_to->len) {
0783
0784 offset_to = 0;
0785 p_to = p_to->next;
0786 }
0787 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
0788 if (offset_from >= p_from->len) {
0789
0790 offset_from = 0;
0791 p_from = p_from->next;
0792 }
0793
0794 if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
0795
0796 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
0797 (p_from->next == NULL), return ERR_VAL;);
0798 }
0799 if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
0800
0801 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
0802 (p_to->next == NULL), return ERR_VAL;);
0803 }
0804 } while (p_from);
0805 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
0806 return ERR_OK;
0807 }
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820 u16_t
0821 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
0822 {
0823 struct pbuf *p;
0824 u16_t left;
0825 u16_t buf_copy_len;
0826 u16_t copied_total = 0;
0827
0828 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
0829 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
0830
0831 left = 0;
0832
0833 if((buf == NULL) || (dataptr == NULL)) {
0834 return 0;
0835 }
0836
0837
0838 for(p = buf; len != 0 && p != NULL; p = p->next) {
0839 if ((offset != 0) && (offset >= p->len)) {
0840
0841 offset -= p->len;
0842 } else {
0843
0844 buf_copy_len = p->len - offset;
0845 if (buf_copy_len > len)
0846 buf_copy_len = len;
0847
0848 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
0849 copied_total += buf_copy_len;
0850 left += buf_copy_len;
0851 len -= buf_copy_len;
0852 offset = 0;
0853 }
0854 }
0855 return copied_total;
0856 }
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868 err_t
0869 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
0870 {
0871 struct pbuf *p;
0872 u16_t buf_copy_len;
0873 u16_t total_copy_len = len;
0874 u16_t copied_total = 0;
0875
0876 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
0877 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
0878
0879 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
0880 return ERR_ARG;
0881 }
0882
0883
0884 for(p = buf; total_copy_len != 0; p = p->next) {
0885 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
0886 buf_copy_len = total_copy_len;
0887 if (buf_copy_len > p->len) {
0888
0889 buf_copy_len = p->len;
0890 }
0891
0892 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
0893 total_copy_len -= buf_copy_len;
0894 copied_total += buf_copy_len;
0895 }
0896 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
0897 return ERR_OK;
0898 }
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912 struct pbuf*
0913 pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
0914 {
0915 struct pbuf *q;
0916 err_t err;
0917 if (p->next == NULL) {
0918 return p;
0919 }
0920 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
0921 if (q == NULL) {
0922
0923 return p;
0924 }
0925 err = pbuf_copy(q, p);
0926 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
0927 pbuf_free(p);
0928 return q;
0929 }