2 |
* @file |
* @file |
3 |
* Packet buffer management |
* Packet buffer management |
4 |
* |
* |
5 |
* Packets are represented by the pbuf data structure. It supports dynamic |
* Packets are built from the pbuf data structure. It supports dynamic |
6 |
* memory allocation for packet contents or can reference externally |
* memory allocation for packet contents or can reference externally |
7 |
* managed packet contents both in RAM and ROM. Quick allocation for |
* managed packet contents both in RAM and ROM. Quick allocation for |
8 |
* incoming packets is provided through pools with fixed sized pbufs. |
* incoming packets is provided through pools with fixed sized pbufs. |
9 |
* |
* |
10 |
* Pbufs can be chained as a singly linked list, called a pbuf chain, so |
* A packet may span over multiple pbufs, chained as a singly linked |
11 |
* that a packet may span over several pbufs. |
* list. This is called a "pbuf chain". |
12 |
* |
* |
13 |
|
* Multiple packets may be queued, also using this singly linked list. |
14 |
|
* This is called a "packet queue". So, a packet queue consists of one |
15 |
|
* or more pbuf chains, each of which consist of one or more pbufs. |
16 |
|
* |
17 |
|
* The last pbuf of a packet has a ->tot_len field that equals the |
18 |
|
* ->len field. It can be found by traversing the list. If the last |
19 |
|
* pbuf of a packet has a ->next field other than NULL, more packets |
20 |
|
* are on the queue. |
21 |
*/ |
*/ |
22 |
|
|
23 |
/* |
/* |
73 |
#endif |
#endif |
74 |
|
|
75 |
static struct pbuf *pbuf_pool = NULL; |
static struct pbuf *pbuf_pool = NULL; |
|
static struct pbuf *pbuf_pool_alloc_cache = NULL; |
|
|
static struct pbuf *pbuf_pool_free_cache = NULL; |
|
76 |
|
|
77 |
/** |
/** |
78 |
* Initializes the pbuf module. |
* Initializes the pbuf module. |
131 |
|
|
132 |
SYS_ARCH_DECL_PROTECT(old_level); |
SYS_ARCH_DECL_PROTECT(old_level); |
133 |
SYS_ARCH_PROTECT(old_level); |
SYS_ARCH_PROTECT(old_level); |
134 |
/* First, see if there are pbufs in the cache. */ |
|
|
if (pbuf_pool_alloc_cache) { |
|
|
p = pbuf_pool_alloc_cache; |
|
|
if (p) { |
|
|
pbuf_pool_alloc_cache = p->next; |
|
|
} |
|
|
} else { |
|
135 |
#if !SYS_LIGHTWEIGHT_PROT |
#if !SYS_LIGHTWEIGHT_PROT |
136 |
/* Next, check the actual pbuf pool, but if the pool is locked, we |
/* Next, check the actual pbuf pool, but if the pool is locked, we |
137 |
pretend to be out of buffers and return NULL. */ |
pretend to be out of buffers and return NULL. */ |
138 |
if (pbuf_pool_free_lock) { |
if (pbuf_pool_free_lock) { |
139 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
140 |
++lwip_stats.pbuf.alloc_locked; |
++lwip_stats.pbuf.alloc_locked; |
141 |
#endif /* PBUF_STATS */ |
#endif /* PBUF_STATS */ |
142 |
return NULL; |
return NULL; |
143 |
} |
} |
144 |
pbuf_pool_alloc_lock = 1; |
pbuf_pool_alloc_lock = 1; |
145 |
if (!pbuf_pool_free_lock) { |
if (!pbuf_pool_free_lock) { |
146 |
#endif /* SYS_LIGHTWEIGHT_PROT */ |
#endif /* SYS_LIGHTWEIGHT_PROT */ |
147 |
p = pbuf_pool; |
p = pbuf_pool; |
148 |
if (p) { |
if (p) { |
149 |
pbuf_pool = p->next; |
pbuf_pool = p->next; |
150 |
} |
} |
151 |
#if !SYS_LIGHTWEIGHT_PROT |
#if !SYS_LIGHTWEIGHT_PROT |
152 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
153 |
} else { |
} else { |
154 |
++lwip_stats.pbuf.alloc_locked; |
++lwip_stats.pbuf.alloc_locked; |
155 |
#endif /* PBUF_STATS */ |
#endif /* PBUF_STATS */ |
|
} |
|
|
pbuf_pool_alloc_lock = 0; |
|
|
#endif /* SYS_LIGHTWEIGHT_PROT */ |
|
156 |
} |
} |
157 |
|
pbuf_pool_alloc_lock = 0; |
158 |
|
#endif /* SYS_LIGHTWEIGHT_PROT */ |
159 |
|
|
160 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
161 |
if (p != NULL) { |
if (p != NULL) { |
170 |
return p; |
return p; |
171 |
} |
} |
172 |
|
|
|
/** |
|
|
* @internal only called from pbuf_alloc() |
|
|
*/ |
|
|
static void |
|
|
pbuf_pool_free(struct pbuf *p) |
|
|
{ |
|
|
struct pbuf *q; |
|
|
SYS_ARCH_DECL_PROTECT(old_level); |
|
|
SYS_ARCH_PROTECT(old_level); |
|
|
|
|
|
#ifdef PBUF_STATS |
|
|
for(q = p; q != NULL; q = q->next) { |
|
|
--lwip_stats.pbuf.used; |
|
|
} |
|
|
#endif /* PBUF_STATS */ |
|
|
|
|
|
if (pbuf_pool_alloc_cache == NULL) { |
|
|
pbuf_pool_alloc_cache = p; |
|
|
} else { |
|
|
for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next); |
|
|
q->next = p; |
|
|
} |
|
|
SYS_ARCH_UNPROTECT(old_level); |
|
|
} |
|
173 |
|
|
174 |
/** |
/** |
175 |
* Allocates a pbuf. |
* Allocates a pbuf. |
244 |
/* make the payload pointer point 'offset' bytes into pbuf data memory */ |
/* make the payload pointer point 'offset' bytes into pbuf data memory */ |
245 |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
246 |
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", |
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", |
247 |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
248 |
/* the total length of the pbuf chain is the requested size */ |
/* the total length of the pbuf chain is the requested size */ |
249 |
p->tot_len = length; |
p->tot_len = length; |
250 |
/* set the length of the first pbuf in the chain */ |
/* set the length of the first pbuf in the chain */ |
267 |
++lwip_stats.pbuf.err; |
++lwip_stats.pbuf.err; |
268 |
#endif /* PBUF_STATS */ |
#endif /* PBUF_STATS */ |
269 |
/* bail out unsuccesfully */ |
/* bail out unsuccesfully */ |
270 |
pbuf_pool_free(p); |
pbuf_free(p); |
271 |
return NULL; |
return NULL; |
272 |
} |
} |
273 |
//q->next = NULL; |
/*q->next = NULL;*/ |
274 |
/* make previous pbuf point to this pbuf */ |
/* make previous pbuf point to this pbuf */ |
275 |
r->next = q; |
r->next = q; |
276 |
/* set length of this pbuf */ |
/* set total length of this pbuf and next in chain */ |
277 |
|
q->tot_len = rem_len; |
278 |
|
/* this pbuf length is pool size, unless smaller sized tail */ |
279 |
q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len; |
q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len; |
280 |
q->flags = PBUF_FLAG_POOL; |
q->flags = PBUF_FLAG_POOL; |
281 |
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); |
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); |
282 |
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", |
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", |
283 |
((u32_t)q->payload % MEM_ALIGNMENT) == 0); |
((u32_t)q->payload % MEM_ALIGNMENT) == 0); |
284 |
q->ref = 1; |
q->ref = 1; |
285 |
/* calculate remaining length to be allocated */ |
/* calculate remaining length to be allocated */ |
286 |
rem_len -= q->len; |
rem_len -= q->len; |
304 |
p->flags = PBUF_FLAG_RAM; |
p->flags = PBUF_FLAG_RAM; |
305 |
|
|
306 |
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", |
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", |
307 |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
308 |
break; |
break; |
309 |
/* pbuf references existing (static constant) ROM payload? */ |
/* pbuf references existing (static constant) ROM payload? */ |
310 |
case PBUF_ROM: |
case PBUF_ROM: |
330 |
return p; |
return p; |
331 |
} |
} |
332 |
|
|
|
/** |
|
|
* |
|
|
* Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool |
|
|
* list (if possible). |
|
|
* |
|
|
*/ |
|
|
void |
|
|
pbuf_refresh(void) |
|
|
{ |
|
|
struct pbuf *p; |
|
|
SYS_ARCH_DECL_PROTECT(old_level); |
|
|
SYS_ARCH_PROTECT(old_level); |
|
|
|
|
|
#if !SYS_LIGHTWEIGHT_PROT |
|
|
sys_sem_wait(pbuf_pool_free_sem); |
|
|
#endif /* else SYS_LIGHTWEIGHT_PROT */ |
|
|
|
|
|
if (pbuf_pool_free_cache != NULL) { |
|
|
#if !SYS_LIGHTWEIGHT_PROT |
|
|
pbuf_pool_free_lock = 1; |
|
|
if (!pbuf_pool_alloc_lock) { |
|
|
#endif /* SYS_LIGHTWEIGHT_PROT */ |
|
|
if (pbuf_pool == NULL) { |
|
|
pbuf_pool = pbuf_pool_free_cache; |
|
|
} else { |
|
|
for(p = pbuf_pool; p->next != NULL; p = p->next); |
|
|
p->next = pbuf_pool_free_cache; |
|
|
} |
|
|
pbuf_pool_free_cache = NULL; |
|
|
#if !SYS_LIGHTWEIGHT_PROT |
|
|
#ifdef PBUF_STATS |
|
|
} else { |
|
|
++lwip_stats.pbuf.refresh_locked; |
|
|
#endif /* PBUF_STATS */ |
|
|
} |
|
|
|
|
|
pbuf_pool_free_lock = 0; |
|
|
#endif /* SYS_LIGHTWEIGHT_PROT */ |
|
|
} |
|
|
SYS_ARCH_UNPROTECT(old_level); |
|
|
#if !SYS_LIGHTWEIGHT_PROT |
|
|
sys_sem_signal(pbuf_pool_free_sem); |
|
|
#endif /* SYS_LIGHTWEIGHT_PROT */ |
|
|
} |
|
333 |
|
|
334 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
335 |
#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0) |
#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0) |
338 |
#endif /* PBUF_STATS */ |
#endif /* PBUF_STATS */ |
339 |
|
|
340 |
#define PBUF_POOL_FAST_FREE(p) do { \ |
#define PBUF_POOL_FAST_FREE(p) do { \ |
341 |
p->next = pbuf_pool_free_cache; \ |
p->next = pbuf_pool; \ |
342 |
pbuf_pool_free_cache = p; \ |
pbuf_pool = p; \ |
343 |
DEC_PBUF_STATS; \ |
DEC_PBUF_STATS; \ |
344 |
} while (0) |
} while (0) |
345 |
|
|
369 |
* resized, and any remaining pbufs will be freed. |
* resized, and any remaining pbufs will be freed. |
370 |
* |
* |
371 |
* @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. |
* @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. |
372 |
|
* @note May not be called on a packet queue. |
373 |
* |
* |
374 |
* @bug Cannot grow the size of a pbuf (chain) (yet). |
* @bug Cannot grow the size of a pbuf (chain) (yet). |
375 |
*/ |
*/ |
428 |
/* q is last packet in chain */ |
/* q is last packet in chain */ |
429 |
q->next = NULL; |
q->next = NULL; |
430 |
|
|
|
pbuf_refresh(); |
|
431 |
} |
} |
432 |
|
|
433 |
/** |
/** |
446 |
* the call will fail. A check is made that the increase in header size does |
* the call will fail. A check is made that the increase in header size does |
447 |
* not move the payload pointer in front of the start of the buffer. |
* not move the payload pointer in front of the start of the buffer. |
448 |
* @return 1 on failure, 0 on success. |
* @return 1 on failure, 0 on success. |
449 |
|
* |
450 |
|
* @note May not be called on a packet queue. |
451 |
*/ |
*/ |
452 |
u8_t |
u8_t |
453 |
pbuf_header(struct pbuf *p, s16_t header_size) |
pbuf_header(struct pbuf *p, s16_t header_size) |
506 |
* @return the number of unreferenced pbufs that were de-allocated |
* @return the number of unreferenced pbufs that were de-allocated |
507 |
* from the head of the chain. |
* from the head of the chain. |
508 |
* |
* |
509 |
|
* @note May not be called on a packet queue. |
510 |
* @note the reference counter of a pbuf equals the number of pointers |
* @note the reference counter of a pbuf equals the number of pointers |
511 |
* that refer to the pbuf (or into the pbuf). |
* that refer to the pbuf (or into the pbuf). |
512 |
* |
* |
543 |
*/ |
*/ |
544 |
SYS_ARCH_PROTECT(old_level); |
SYS_ARCH_PROTECT(old_level); |
545 |
/* de-allocate all consecutive pbufs from the head of the chain that |
/* de-allocate all consecutive pbufs from the head of the chain that |
546 |
* obtain a zero reference count */ |
* obtain a zero reference count after decrementing*/ |
547 |
while (p != NULL) { |
while (p != NULL) { |
548 |
/* all pbufs in a chain are referenced at least once */ |
/* all pbufs in a chain are referenced at least once */ |
549 |
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); |
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); |
550 |
|
/* decrease reference count (number of pointers to pbuf) */ |
551 |
p->ref--; |
p->ref--; |
552 |
/* this pbuf is no longer referenced to? */ |
/* this pbuf is no longer referenced to? */ |
553 |
if (p->ref == 0) { |
if (p->ref == 0) { |
558 |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
559 |
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); |
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); |
560 |
PBUF_POOL_FREE(p); |
PBUF_POOL_FREE(p); |
561 |
/* a RAM/ROM referencing pbuf */ |
/* a ROM or RAM referencing pbuf */ |
562 |
} else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { |
} else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { |
563 |
memp_freep(MEMP_PBUF, p); |
memp_freep(MEMP_PBUF, p); |
564 |
/* pbuf with data */ |
/* p->flags == PBUF_FLAG_RAM */ |
565 |
} else { |
} else { |
566 |
mem_free(p); |
mem_free(p); |
567 |
} |
} |
569 |
/* proceed to next pbuf */ |
/* proceed to next pbuf */ |
570 |
p = q; |
p = q; |
571 |
/* p->ref > 0, this pbuf is still referenced to */ |
/* p->ref > 0, this pbuf is still referenced to */ |
572 |
/* (so the remaining pbufs in chain as well) */ |
/* (and so the remaining pbufs in chain as well) */ |
573 |
} else { |
} else { |
574 |
/* stop walking through chain */ |
/* stop walking through chain */ |
575 |
p = NULL; |
p = NULL; |
576 |
} |
} |
577 |
} |
} |
578 |
SYS_ARCH_UNPROTECT(old_level); |
SYS_ARCH_UNPROTECT(old_level); |
|
pbuf_refresh(); |
|
579 |
PERF_STOP("pbuf_free"); |
PERF_STOP("pbuf_free"); |
580 |
/* return number of de-allocated pbufs */ |
/* return number of de-allocated pbufs */ |
581 |
return count; |
return count; |
600 |
} |
} |
601 |
return len; |
return len; |
602 |
} |
} |
603 |
|
|
604 |
/** |
/** |
605 |
* |
* |
606 |
* Increment the reference count of the pbuf. |
* Increment the reference count of the pbuf. |
622 |
|
|
623 |
/** |
/** |
624 |
* |
* |
625 |
* Increment the reference count of all pbufs in a chain. |
* Chain two pbufs (or pbuf chains) together. They must belong to the same packet. |
|
* |
|
|
* @param p first pbuf of chain |
|
|
* |
|
|
*/ |
|
|
void |
|
|
pbuf_ref_chain(struct pbuf *p) |
|
|
{ |
|
|
SYS_ARCH_DECL_PROTECT(old_level); |
|
|
SYS_ARCH_PROTECT(old_level); |
|
|
|
|
|
while (p != NULL) { |
|
|
++p->ref; |
|
|
p = p->next; |
|
|
} |
|
|
SYS_ARCH_UNPROTECT(old_level); |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
* |
|
|
* Link two pbufs (or chains) together. |
|
626 |
* |
* |
627 |
* @param h head pbuf (chain) |
* @param h head pbuf (chain) |
628 |
* @param t tail pbuf (chain) |
* @param t tail pbuf (chain) |
629 |
|
* @note May not be called on a packet queue. |
630 |
|
* |
631 |
|
* The ->tot_len fields of all pbufs of the head chain are adjusted. |
632 |
|
* The ->next field of the last pbuf of the head chain is adjusted. |
633 |
|
* The ->ref field of the first pbuf of the tail chain is adjusted. |
634 |
* |
* |
|
* The ->tot_len field of the first pbuf (h) is adjusted. |
|
635 |
*/ |
*/ |
636 |
void |
void |
637 |
pbuf_chain(struct pbuf *h, struct pbuf *t) |
pbuf_chain(struct pbuf *h, struct pbuf *t) |
640 |
|
|
641 |
LWIP_ASSERT("h != NULL", h != NULL); |
LWIP_ASSERT("h != NULL", h != NULL); |
642 |
LWIP_ASSERT("t != NULL", t != NULL); |
LWIP_ASSERT("t != NULL", t != NULL); |
643 |
|
|
644 |
|
if (t == NULL) |
645 |
|
return; |
646 |
|
|
647 |
/* proceed to last pbuf of chain */ |
/* proceed to last pbuf of chain */ |
648 |
for (p = h; p->next != NULL; p = p->next) { |
for (p = h; p->next != NULL; p = p->next) { |
650 |
p->tot_len += t->tot_len; |
p->tot_len += t->tot_len; |
651 |
} |
} |
652 |
/* p is last pbuf of first h chain */ |
/* p is last pbuf of first h chain */ |
653 |
|
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); |
654 |
/* add total length of second chain to last pbuf total of first chain */ |
/* add total length of second chain to last pbuf total of first chain */ |
655 |
p->tot_len += t->tot_len; |
p->tot_len += t->tot_len; |
656 |
/* chain last pbuf of h chain (p) with first of tail (t) */ |
/* chain last pbuf of h chain (p) with first of tail (t) */ |
660 |
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t)); |
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t)); |
661 |
} |
} |
662 |
|
|
663 |
|
/* For packet queueing. Note that queued packets must be dequeued first |
664 |
|
* before calling any pbuf functions. */ |
665 |
|
#if ARP_QUEUEING |
666 |
/** |
/** |
667 |
* Dechains the first pbuf from its succeeding pbufs in the chain. |
* Add a packet to the end of a queue. |
668 |
* |
* |
669 |
* Makes p->tot_len field equal to p->len. |
* @param q pointer to first packet on the queue |
670 |
* @param p pbuf to dechain |
* @param n packet to be queued |
671 |
* @return remainder of the pbuf chain, or NULL if it was de-allocated. |
* |
672 |
|
*/ |
673 |
|
void |
674 |
|
pbuf_queue(struct pbuf *p, struct pbuf *n) |
675 |
|
{ |
676 |
|
LWIP_ASSERT("p != NULL", p != NULL); |
677 |
|
LWIP_ASSERT("n != NULL", n != NULL); |
678 |
|
|
679 |
|
if ((p == NULL) || (n == NULL)) |
680 |
|
return; |
681 |
|
|
682 |
|
/* iterate through all packets on queue */ |
683 |
|
while (p->next != NULL) { |
684 |
|
/* be very picky about pbuf chain correctness */ |
685 |
|
#if PBUF_DEBUG |
686 |
|
/* iterate through all pbufs in packet */ |
687 |
|
while (p->tot_len != p->len) { |
688 |
|
/* make sure each packet is complete */ |
689 |
|
LWIP_ASSERT("p->next != NULL", p->next != NULL); |
690 |
|
p = p->next; |
691 |
|
} |
692 |
|
#endif |
693 |
|
/* now p->tot_len == p->len */ |
694 |
|
/* proceed to next packet on queue */ |
695 |
|
p = p->next; |
696 |
|
} |
697 |
|
/* chain last pbuf of h chain (p) with first of tail (t) */ |
698 |
|
p->next = n; |
699 |
|
/* t is now referenced to one more time */ |
700 |
|
pbuf_ref(n); |
701 |
|
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_queue: referencing queued packet %p\n", (void *)n)); |
702 |
|
} |
703 |
|
|
704 |
|
/** |
705 |
|
* Remove a packet from the head of a queue. |
706 |
|
* |
707 |
|
* @param p pointer to first packet on the queue which will be dequeued. |
708 |
|
* @return first packet on the remaining queue (NULL if no further packets). |
709 |
|
* |
710 |
*/ |
*/ |
711 |
struct pbuf * |
struct pbuf * |
712 |
pbuf_dechain(struct pbuf *p) |
pbuf_dequeue(struct pbuf *p) |
713 |
{ |
{ |
714 |
struct pbuf *q; |
struct pbuf *q; |
715 |
u8_t tail_gone = 1; |
LWIP_ASSERT("p != NULL", p != NULL); |
716 |
/* tail */ |
|
717 |
q = p->next; |
/* iterate through all pbufs in packet */ |
718 |
/* pbuf has successor in chain? */ |
while (p->tot_len != p->len) { |
719 |
if (q != NULL) { |
/* make sure each packet is complete */ |
720 |
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
LWIP_ASSERT("p->next != NULL", p->next != NULL); |
721 |
LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); |
p = p->next; |
|
/* enforce invariant if assertions are disabled -- this should not be necessary but is |
|
|
* a robustness item */ |
|
|
q->tot_len = p->tot_len - p->len; |
|
|
/* decouple pbuf from remainder */ |
|
|
p->next = NULL; |
|
|
/* total length of pbuf p is its own length only */ |
|
|
p->tot_len = p->len; |
|
|
/* q is no longer referenced by p, free it */ |
|
|
DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q)); |
|
|
tail_gone = pbuf_free(q); |
|
722 |
} |
} |
723 |
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
/* remember next packet on queue */ |
724 |
LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); |
q = p->next; |
725 |
/* return remaining tail or NULL if deallocated */ |
/* dequeue p from queue */ |
726 |
return (tail_gone > 0? NULL: q); |
p->next = NULL; |
727 |
|
/* q is now referenced to one less time */ |
728 |
|
pbuf_free(q); |
729 |
|
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: dereferencing remaining queue %p\n", (void *)q)); |
730 |
|
return q; |
731 |
} |
} |
732 |
|
#endif |
733 |
|
|
734 |
/** |
/** |
735 |
* |
* |
736 |
* Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs. |
* Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs. |
737 |
* |
* |
738 |
|
* Used to queue packets on behalf of the lwIP stack, such as |
739 |
|
* ARP based queueing. |
740 |
|
* |
741 |
* Go through a pbuf chain and replace any PBUF_REF buffers |
* Go through a pbuf chain and replace any PBUF_REF buffers |
742 |
* with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of |
* with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of |
743 |
* the referenced data. |
* the referenced data. |
747 |
* by pbuf_take()! |
* by pbuf_take()! |
748 |
* |
* |
749 |
* @note Any replaced pbufs will be freed through pbuf_free(). |
* @note Any replaced pbufs will be freed through pbuf_free(). |
750 |
* |
* This may allocate them if they become no longer referenced. |
|
* Used to queue packets on behalf of the lwIP stack, such as |
|
|
* ARP based queueing. |
|
751 |
* |
* |
752 |
* @param p Head of pbuf chain to process |
* @param p Head of pbuf chain to process |
753 |
* |
* |
754 |
* @return Pointer to new head of pbuf chain |
* @return Pointer to head of pbuf chain |
755 |
*/ |
*/ |
756 |
struct pbuf * |
struct pbuf * |
757 |
pbuf_take(struct pbuf *p) |
pbuf_take(struct pbuf *p) |
774 |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); |
775 |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n")); |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n")); |
776 |
} else { |
} else { |
777 |
/* no replacement pbuf yet */ |
/* no replacement pbuf yet */ |
778 |
q = NULL; |
q = NULL; |
779 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n")); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n")); |
780 |
} |
} |
836 |
return head; |
return head; |
837 |
} |
} |
838 |
|
|
839 |
|
#if 0 /* TODO: See if we might need this for future features */ |
840 |
|
/** |
841 |
|
* Dechains the first pbuf from its succeeding pbufs in the chain. |
842 |
|
* |
843 |
|
* Makes p->tot_len field equal to p->len. |
844 |
|
* @param p pbuf to dechain |
845 |
|
* @return remainder of the pbuf chain, or NULL if it was de-allocated. |
846 |
|
* @note May not be called on a packet queue. |
847 |
|
*/ |
848 |
|
struct pbuf * |
849 |
|
pbuf_dechain(struct pbuf *p) |
850 |
|
{ |
851 |
|
struct pbuf *q; |
852 |
|
u8_t tail_gone = 1; |
853 |
|
/* tail */ |
854 |
|
q = p->next; |
855 |
|
/* pbuf has successor in chain? */ |
856 |
|
if (q != NULL) { |
857 |
|
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
858 |
|
LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); |
859 |
|
/* enforce invariant if assertion is disabled */ |
860 |
|
q->tot_len = p->tot_len - p->len; |
861 |
|
/* decouple pbuf from remainder */ |
862 |
|
p->next = NULL; |
863 |
|
/* total length of pbuf p is its own length only */ |
864 |
|
p->tot_len = p->len; |
865 |
|
/* q is no longer referenced by p, free it */ |
866 |
|
DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q)); |
867 |
|
tail_gone = pbuf_free(q); |
868 |
|
/* return remaining tail or NULL if deallocated */ |
869 |
|
} |
870 |
|
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
871 |
|
LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); |
872 |
|
return (tail_gone > 0? NULL: q); |
873 |
|
} |
874 |
|
#endif /* pbuf_dechain() */ |
875 |
|
|
876 |
|
/* TODO: This function is unused in the lwIP stack and will be deprecated. This is due |
877 |
|
* to the new way chains are built. */ |
878 |
|
#if 0 |
879 |
|
/** |
880 |
|
* |
881 |
|
* Increment the reference count of all pbufs in a chain. |
882 |
|
* |
883 |
|
* @param p first pbuf of chain |
884 |
|
* |
885 |
|
*/ |
886 |
|
void |
887 |
|
pbuf_ref_chain(struct pbuf *p) |
888 |
|
{ |
889 |
|
SYS_ARCH_DECL_PROTECT(old_level); |
890 |
|
SYS_ARCH_PROTECT(old_level); |
891 |
|
|
892 |
|
while (p != NULL) { |
893 |
|
++p->ref; |
894 |
|
p = p->next; |
895 |
|
} |
896 |
|
SYS_ARCH_UNPROTECT(old_level); |
897 |
|
} |
898 |
|
#endif |