00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
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.h"
00075 #endif
00076
00077 #include <string.h>
00078
00079 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
00080
00081
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
00087
00088 #ifndef PBUF_POOL_FREE_OOSEQ
00089 #define PBUF_POOL_FREE_OOSEQ 1
00090 #endif
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
00098
00099
00100
00101
00102
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
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
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
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
00148 #endif
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
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;
00187 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
00188
00189
00190 offset = 0;
00191 switch (layer) {
00192 case PBUF_TRANSPORT:
00193
00194 offset += PBUF_TRANSPORT_HLEN;
00195
00196 case PBUF_IP:
00197
00198 offset += PBUF_IP_HLEN;
00199
00200 case PBUF_LINK:
00201
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
00214 p = 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
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
00228 p->tot_len = length;
00229
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
00237 p->ref = 1;
00238
00239
00240
00241
00242 r = p;
00243
00244 rem_len = length - p->len;
00245
00246 while (rem_len > 0) {
00247 q = memp_malloc(MEMP_PBUF_POOL);
00248 if (q == NULL) {
00249 PBUF_POOL_IS_EMPTY();
00250
00251 pbuf_free(p);
00252
00253 return NULL;
00254 }
00255 q->type = type;
00256 q->flags = 0;
00257 q->next = NULL;
00258
00259 r->next = q;
00260
00261 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
00262 q->tot_len = (u16_t)rem_len;
00263
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
00273 rem_len -= q->len;
00274
00275 r = q;
00276 }
00277
00278
00279
00280 break;
00281 case PBUF_RAM:
00282
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
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
00297 case PBUF_ROM:
00298
00299 case PBUF_REF:
00300
00301 p = 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
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
00319 p->ref = 1;
00320
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
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 void
00343 pbuf_realloc(struct pbuf *p, u16_t new_len)
00344 {
00345 struct pbuf *q;
00346 u16_t rem_len;
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
00356 if (new_len >= p->tot_len) {
00357
00358 return;
00359 }
00360
00361
00362
00363 grow = new_len - p->tot_len;
00364
00365
00366 rem_len = new_len;
00367 q = p;
00368
00369 while (rem_len > q->len) {
00370
00371 rem_len -= q->len;
00372
00373 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
00374 q->tot_len += (u16_t)grow;
00375
00376 q = q->next;
00377 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
00378 }
00379
00380
00381
00382
00383
00384 if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
00385
00386 q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
00387 LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
00388 }
00389
00390 q->len = rem_len;
00391 q->tot_len = q->len;
00392
00393
00394 if (q->next != NULL) {
00395
00396 pbuf_free(q->next);
00397 }
00398
00399 q->next = NULL;
00400
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
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
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
00442
00443
00444 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
00445 p->type == PBUF_RAM || p->type == PBUF_POOL);
00446
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
00454 payload = p->payload;
00455
00456
00457 if (type == PBUF_RAM || type == PBUF_POOL) {
00458
00459 p->payload = (u8_t *)p->payload - header_size_increment;
00460
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
00466 p->payload = payload;
00467
00468 return 1;
00469 }
00470
00471 } else if (type == PBUF_REF || type == PBUF_ROM) {
00472
00473 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
00474
00475 p->payload = (u8_t *)p->payload - header_size_increment;
00476 } else {
00477
00478
00479 return 1;
00480 }
00481 }
00482 else {
00483
00484 LWIP_ASSERT("bad pbuf type", 0);
00485 return 1;
00486 }
00487
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
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
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
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
00554
00555 while (p != NULL) {
00556 u16_t ref;
00557 SYS_ARCH_DECL_PROTECT(old_level);
00558
00559
00560
00561 SYS_ARCH_PROTECT(old_level);
00562
00563 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
00564
00565 ref = --(p->ref);
00566 SYS_ARCH_UNPROTECT(old_level);
00567
00568 if (ref == 0) {
00569
00570 q = p->next;
00571 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
00572 type = p->type;
00573
00574 if (type == PBUF_POOL) {
00575 memp_free(MEMP_PBUF_POOL, p);
00576
00577 } else if (type == PBUF_ROM || type == PBUF_REF) {
00578 memp_free(MEMP_PBUF, p);
00579
00580 } else {
00581 mem_free(p);
00582 }
00583 count++;
00584
00585 p = q;
00586
00587
00588 } else {
00589 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
00590
00591 p = NULL;
00592 }
00593 }
00594
00595
00596 return count;
00597 }
00598
00599
00600
00601
00602
00603
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
00621
00622
00623
00624
00625 void
00626 pbuf_ref(struct pbuf *p)
00627 {
00628 SYS_ARCH_DECL_PROTECT(old_level);
00629
00630 if (p != NULL) {
00631 SYS_ARCH_PROTECT(old_level);
00632 ++(p->ref);
00633 SYS_ARCH_UNPROTECT(old_level);
00634 }
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
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
00656 for (p = h; p->next != NULL; p = p->next) {
00657
00658 p->tot_len += t->tot_len;
00659 }
00660
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
00664 p->tot_len += t->tot_len;
00665
00666 p->next = t;
00667
00668
00669
00670 }
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 void
00689 pbuf_chain(struct pbuf *h, struct pbuf *t)
00690 {
00691 pbuf_cat(h, t);
00692
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
00699
00700
00701
00702
00703
00704
00705 struct pbuf *
00706 pbuf_dechain(struct pbuf *p)
00707 {
00708 struct pbuf *q;
00709 u8_t tail_gone = 1;
00710
00711 q = p->next;
00712
00713 if (q != NULL) {
00714
00715 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
00716
00717 q->tot_len = p->tot_len - p->len;
00718
00719 p->next = NULL;
00720
00721 p->tot_len = p->len;
00722
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
00730 }
00731
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
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
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
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
00767 do
00768 {
00769 LWIP_ASSERT("p_to != NULL", p_to != NULL);
00770
00771 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
00772
00773 len = p_from->len - offset_from;
00774 } else {
00775
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
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
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
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
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
00811
00812
00813
00814
00815
00816
00817
00818
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
00838 for(p = buf; len != 0 && p != NULL; p = p->next) {
00839 if ((offset != 0) && (offset >= p->len)) {
00840
00841 offset -= p->len;
00842 } else {
00843
00844 buf_copy_len = p->len - offset;
00845 if (buf_copy_len > len)
00846 buf_copy_len = len;
00847
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
00860
00861
00862
00863
00864
00865
00866
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
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
00889 buf_copy_len = p->len;
00890 }
00891
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
00902
00903
00904
00905
00906
00907
00908
00909
00910
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
00923 return p;
00924 }
00925 err = pbuf_copy(q, p);
00926 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
00927 err = err;
00928 pbuf_free(p);
00929 return q;
00930 }