00001
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 #include "lwip/opt.h"
00054 #include "lwip/stats.h"
00055 #include "lwip/def.h"
00056 #include "lwip/mem.h"
00057 #include "lwip/memp.h"
00058 #include "lwip/pbuf.h"
00059 #include "lwip/sys.h"
00060
00061
00062 static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];
00063
00064 #if !SYS_LIGHTWEIGHT_PROT
00065 static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
00066 static sys_sem_t pbuf_pool_free_sem;
00067 #endif
00068
00069 static struct pbuf *pbuf_pool = NULL;
00070 static struct pbuf *pbuf_pool_alloc_cache = NULL;
00071 static struct pbuf *pbuf_pool_free_cache = NULL;
00072
00085 void
00086 pbuf_init(void)
00087 {
00088 struct pbuf *p, *q = NULL;
00089 u16_t i;
00090
00091 pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
00092 LWIP_ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0);
00093
00094 #ifdef PBUF_STATS
00095 lwip_stats.pbuf.avail = PBUF_POOL_SIZE;
00096 #endif
00097
00098
00099 p = pbuf_pool;
00100
00101 for(i = 0; i < PBUF_POOL_SIZE; ++i) {
00102 p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
00103 p->len = p->tot_len = PBUF_POOL_BUFSIZE;
00104 p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
00105 q = p;
00106 p = p->next;
00107 }
00108
00109
00110
00111 q->next = NULL;
00112
00113 #if !SYS_LIGHTWEIGHT_PROT
00114 pbuf_pool_alloc_lock = 0;
00115 pbuf_pool_free_lock = 0;
00116 pbuf_pool_free_sem = sys_sem_new(1);
00117 #endif
00118 }
00119
00123 static struct pbuf *
00124 pbuf_pool_alloc(void)
00125 {
00126 struct pbuf *p = NULL;
00127
00128 unsigned int state;
00129 sys_stop_interrupts(&state);
00130
00131 if(pbuf_pool_alloc_cache) {
00132 p = pbuf_pool_alloc_cache;
00133 if(p) {
00134 pbuf_pool_alloc_cache = p->next;
00135 }
00136 } else {
00137 #if !SYS_LIGHTWEIGHT_PROT
00138
00139
00140 if(pbuf_pool_free_lock) {
00141 #ifdef PBUF_STATS
00142 ++lwip_stats.pbuf.alloc_locked;
00143 #endif
00144 return NULL;
00145 }
00146 pbuf_pool_alloc_lock = 1;
00147 if(!pbuf_pool_free_lock) {
00148 #endif
00149 p = pbuf_pool;
00150 if(p) {
00151 pbuf_pool = p->next;
00152 }
00153 #if !SYS_LIGHTWEIGHT_PROT
00154 #ifdef PBUF_STATS
00155 } else {
00156 ++lwip_stats.pbuf.alloc_locked;
00157 #endif
00158 }
00159 pbuf_pool_alloc_lock = 0;
00160 #endif
00161 }
00162
00163 #ifdef PBUF_STATS
00164 if(p != NULL) {
00165 ++lwip_stats.pbuf.used;
00166 if(lwip_stats.pbuf.used > lwip_stats.pbuf.max) {
00167 lwip_stats.pbuf.max = lwip_stats.pbuf.used;
00168 }
00169 }
00170 #endif
00171
00172 sys_allow_interrupts(&state);
00173 return p;
00174 }
00175
00179 static void
00180 pbuf_pool_free(struct pbuf *p)
00181 {
00182 struct pbuf *q;
00183 unsigned int state;
00184 sys_stop_interrupts(&state);
00185
00186 #ifdef PBUF_STATS
00187 for(q = p; q != NULL; q = q->next) {
00188 --lwip_stats.pbuf.used;
00189 }
00190 #endif
00191
00192 if(pbuf_pool_alloc_cache == NULL) {
00193 pbuf_pool_alloc_cache = p;
00194 } else {
00195 for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next);
00196 q->next = p;
00197 }
00198 sys_allow_interrupts(&state);
00199 }
00200
00230 struct pbuf *
00231 pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)
00232 {
00233 struct pbuf *p, *q, *r;
00234 u16_t offset;
00235 s32_t rem_len;
00236
00237
00238 offset = 0;
00239 switch (l) {
00240 case PBUF_TRANSPORT:
00241
00242 offset += PBUF_TRANSPORT_HLEN;
00243
00244 case PBUF_IP:
00245
00246 offset += PBUF_IP_HLEN;
00247
00248 case PBUF_LINK:
00249
00250 offset += PBUF_LINK_HLEN;
00251 break;
00252 case PBUF_RAW:
00253 break;
00254 default:
00255 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
00256 return NULL;
00257 }
00258
00259 switch (flag) {
00260 case PBUF_POOL:
00261
00262 p = pbuf_pool_alloc();
00263 if (p == NULL) {
00264 #ifdef PBUF_STATS
00265 ++lwip_stats.pbuf.err;
00266 #endif
00267 return NULL;
00268 }
00269 p->next = NULL;
00270
00271
00272 p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
00273 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
00274 ((u32_t)p->payload % MEM_ALIGNMENT) == 0);
00275
00276 p->tot_len = length;
00277
00278 p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;
00279
00280 p->flags = PBUF_FLAG_POOL;
00281
00282
00283
00284
00285 r = p;
00286
00287 rem_len = length - p->len;
00288
00289 while(rem_len > 0) {
00290 q = pbuf_pool_alloc();
00291 if (q == NULL) {
00292 DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
00293 #ifdef PBUF_STATS
00294 ++lwip_stats.pbuf.err;
00295 #endif
00296
00297 pbuf_pool_free(p);
00298 return NULL;
00299 }
00300
00301
00302 r->next = q;
00303
00304 q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
00305 q->flags = PBUF_FLAG_POOL;
00306 q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
00307 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
00308 ((u32_t)q->payload % MEM_ALIGNMENT) == 0);
00309 q->ref = 1;
00310
00311 rem_len -= q->len;
00312
00313 r = q;
00314 }
00315
00316 r->next = NULL;
00317
00318 break;
00319 case PBUF_RAM:
00320
00321 p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset));
00322 if (p == NULL) {
00323 return NULL;
00324 }
00325
00326 p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
00327 p->len = p->tot_len = length;
00328 p->next = NULL;
00329 p->flags = PBUF_FLAG_RAM;
00330
00331 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
00332 ((u32_t)p->payload % MEM_ALIGNMENT) == 0);
00333 break;
00334
00335 case PBUF_ROM:
00336
00337 case PBUF_REF:
00338
00339 p = memp_mallocp(MEMP_PBUF);
00340 if (p == NULL) {
00341 DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_REF.\n"));
00342 return NULL;
00343 }
00344
00345 p->payload = NULL;
00346 p->len = p->tot_len = length;
00347 p->next = NULL;
00348 p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);
00349 break;
00350 default:
00351 LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
00352 return NULL;
00353 }
00354 p->ref = 1;
00355 return p;
00356 }
00357
00364 void
00365 pbuf_refresh(void)
00366 {
00367 struct pbuf *p;
00368 unsigned int state;
00369 sys_stop_interrupts(&state);
00370
00371 #if !SYS_LIGHTWEIGHT_PROT
00372 sys_sem_wait(pbuf_pool_free_sem);
00373 #endif
00374
00375 if(pbuf_pool_free_cache != NULL) {
00376 #if !SYS_LIGHTWEIGHT_PROT
00377 pbuf_pool_free_lock = 1;
00378 if(!pbuf_pool_alloc_lock) {
00379 #endif
00380 if(pbuf_pool == NULL) {
00381 pbuf_pool = pbuf_pool_free_cache;
00382 } else {
00383 for(p = pbuf_pool; p->next != NULL; p = p->next);
00384 p->next = pbuf_pool_free_cache;
00385 }
00386 pbuf_pool_free_cache = NULL;
00387 #if !SYS_LIGHTWEIGHT_PROT
00388 #ifdef PBUF_STATS
00389 } else {
00390 ++lwip_stats.pbuf.refresh_locked;
00391 #endif
00392 }
00393
00394 pbuf_pool_free_lock = 0;
00395 #endif
00396 }
00397 sys_allow_interrupts(&state);
00398 #if !SYS_LIGHTWEIGHT_PROT
00399 sys_sem_signal(pbuf_pool_free_sem);
00400 #endif
00401 }
00402
00403 #ifdef PBUF_STATS
00404 #define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)
00405 #else
00406 #define DEC_PBUF_STATS
00407 #endif
00408
00409 #define PBUF_POOL_FAST_FREE(p) do { \
00410 p->next = pbuf_pool_free_cache; \
00411 pbuf_pool_free_cache = p; \
00412 DEC_PBUF_STATS; \
00413 } while (0)
00414
00415 #if SYS_LIGHTWEIGHT_PROT
00416 #define PBUF_POOL_FREE(p) do { \
00417 unsigned int state; \
00418 sys_stop_interrupts(&state); \
00419 PBUF_POOL_FAST_FREE(p); \
00420 sys_allow_interrupts(&state) \
00421 } while(0)
00422 #else
00423 #define PBUF_POOL_FREE(p) do { \
00424 sys_sem_wait(pbuf_pool_free_sem); \
00425 PBUF_POOL_FAST_FREE(p); \
00426 sys_sem_signal(pbuf_pool_free_sem); \
00427 } while(0)
00428 #endif
00429
00444 void
00445 pbuf_realloc(struct pbuf *p, u16_t new_len)
00446 {
00447 struct pbuf *q;
00448 u16_t rem_len;
00449 s16_t grow;
00450
00451 LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
00452 p->flags == PBUF_FLAG_ROM ||
00453 p->flags == PBUF_FLAG_RAM ||
00454 p->flags == PBUF_FLAG_REF);
00455
00456
00457 if (new_len >= p->tot_len) {
00458
00459 return;
00460 }
00461
00462
00463
00464 grow = new_len - p->tot_len;
00465
00466
00467 rem_len = new_len;
00468 q = p;
00469
00470 while (rem_len > q->len) {
00471
00472 rem_len -= q->len;
00473
00474 q->tot_len += grow;
00475
00476 q = q->next;
00477 }
00478
00479
00480
00481
00482
00483 if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {
00484
00485 mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
00486 }
00487
00488 q->len = rem_len;
00489 q->tot_len = q->len;
00490
00491
00492 if (q->next != NULL) {
00493
00494 pbuf_free(q->next);
00495 }
00496
00497 q->next = NULL;
00498
00499 pbuf_refresh();
00500 }
00501
00519 u8_t
00520 pbuf_header(struct pbuf *p, s16_t header_size)
00521 {
00522 void *payload;
00523
00524
00525 payload = p->payload;
00526
00527
00528 if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) {
00529
00530 p->payload = (u8_t *)p->payload - header_size;
00531
00532 if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
00533 DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n",
00534 (u8_t *)p->payload,
00535 (u8_t *)p + sizeof(struct pbuf)) );\
00536
00537 p->payload = payload;
00538
00539 return 1;
00540 }
00541
00542 } else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) {
00543
00544 if ((header_size < 0) && (header_size - p->len <= 0)) {
00545
00546 p->payload = (u8_t *)p->payload - header_size;
00547 } else {
00548
00549
00550 return 1;
00551 }
00552 }
00553 DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size) );
00554
00555 p->len += header_size;
00556 p->tot_len += header_size;
00557
00558 return 0;
00559 }
00560
00588 u8_t
00589 pbuf_free(struct pbuf *p)
00590 {
00591 struct pbuf *q;
00592 u8_t count;
00593 unsigned int state;
00594
00595 if (p == NULL) {
00596 DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
00597 return 0;
00598 }
00599
00600
00601
00602 LWIP_ASSERT("pbuf_free: sane flags",
00603 p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||
00604 p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);
00605
00606 count = 0;
00607
00608
00609
00610 sys_stop_interrupts(&state);
00611
00612
00613 while (p != NULL) {
00614
00615 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
00616 p->ref--;
00617
00618 if (p->ref == 0) {
00619
00620 q = p->next;
00621
00622 if (p->flags == PBUF_FLAG_POOL) {
00623 p->len = p->tot_len = PBUF_POOL_BUFSIZE;
00624 p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
00625 PBUF_POOL_FREE(p);
00626
00627 } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
00628 memp_freep(MEMP_PBUF, p);
00629
00630 } else {
00631 mem_free(p);
00632 }
00633 count++;
00634
00635 p = q;
00636
00637
00638 } else {
00639
00640 p = NULL;
00641 }
00642 }
00643 sys_allow_interrupts(&state);
00644 pbuf_refresh();
00645
00646
00647 return count;
00648 }
00649
00657 u8_t
00658 pbuf_clen(struct pbuf *p)
00659 {
00660 u8_t len;
00661
00662 len = 0;
00663 while (p != NULL) {
00664 ++len;
00665 p = p->next;
00666 }
00667 return len;
00668 }
00676 void
00677 pbuf_ref(struct pbuf *p)
00678 {
00679 unsigned int state;
00680
00681 if (p != NULL) {
00682 sys_stop_interrupts(&state);
00683 ++(p->ref);
00684 sys_allow_interrupts(&state);
00685 }
00686 }
00687
00695 void
00696 pbuf_ref_chain(struct pbuf *p)
00697 {
00698 unsigned int state;
00699 sys_stop_interrupts(&state);
00700
00701 while (p != NULL) {
00702 ++p->ref;
00703 p = p->next;
00704 }
00705 sys_allow_interrupts(&state);
00706 }
00707
00708
00718 void
00719 pbuf_chain(struct pbuf *h, struct pbuf *t)
00720 {
00721 struct pbuf *p;
00722
00723 LWIP_ASSERT("h != NULL", h != NULL);
00724 LWIP_ASSERT("t != NULL", t != NULL);
00725
00726
00727 for (p = h; p->next != NULL; p = p->next) {
00728
00729 p->tot_len += t->tot_len;
00730 }
00731
00732
00733 p->tot_len += t->tot_len;
00734
00735 p->next = t;
00736
00737 pbuf_ref(t);
00738 DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t));
00739 }
00740
00748 struct pbuf *
00749 pbuf_dechain(struct pbuf *p)
00750 {
00751 struct pbuf *q;
00752 u8_t tail_gone = 1;
00753
00754 q = p->next;
00755
00756 if (q != NULL) {
00757
00758 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
00759
00760 q->tot_len = p->tot_len - p->len;
00761
00762 p->next = NULL;
00763
00764 p->tot_len = p->len;
00765
00766 DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q));
00767 tail_gone = pbuf_free(q);
00768
00769 }
00770
00771 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
00772 return (tail_gone > 0? NULL: q);
00773 }
00774
00796 struct pbuf *
00797 pbuf_take(struct pbuf *p)
00798 {
00799 struct pbuf *q , *prev, *head;
00800 LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
00801 DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));
00802
00803 prev = NULL;
00804 head = p;
00805
00806 do
00807 {
00808
00809 if (p->flags == PBUF_FLAG_REF) {
00810 DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
00811
00812
00813 if (p->len <= PBUF_POOL_BUFSIZE) {
00814 q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
00815 if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
00816 } else {
00817
00818 q = NULL;
00819 DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
00820 }
00821
00822 if (q == NULL) {
00823 q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
00824 if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
00825 }
00826
00827 if (q != NULL)
00828 {
00829
00830
00831 q->next = p->next;
00832
00833 p->next = NULL;
00834
00835 if (prev != NULL) {
00836
00837 LWIP_ASSERT("prev->next == p", prev->next == p);
00838
00839 prev->next = q;
00840
00841 } else {
00842 head = q;
00843 }
00844
00845 memcpy(q->payload, p->payload, p->len);
00846 q->tot_len = p->tot_len;
00847 q->len = p->len;
00848
00849
00850
00851
00852
00853
00854
00855 pbuf_free(p);
00856
00857 DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
00858 p = q;
00859 } else {
00860
00861 pbuf_free(head);
00862 DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
00863 return NULL;
00864 }
00865
00866 } else {
00867 DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
00868 }
00869
00870 prev = p;
00871
00872 p = p->next;
00873 } while (p);
00874 DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));
00875
00876 return head;
00877 }
00878