1 |
/** |
/** |
2 |
* @file |
* @file |
3 |
* Packet buffers/chains management module |
* Packet buffer management |
4 |
|
* |
5 |
|
* Packets are represented by the pbuf data structure. It supports dynamic |
6 |
|
* memory allocation for packet contents or can reference externally |
7 |
|
* managed packet contents both in RAM and ROM. Quick allocation for |
8 |
|
* 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 |
11 |
|
* that a packet may span over several pbufs. |
12 |
|
* |
13 |
*/ |
*/ |
14 |
|
|
15 |
/* |
/* |
69 |
static struct pbuf *pbuf_pool_free_cache = NULL; |
static struct pbuf *pbuf_pool_free_cache = NULL; |
70 |
|
|
71 |
/** |
/** |
|
* |
|
72 |
* Initializes the pbuf module. |
* Initializes the pbuf module. |
73 |
* |
* |
74 |
* A large part of memory is allocated for holding the pool of pbufs. |
* A large part of memory is allocated for holding the pool of pbufs. |
197 |
} |
} |
198 |
|
|
199 |
/** |
/** |
200 |
|
* Allocates a pbuf. |
201 |
* |
* |
|
* Allocates a pbuf at protocol layer l. |
|
202 |
* The actual memory allocated for the pbuf is determined by the |
* The actual memory allocated for the pbuf is determined by the |
203 |
* layer at which the pbuf is allocated and the requested size |
* layer at which the pbuf is allocated and the requested size |
204 |
* (from the size parameter). The flag parameter decides how and |
* (from the size parameter). |
205 |
* where the pbuf should be allocated as follows: |
* |
206 |
|
* @param flag this parameter decides how and where the pbuf |
207 |
|
* should be allocated as follows: |
208 |
* |
* |
209 |
* - PBUF_RAM: buffer memory for pbuf is allocated as one large |
* - PBUF_RAM: buffer memory for pbuf is allocated as one large |
210 |
* chunk. This includes protocol headers as well. |
* chunk. This includes protocol headers as well. |
221 |
* then pbuf_take should be called to copy the buffer. |
* then pbuf_take should be called to copy the buffer. |
222 |
* - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from |
* - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from |
223 |
* the pbuf pool that is allocated during pbuf_init(). |
* the pbuf pool that is allocated during pbuf_init(). |
224 |
|
* |
225 |
|
* @return the allocated pbuf. If multiple pbufs where allocated, this |
226 |
|
* is the first pbuf of a pbuf chain. |
227 |
*/ |
*/ |
228 |
struct pbuf * |
struct pbuf * |
229 |
pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag) |
pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag) |
230 |
{ |
{ |
231 |
struct pbuf *p, *q, *r; |
struct pbuf *p, *q, *r; |
232 |
u16_t offset; |
u16_t offset; |
233 |
s32_t rem_len; |
s32_t rem_len; /* remaining length */ |
234 |
|
|
235 |
/* determine header offset */ |
/* determine header offset */ |
236 |
offset = 0; |
offset = 0; |
263 |
} |
} |
264 |
p->next = NULL; |
p->next = NULL; |
265 |
|
|
266 |
/* make the payload pointer points offset bytes into pbuf data memory */ |
/* make the payload pointer point offset bytes into pbuf data memory */ |
267 |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
268 |
/* the total length of the pbuf is the requested size */ |
/* the total length of the pbuf is the requested size */ |
269 |
p->tot_len = size; |
p->tot_len = length; |
270 |
/* set the length of the first pbuf is the chain */ |
/* set the length of the first pbuf in the chain */ |
271 |
p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size; |
p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length; |
272 |
p->flags = PBUF_FLAG_POOL; |
p->flags = PBUF_FLAG_POOL; |
273 |
|
|
274 |
/* allocate the tail of the pbuf chain. */ |
/* allocate the tail of the pbuf chain. */ |
275 |
r = p; |
r = p; |
276 |
rem_len = size - p->len; |
/* remaining length to be allocated */ |
277 |
|
rem_len = length - p->len; |
278 |
|
/* any remaining pbufs to be allocated? */ |
279 |
while(rem_len > 0) { |
while(rem_len > 0) { |
280 |
q = pbuf_pool_alloc(); |
q = pbuf_pool_alloc(); |
281 |
if (q == NULL) { |
if (q == NULL) { |
294 |
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); |
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); |
295 |
r = q; |
r = q; |
296 |
q->ref = 1; |
q->ref = 1; |
297 |
rem_len -= PBUF_POOL_BUFSIZE; |
rem_len -= q->len; |
298 |
} |
} |
299 |
/* end of chain */ |
/* end of chain */ |
300 |
r->next = NULL; |
r->next = NULL; |
304 |
break; |
break; |
305 |
case PBUF_RAM: |
case PBUF_RAM: |
306 |
/* If pbuf is to be allocated in RAM, allocate memory for it. */ |
/* If pbuf is to be allocated in RAM, allocate memory for it. */ |
307 |
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset)); |
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset)); |
308 |
if (p == NULL) { |
if (p == NULL) { |
309 |
return NULL; |
return NULL; |
310 |
} |
} |
311 |
/* Set up internal structure of the pbuf. */ |
/* Set up internal structure of the pbuf. */ |
312 |
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset)); |
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset)); |
313 |
p->len = p->tot_len = size; |
p->len = p->tot_len = length; |
314 |
p->next = NULL; |
p->next = NULL; |
315 |
p->flags = PBUF_FLAG_RAM; |
p->flags = PBUF_FLAG_RAM; |
316 |
|
|
329 |
} |
} |
330 |
/* caller must set this field properly, afterwards */ |
/* caller must set this field properly, afterwards */ |
331 |
p->payload = NULL; |
p->payload = NULL; |
332 |
p->len = p->tot_len = size; |
p->len = p->tot_len = length; |
333 |
p->next = NULL; |
p->next = NULL; |
334 |
p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); |
p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); |
335 |
break; |
break; |
486 |
} |
} |
487 |
|
|
488 |
/** |
/** |
489 |
* Tries to decrease the payload pointer by the given header size. |
* Tries to add a header to the payload. |
490 |
* |
* |
491 |
* Adjusts the ->payload pointer so that space for a header appears in |
* Adjusts the ->payload pointer so that space for a header appears in |
492 |
* the pbuf. Also, the ->tot_len and ->len fields are adjusted. |
* the pbuf. Also, the ->tot_len and ->len fields are adjusted. |
500 |
pbuf_header(struct pbuf *p, s16_t header_size) |
pbuf_header(struct pbuf *p, s16_t header_size) |
501 |
{ |
{ |
502 |
void *payload; |
void *payload; |
503 |
/* referencing pbufs cannot be realloc()ed */ |
|
504 |
/* TODO: WHY NOT? just adjust payload, tot_len and len? */ |
/* remember current payload pointer */ |
|
if (p->flags == PBUF_FLAG_ROM || |
|
|
p->flags == PBUF_FLAG_REF) { |
|
|
/* failure */ |
|
|
return 1; |
|
|
} |
|
|
|
|
505 |
payload = p->payload; |
payload = p->payload; |
506 |
|
/* set new payload pointer */ |
507 |
p->payload = (u8_t *)p->payload - header_size; |
p->payload = (u8_t *)p->payload - header_size; |
508 |
|
|
509 |
DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size)); |
/* pbuf types containing payloads? */ |
510 |
|
if (p->flags == PBUF_FLAG_RAM || |
511 |
/* */ |
p->flags == PBUF_FLAG_POOL) { |
512 |
if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { |
/* boundary check fails? */ |
513 |
DEBUGF(PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n", |
if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { |
514 |
(u8_t *)p->payload, |
DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n", |
515 |
(u8_t *)p + sizeof(struct pbuf)));\ |
(u8_t *)p->payload, |
516 |
/* restore old payload pointer */ |
(u8_t *)p + sizeof(struct pbuf)) );\ |
517 |
p->payload = payload; |
/* restore old payload pointer */ |
518 |
return 1; |
p->payload = payload;/ |
519 |
|
/* bail out unsuccesfully */ |
520 |
|
return 1; |
521 |
|
} |
522 |
} |
} |
523 |
|
|
524 |
|
DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size) ); |
525 |
|
/* modify pbuf length fields */ |
526 |
p->len += header_size; |
p->len += header_size; |
527 |
p->tot_len += header_size; |
p->tot_len += header_size; |
528 |
|
|
529 |
return 0; |
return 0; |
530 |
} |
} |
531 |
|
|
563 |
SYS_ARCH_DECL_PROTECT(old_level); |
SYS_ARCH_DECL_PROTECT(old_level); |
564 |
|
|
565 |
if (p == NULL) { |
if (p == NULL) { |
566 |
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")); |
567 |
return 0; |
return 0; |
568 |
} |
} |
569 |
|
|
591 |
{ |
{ |
592 |
/* remember next pbuf in chain for next iteration */ |
/* remember next pbuf in chain for next iteration */ |
593 |
q = p->next; |
q = p->next; |
|
|
|
594 |
/* is this a pbuf from the pool? */ |
/* is this a pbuf from the pool? */ |
595 |
if (p->flags == PBUF_FLAG_POOL) { |
if (p->flags == PBUF_FLAG_POOL) { |
596 |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
695 |
|
|
696 |
/* proceed to last pbuf of chain */ |
/* proceed to last pbuf of chain */ |
697 |
for (p = h; p->next != NULL; p = p->next) { |
for (p = h; p->next != NULL; p = p->next) { |
698 |
/* add length of second chain to totals of first chain */ |
/* add total length of second chain to each total of first chain */ |
699 |
p->tot_len += t->tot_len; |
p->tot_len += t->tot_len; |
700 |
} |
} |
701 |
/* chain last pbuf of h chain (p) with first of tail (t) */ |
/* chain last pbuf of h chain (p) with first of tail (t) */ |
762 |
{ |
{ |
763 |
struct pbuf *p, *prev, *top; |
struct pbuf *p, *prev, *top; |
764 |
LWIP_ASSERT("pbuf_take: f != NULL", f != NULL); |
LWIP_ASSERT("pbuf_take: f != NULL", f != NULL); |
765 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)", (void*)f)); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)f)); |
766 |
|
|
767 |
prev = NULL; |
prev = NULL; |
768 |
p = f; |
p = f; |
775 |
{ |
{ |
776 |
/* the replacement pbuf */ |
/* the replacement pbuf */ |
777 |
struct pbuf *q; |
struct pbuf *q; |
778 |
DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p", (void *)p)); |
DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p)); |
779 |
/* allocate a pbuf (w/ payload) fully in RAM */ |
/* allocate a pbuf (w/ payload) fully in RAM */ |
780 |
/* PBUF_POOL buffers are faster if we can use them */ |
/* PBUF_POOL buffers are faster if we can use them */ |
781 |
if (p->len <= PBUF_POOL_BUFSIZE) { |
if (p->len <= PBUF_POOL_BUFSIZE) { |
782 |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL); |
783 |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL")); |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n")); |
784 |
} else { |
} else { |
785 |
/* no replacement pbuf yet */ |
/* no replacement pbuf yet */ |
786 |
q = NULL; |
q = NULL; |
787 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF")); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n")); |
788 |
} |
} |
789 |
/* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */ |
/* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */ |
790 |
if (q == NULL) { |
if (q == NULL) { |
791 |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM); |
q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM); |
792 |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM")); |
if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n")); |
793 |
} |
} |
794 |
/* replacement pbuf could be allocated? */ |
/* replacement pbuf could be allocated? */ |
795 |
if (q != NULL) |
if (q != NULL) |
831 |
} |
} |
832 |
} |
} |
833 |
else { |
else { |
834 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: not PBUF_REF")); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: not PBUF_REF\n")); |
835 |
} |
} |
836 |
|
|
837 |
prev = p; |
prev = p; |
838 |
p = p->next; |
p = p->next; |
839 |
} while (p); |
} while (p); |
840 |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.")); |
DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n")); |
841 |
|
|
842 |
return top; |
return top; |
843 |
} |
} |