diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 28fe48e3..8e9bcd06 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -151,6 +151,20 @@ void eth_rx_irq() volatile u8_t pbuf_free_ooseq_pending; #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() +/* Initialize members of struct pbuf after allocation */ +static void +pbuf_init_alloced_pbuf(struct pbuf *p, void* payload, u16_t tot_len, u16_t len, u8_t type) +{ + p->next = NULL; + p->payload = payload; + p->tot_len = tot_len; + p->len = len; + p->type = type; + p->flags = 0; + p->ref = 1; + p->if_idx = NETIF_NO_INDEX; +} + /** * Attempt to reclaim some memory from queued out-of-sequence TCP segments * if we run out of pool pbufs. It's better to give priority to new packets @@ -248,11 +262,14 @@ pbuf_pool_is_empty(void) struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { - struct pbuf *p, *q, *r; + struct pbuf *p; u16_t offset; - s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); + if ((type == PBUF_REF) || (type == PBUF_ROM)) { + return pbuf_alloc_reference(NULL, length, type); + } + /* determine header offset */ switch (layer) { case PBUF_TRANSPORT: @@ -282,75 +299,42 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) switch (type) { case PBUF_POOL: - /* allocate head of pbuf chain into p */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); - if (p == NULL) { - PBUF_POOL_IS_EMPTY(); - return NULL; - } - p->type = type; - p->next = NULL; - p->if_idx = NETIF_NO_INDEX; - - /* make the payload pointer point 'offset' bytes into pbuf data memory */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); - LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - /* the total length of the pbuf chain is the requested size */ - p->tot_len = length; - /* set the length of the first pbuf in the chain */ - p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", - (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); - /* set reference count (needed here in case we fail) */ - p->ref = 1; - - /* now allocate the tail of the pbuf chain */ - - /* remember first pbuf for linkage in next iteration */ - r = p; - /* remaining length to be allocated */ - rem_len = length - p->len; - /* any remaining pbufs to be allocated? */ - while (rem_len > 0) { - q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - if (q == NULL) { - PBUF_POOL_IS_EMPTY(); - /* free chain so far allocated */ - pbuf_free(p); - /* bail out unsuccessfully */ - return NULL; + { + struct pbuf *q, *last; + u16_t rem_len; /* remaining length */ + p = NULL; + last = NULL; + rem_len = length; + while (rem_len > 0) { + q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + if (q == NULL) { + PBUF_POOL_IS_EMPTY(); + /* free chain so far allocated */ + if (p) { + pbuf_free(p); + } + /* bail out unsuccessfully */ + return NULL; + } + pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), + rem_len, LWIP_MIN(rem_len, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)), type); + LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", + ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", + (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); + if (p == NULL) { + /* allocated head of pbuf chain (into p) */ + p = q; + } else { + /* make previous pbuf point to this pbuf */ + last->next = q; + } + last = q; + rem_len -= q->len; + offset = 0; } - q->type = type; - q->flags = 0; - q->next = NULL; - /* make previous pbuf point to this pbuf */ - r->next = q; - /* set total length of this pbuf and next in chain */ - LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); - q->tot_len = (u16_t)rem_len; - /* this pbuf length is pool size, unless smaller sized tail */ - q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); - q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); - LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", - ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - q->ref = 1; - /* calculate remaining length to be allocated */ - rem_len -= q->len; - /* remember this pbuf for linkage in next iteration */ - r = q; + break; } - /* end of chain */ - /*r->next = NULL;*/ - - break; case PBUF_RAM: { mem_size_t alloc_len = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length); @@ -362,50 +346,65 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)mem_malloc(alloc_len); + if (p == NULL) { + return NULL; + } + pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), + length, length, type); + LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + break; } - - if (p == NULL) { - return NULL; - } - /* Set up internal structure of the pbuf. */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - break; - /* pbuf references existing (non-volatile static constant) ROM payload? */ - case PBUF_ROM: - /* pbuf references existing (externally allocated) RAM payload? */ - case PBUF_REF: - /* only allocate memory for the pbuf structure */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF); - if (p == NULL) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", - (type == PBUF_ROM) ? "ROM" : "REF")); - return NULL; - } - /* caller must set this field properly, afterwards */ - p->payload = NULL; - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - break; default: LWIP_ASSERT("pbuf_alloc: erroneous type", 0); return NULL; } - /* set reference count */ - p->ref = 1; - /* set flags */ - p->flags = 0; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); return p; } +/** + * @ingroup pbuf + * Allocates a pbuf for referenced data. + * Referenced data can be volatile (PBUF_REF) or long-lived (PBUF_ROM). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param payload referenced payload + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_ROM: It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * + * @return the allocated pbuf. + */ +struct pbuf * +pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type) +{ + struct pbuf *p; + LWIP_ASSERT("invalid pbuf_type", (type == PBUF_REF) || (type == PBUF_ROM)); + /* only allocate memory for the pbuf structure */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF); + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_alloc_reference: Could not allocate MEMP_PBUF for PBUF_%s.\n", + (type == PBUF_ROM) ? "ROM" : "REF")); + return NULL; + } + pbuf_init_alloced_pbuf(p, payload, length, length, type); + return p; +} + + #if LWIP_SUPPORT_CUSTOM_PBUF /** * @ingroup pbuf diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 0f3c18d1..cfce97ac 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -240,6 +240,7 @@ void pbuf_free_ooseq(void); #define pbuf_init() struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type); #if LWIP_SUPPORT_CUSTOM_PBUF struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, void *payload_mem,