1 |
|
/** |
2 |
|
* @file |
3 |
|
* Packet buffers/chains management module |
4 |
|
*/ |
5 |
/* |
/* |
6 |
* Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
* Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
7 |
* All rights reserved. |
* All rights reserved. |
92 |
lwip_stats.pbuf.avail = PBUF_POOL_SIZE; |
lwip_stats.pbuf.avail = PBUF_POOL_SIZE; |
93 |
#endif /* PBUF_STATS */ |
#endif /* PBUF_STATS */ |
94 |
|
|
95 |
/* Set up ->next pointers to link the pbufs of the pool together. */ |
/* Set up ->next pointers to link the pbufs of the pool together */ |
96 |
p = pbuf_pool; |
p = pbuf_pool; |
97 |
|
|
98 |
for(i = 0; i < PBUF_POOL_SIZE; ++i) { |
for(i = 0; i < PBUF_POOL_SIZE; ++i) { |
104 |
} |
} |
105 |
|
|
106 |
/* The ->next pointer of last pbuf is NULL to indicate that there |
/* The ->next pointer of last pbuf is NULL to indicate that there |
107 |
are no more pbufs in the pool. */ |
are no more pbufs in the pool */ |
108 |
q->next = NULL; |
q->next = NULL; |
109 |
|
|
110 |
#if !SYS_LIGHTWEIGHT_PROT |
#if !SYS_LIGHTWEIGHT_PROT |
223 |
u16_t offset; |
u16_t offset; |
224 |
s32_t rsize; |
s32_t rsize; |
225 |
|
|
226 |
|
/* determine header offset */ |
227 |
offset = 0; |
offset = 0; |
228 |
switch(l) { |
switch(l) { |
229 |
case PBUF_TRANSPORT: |
case PBUF_TRANSPORT: |
244 |
|
|
245 |
switch(flag) { |
switch(flag) { |
246 |
case PBUF_POOL: |
case PBUF_POOL: |
247 |
/* Allocate head of pbuf chain into p. */ |
/* allocate head of pbuf chain into p */ |
248 |
p = pbuf_pool_alloc(); |
p = pbuf_pool_alloc(); |
249 |
if(p == NULL) { |
if(p == NULL) { |
250 |
#ifdef PBUF_STATS |
#ifdef PBUF_STATS |
254 |
} |
} |
255 |
p->next = NULL; |
p->next = NULL; |
256 |
|
|
257 |
/* Set the payload pointer so that it points offset bytes into |
/* make the payload pointer points offset bytes into pbuf data memory */ |
|
pbuf data memory. */ |
|
258 |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); |
259 |
|
|
260 |
/* The total length of the pbuf is the requested size. */ |
/* the total length of the pbuf is the requested size */ |
261 |
p->tot_len = size; |
p->tot_len = size; |
262 |
|
|
263 |
/* Set the length of the first pbuf is the chain. */ |
/* set the length of the first pbuf is the chain */ |
264 |
p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size; |
p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size; |
265 |
|
|
266 |
p->flags = PBUF_FLAG_POOL; |
p->flags = PBUF_FLAG_POOL; |
267 |
|
|
268 |
/* Allocate the tail of the pbuf chain. */ |
/* allocate the tail of the pbuf chain. */ |
269 |
r = p; |
r = p; |
270 |
rsize = size - p->len; |
rsize = size - p->len; |
271 |
while(rsize > 0) { |
while(rsize > 0) { |
308 |
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", |
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", |
309 |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
((u32_t)p->payload % MEM_ALIGNMENT) == 0); |
310 |
break; |
break; |
311 |
/* pbuf references existing ROM payload? */ |
/* pbuf references existing (static constant) ROM payload? */ |
312 |
case PBUF_ROM: |
case PBUF_ROM: |
313 |
/* pbuf references existing (externally allocated) RAM payload? */ |
/* pbuf references existing (externally allocated) RAM payload? */ |
314 |
case PBUF_REF: |
case PBUF_REF: |
322 |
p->payload = NULL; |
p->payload = NULL; |
323 |
p->len = p->tot_len = size; |
p->len = p->tot_len = size; |
324 |
p->next = NULL; |
p->next = NULL; |
325 |
if (flag == PBUF_ROM) |
p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); |
|
p->flags = PBUF_FLAG_ROM; |
|
|
else |
|
|
p->flags = PBUF_FLAG_REF; |
|
326 |
break; |
break; |
327 |
default: |
default: |
328 |
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0); |
LWIP_ASSERT("pbuf_alloc: erroneous flag", 0); |
427 |
p->flags == PBUF_FLAG_RAM || |
p->flags == PBUF_FLAG_RAM || |
428 |
p->flags == PBUF_FLAG_REF); |
p->flags == PBUF_FLAG_REF); |
429 |
|
|
|
|
|
430 |
if(p->tot_len <= size) { |
if(p->tot_len <= size) { |
431 |
return; |
return; |
432 |
} |
} |
487 |
|
|
488 |
pbuf_refresh(); |
pbuf_refresh(); |
489 |
} |
} |
490 |
/*-----------------------------------------------------------------------------------*/ |
/** |
491 |
/* pbuf_header(): |
* Decreases the header size by the given amount. |
492 |
* |
* |
493 |
* Adjusts the ->payload pointer so that space for a header appears in |
* Adjusts the ->payload pointer so that space for a header appears in |
494 |
* the pbuf. Also, the ->tot_len and ->len fields are adjusted. |
* the pbuf. Also, the ->tot_len and ->len fields are adjusted. |
495 |
* |
* |
496 |
* Decreases the header size by the given amount. |
* @param hdr_decrement Number of bytes to decrement header size. |
497 |
* Using a negative value increases the header size. |
* (Using a negative value increases the header size.) |
498 |
|
* |
499 |
|
* @return 1 on failure, 0 on succes. |
500 |
*/ |
*/ |
501 |
/*-----------------------------------------------------------------------------------*/ |
/*-----------------------------------------------------------------------------------*/ |
502 |
u8_t |
u8_t |
503 |
pbuf_header(struct pbuf *p, s16_t header_size) |
pbuf_header(struct pbuf *p, s16_t header_size) |
504 |
{ |
{ |
505 |
void *payload; |
void *payload; |
506 |
|
/* referencing pbufs cannot be realloc()ed */ |
507 |
if(p->flags == PBUF_FLAG_ROM || |
if (p->flags == PBUF_FLAG_ROM || |
508 |
p->flags == PBUF_FLAG_REF) { |
p->flags == PBUF_FLAG_REF) { |
509 |
return 1; |
return 1; |
510 |
} |
} |
511 |
|
|
514 |
|
|
515 |
DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size)); |
DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size)); |
516 |
|
|
517 |
|
/* */ |
518 |
if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { |
if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) { |
519 |
DEBUGF(PBUF_DEBUG | 2, ("pbuf_header: failed %p %p\n", |
DEBUGF(PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p\n", |
520 |
(u8_t *)p->payload, |
(u8_t *)p->payload, |
521 |
(u8_t *)p + sizeof(struct pbuf))); |
(u8_t *)p + sizeof(struct pbuf)));\ |
522 |
|
/* restore old payload pointer */ |
523 |
p->payload = payload; |
p->payload = payload; |
524 |
return 1; |
return 1; |
525 |
} |
} |
543 |
u8_t count = 0; |
u8_t count = 0; |
544 |
SYS_ARCH_DECL_PROTECT(old_level); |
SYS_ARCH_DECL_PROTECT(old_level); |
545 |
|
|
546 |
if(p == NULL) { |
if (p == NULL) { |
547 |
|
DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p==NULL) was called.\n")); |
548 |
return 0; |
return 0; |
549 |
} |
} |
550 |
|
|
556 |
p->flags == PBUF_FLAG_REF ); |
p->flags == PBUF_FLAG_REF ); |
557 |
|
|
558 |
/* Since decrementing ref cannot be guarranteed to be a single machine operation |
/* Since decrementing ref cannot be guarranteed to be a single machine operation |
559 |
we must protect it. Also, the later test of ref must be protected. |
* we must protect it. Also, the later test of ref must be protected. |
560 |
*/ |
*/ |
561 |
SYS_ARCH_PROTECT(old_level); |
SYS_ARCH_PROTECT(old_level); |
562 |
/* Decrement reference count. */ |
/* decrement individual reference count for each pbufs in chain */ |
563 |
for (q = p; q != NULL; q = q->next) { |
for (q = p; q != NULL; q = q->next) { |
564 |
LWIP_ASSERT("pbuf_free: q->ref > 0", q->ref > 0); |
LWIP_ASSERT("pbuf_free: q->ref > 0", q->ref > 0); |
565 |
q->ref--; |
q->ref--; |
566 |
} |
} |
567 |
|
|
568 |
/* If reference count == 0, actually deallocate pbuf. */ |
/* if reference count == 0, actually deallocate pbuf */ |
569 |
if(p->ref == 0) { |
if (p->ref == 0) { |
570 |
SYS_ARCH_UNPROTECT(old_level); |
SYS_ARCH_UNPROTECT(old_level); |
571 |
|
|
572 |
while(p != NULL) { |
while (p != NULL) { |
573 |
|
/* remember next in chain */ |
574 |
|
q = p->next; |
575 |
/* this is a pbuf from the pool? */ |
/* this is a pbuf from the pool? */ |
576 |
if(p->flags == PBUF_FLAG_POOL) { |
if (p->flags == PBUF_FLAG_POOL) { |
577 |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
p->len = p->tot_len = PBUF_POOL_BUFSIZE; |
578 |
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); |
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); |
|
q = p->next; |
|
579 |
PBUF_POOL_FREE(p); |
PBUF_POOL_FREE(p); |
580 |
/* not a pbuf from the pool */ |
/* RAM/ROM referencing pbuf */ |
581 |
|
} else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { |
582 |
|
memp_freep(MEMP_PBUF, p); |
583 |
|
/* pbuf with data */ |
584 |
|
} else { |
585 |
|
mem_free(p); |
586 |
} |
} |
587 |
else { |
/* next in chain */ |
|
if(p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) { |
|
|
q = p->next; |
|
|
memp_freep(MEMP_PBUF, p); |
|
|
} |
|
|
else { |
|
|
q = p->next; |
|
|
mem_free(p); |
|
|
} |
|
|
} |
|
|
|
|
588 |
p = q; |
p = q; |
589 |
/* Only free the next one in a chain if it's reference count is 0. |
/* Only free the next one in a chain if it's reference count is 0. |
590 |
This allows buffer chains to have multiple headers pointing to them. */ |
This allows buffer chains to have multiple headers pointing to them. */ |
591 |
if (p) |
if (p != NULL) |
592 |
{ |
{ |
593 |
p->ref--; |
p->ref--; |
594 |
if (p->ref > 0) |
if (p->ref > 0) |
598 |
++count; |
++count; |
599 |
} |
} |
600 |
pbuf_refresh(); |
pbuf_refresh(); |
601 |
} |
} else |
602 |
else |
SYS_ARCH_UNPROTECT(old_level); |
|
SYS_ARCH_UNPROTECT(old_level); |
|
|
|
|
603 |
PERF_STOP("pbuf_free"); |
PERF_STOP("pbuf_free"); |
604 |
|
|
605 |
return count; |
return count; |
681 |
p->next = t; |
p->next = t; |
682 |
h->tot_len += t->tot_len; |
h->tot_len += t->tot_len; |
683 |
} |
} |
684 |
/*-----------------------------------------------------------------------------------*/ |
|
685 |
/* pbuf_dechain(): |
/** |
686 |
|
* Dechains a pbuf from any succeeding pbufs in the chain. |
687 |
* |
* |
688 |
* Adjusts the ->tot_len field of the pbuf and returns the tail (if |
* Makes p->tot_len field equal to p->len. |
689 |
* any) of the pbuf chain. |
* @param p pbuf to dechain |
690 |
|
* @return remainder (if any) of the pbuf chain. |
691 |
*/ |
*/ |
|
/*-----------------------------------------------------------------------------------*/ |
|
692 |
struct pbuf * |
struct pbuf * |
693 |
pbuf_dechain(struct pbuf *p) |
pbuf_dechain(struct pbuf *p) |
694 |
{ |
{ |
695 |
struct pbuf *q; |
struct pbuf *q; |
696 |
|
|
697 |
q = p->next; |
q = p->next; |
698 |
|
/* pbuf has successor in chain? */ |
699 |
if (q != NULL) { |
if (q != NULL) { |
700 |
|
/* LW: shouldn't q->tot_len be already exactly this? (make this an assert?) */ |
701 |
q->tot_len = p->tot_len - p->len; |
q->tot_len = p->tot_len - p->len; |
702 |
} |
} |
703 |
|
/* decouple pbuf from remainder */ |
704 |
p->tot_len = p->len; |
p->tot_len = p->len; |
705 |
p->next = NULL; |
p->next = NULL; |
706 |
return q; |
return q; |