13 |
* Multiple packets may be queued, also using this singly linked list. |
* 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 |
* 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. |
* or more pbuf chains, each of which consist of one or more pbufs. |
16 |
|
* The differences between a pbuf chain and a packet queue are very |
17 |
|
* subtle. Currently, queues are only supported in a limited section |
18 |
|
* of lwIP, this is the etharp queueing code. Outside of this section |
19 |
|
* no packet queues are supported as of yet. |
20 |
* |
* |
21 |
* The last pbuf of a packet has a ->tot_len field that equals the |
* The last pbuf of a packet has a ->tot_len field that equals the |
22 |
* ->len field. It can be found by traversing the list. If the last |
* ->len field. It can be found by traversing the list. If the last |
23 |
* pbuf of a packet has a ->next field other than NULL, more packets |
* pbuf of a packet has a ->next field other than NULL, more packets |
24 |
* are on the queue. |
* are on the queue. |
25 |
|
* |
26 |
|
* Therefore, looping through a pbuf of a single packet, has an |
27 |
|
* loop end condition (tot_len == p->len), NOT (next == NULL). |
28 |
*/ |
*/ |
29 |
|
|
30 |
/* |
/* |
213 |
struct pbuf *p, *q, *r; |
struct pbuf *p, *q, *r; |
214 |
u16_t offset; |
u16_t offset; |
215 |
s32_t rem_len; /* remaining length */ |
s32_t rem_len; /* remaining length */ |
216 |
|
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u)\n", length)); |
217 |
|
|
218 |
/* determine header offset */ |
/* determine header offset */ |
219 |
offset = 0; |
offset = 0; |
241 |
case PBUF_POOL: |
case PBUF_POOL: |
242 |
/* allocate head of pbuf chain into p */ |
/* allocate head of pbuf chain into p */ |
243 |
p = pbuf_pool_alloc(); |
p = pbuf_pool_alloc(); |
244 |
|
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", p)); |
245 |
if (p == NULL) { |
if (p == NULL) { |
246 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
247 |
++lwip_stats.pbuf.err; |
++lwip_stats.pbuf.err; |
300 |
r = q; |
r = q; |
301 |
} |
} |
302 |
/* end of chain */ |
/* end of chain */ |
303 |
r->next = NULL; |
//r->next = NULL; |
304 |
|
|
305 |
break; |
break; |
306 |
case PBUF_RAM: |
case PBUF_RAM: |
340 |
} |
} |
341 |
/* set reference count */ |
/* set reference count */ |
342 |
p->ref = 1; |
p->ref = 1; |
343 |
|
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u) == %p\n", length, (void *)p)); |
344 |
return p; |
return p; |
345 |
} |
} |
346 |
|
|
544 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); |
545 |
return 0; |
return 0; |
546 |
} |
} |
547 |
|
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); |
548 |
|
|
549 |
PERF_START; |
PERF_START; |
550 |
|
|
568 |
if (p->ref == 0) { |
if (p->ref == 0) { |
569 |
/* remember next pbuf in chain for next iteration */ |
/* remember next pbuf in chain for next iteration */ |
570 |
q = p->next; |
q = p->next; |
571 |
|
DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); |
572 |
/* is this a pbuf from the pool? */ |
/* is this a pbuf from the pool? */ |
573 |
if (p->flags == PBUF_FLAG_POOL) { |
if (p->flags == PBUF_FLAG_POOL) { |
574 |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
587 |
/* p->ref > 0, this pbuf is still referenced to */ |
/* p->ref > 0, this pbuf is still referenced to */ |
588 |
/* (and so the remaining pbufs in chain as well) */ |
/* (and so the remaining pbufs in chain as well) */ |
589 |
} else { |
} else { |
590 |
|
DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %u, ending here.\n", (void *)p, p->ref)); |
591 |
/* stop walking through chain */ |
/* stop walking through chain */ |
592 |
p = NULL; |
p = NULL; |
593 |
} |
} |
674 |
p->next = t; |
p->next = t; |
675 |
/* t is now referenced to one more time */ |
/* t is now referenced to one more time */ |
676 |
pbuf_ref(t); |
pbuf_ref(t); |
677 |
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t)); |
DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)p, (void *)t)); |
678 |
} |
} |
679 |
|
|
680 |
/* For packet queueing. Note that queued packets must be dequeued first |
/* For packet queueing. Note that queued packets must be dequeued first |
882 |
/* q is no longer referenced by p, free it */ |
/* q is no longer referenced by p, free it */ |
883 |
DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q)); |
DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *) q)); |
884 |
tail_gone = pbuf_free(q); |
tail_gone = pbuf_free(q); |
885 |
|
if (tail_gone > 0) DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *) q)); |
886 |
/* return remaining tail or NULL if deallocated */ |
/* return remaining tail or NULL if deallocated */ |
887 |
} |
} |
888 |
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |