/** * Initialize the restricted areas of all memp elements in every pool. */ static void memp_overflow_init(void) { u16_t i, j; struct memp *p; u8_t *m; #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp *)(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ for (j = 0; j < memp_num[i]; ++j) { #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); #endif #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); #endif p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } }
/** * Zero the heap and initialize start, end and lowest-free */ void mem_init(void) { struct mem *mem; LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap */ ram = LWIP_MEM_ALIGN(ram_heap); /* initialize the start of the heap */ mem = (struct mem *)ram; mem->next = MEM_SIZE_ALIGNED; mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; ram_end->used = 1; ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; mem_sem = sys_sem_new(1); /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); }
/** * Initialize this module. * * Carves out memp_memory into linked lists for each pool-type. */ void memp_init(void) { struct memp *memp; u16_t i, j; #if MEMP_STATS for (i = 0; i < MEMP_MAX; ++i) { lwip_stats.memp[i].used = lwip_stats.memp[i].max = lwip_stats.memp[i].err = 0; lwip_stats.memp[i].avail = memp_num[i]; } #endif /* MEMP_STATS */ memp = LWIP_MEM_ALIGN(memp_memory); /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; memp_tab[i] = memp; memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]); } } #if MEMP_OVERFLOW_CHECK memp_overflow_init(); /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ }
/** * Initialize this module. * * Carves out memp_memory into linked lists for each pool-type. */ void memp_init(void) { struct memp *memp; u16_t i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } memp = LWIP_MEM_ALIGN(memp_memory); /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; memp_tab[i] = memp; memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } } #if MEMP_OVERFLOW_CHECK memp_overflow_init(); /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ }
/** * Zero the heap and initialize start, end and lowest-free */ void mem_init(void) { struct mem *mem; LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap */ ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); /* initialize the start of the heap */ mem = (struct mem *)(void *)ram; mem->next = MEM_SIZE_ALIGNED; mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; ram_end->used = 1; ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)(void *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); if(sys_mutex_new(&mem_mutex) != ERR_OK) { LWIP_ASSERT("failed to create mem_mutex", 0); } }
/** * Free memory previously allocated by mem_malloc. Loads the pool number * and calls memp_free with that pool number to put the element back into * its pool * * @param rmem the memory element to free */ void mem_free(void *rmem) { struct memp_malloc_helper *hmem = (struct memp_malloc_helper *)rmem; LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); /* get the original struct memp_malloc_helper */ hmem--; LWIP_ASSERT("hmem != NULL", (hmem != NULL)); LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); /* and put it in the pool we saved earlier */ memp_free(hmem->poolnr, hmem); }
/** * Free memory previously allocated by mem_malloc. Loads the pool number * and calls memp_free with that pool number to put the element back into * its pool * * @param rmem the memory element to free */ void mem_free(void *rmem) { struct memp_malloc_helper *hmem; LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); /* get the original struct memp_malloc_helper */ hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); LWIP_ASSERT("hmem != NULL", (hmem != NULL)); LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); /* and put it in the pool we saved earlier */ fprintf(stderr,"mem_free ###################\n"); memp_free(hmem->poolnr, hmem); }
/** Put memory back on the heap * * @param rmem is the pointer as returned by a previous call to mem_malloc() */ void mem_free(void *rmem) { LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); #if LWIP_STATS && MEM_STATS rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE; MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem); #endif mem_clib_free(rmem); }
void memp_initialize_pbuf_list(void) { assert(memp_memory != NULL); struct memp *memp; uintptr_t uimemp; u16_t k, i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } memp = LWIP_MEM_ALIGN(memp_memory); /* printf("memp_init: total types of pools %d\n", MEMP_MAX ); printf("memp_init: total types of pools %d, memp_mem %p\n", MEMP_MAX, memp_memory); printf("memp_init: total types of pools %d, memp %p\n", MEMP_MAX, memp); */ memp->next = NULL; /* for every pool: */ for (k = 0; k < MEMP_MAX; ++k) { i = memp_sorted[k]; memp_tab[i] = NULL; // Align memp to element size uimemp = (uintptr_t) memp; if (uimemp % memp_sizes[i] > 0) { uimemp += memp_sizes[i] - (uimemp % memp_sizes[i]); } memp = (struct memp *) uimemp; /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = NULL; memp->next = memp_tab[i]; memp_tab[i] = memp; memp = (struct memp *) ((u8_t *) memp + memp_sizes[i]); } } // Set how many free pbuf_pools are there // printf("memp_num[PBUF_POOL] %" PRIu16 "\n", memp_num[MEMP_MAX - 1]); pbuf_pool_counter = 0; #if MEMP_OVERFLOW_CHECK memp_overflow_init(); /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ // mem_barrelfish_register_buf(RX_BUFFER_ID, memp_memory_size); }
/** Initialize a custom pbuf (already allocated). * * @param layer flag to define header size * @param length size of the pbuf's payload * @param type type of the pbuf (only used to treat the pbuf accordingly, as * this function allocates no memory) * @param p pointer to the custom pbuf to initialize (already allocated) * @param payload_mem pointer to the buffer that is used for payload and headers, * must be at least big enough to hold 'length' plus the header size, * may be NULL if set later * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least * big enough to hold 'length' plus the header size */ struct pbuf* pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, void *payload_mem, u16_t payload_mem_len) { u16_t offset; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); /* determine header offset */ offset = 0; switch (l) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset += PBUF_TRANSPORT_HLEN; /* FALLTHROUGH */ case PBUF_IP: /* add room for IP layer header */ offset += PBUF_IP_HLEN; /* FALLTHROUGH */ case PBUF_LINK: /* add room for link layer header */ offset += PBUF_LINK_HLEN; break; case PBUF_RAW: break; default: LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); return NULL; } if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); return NULL; } p->pbuf.next = NULL; if (payload_mem != NULL) { p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset)); } else { p->pbuf.payload = NULL; } p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; p->pbuf.len = p->pbuf.tot_len = length; p->pbuf.type = type; p->pbuf.ref = 1; return &p->pbuf; }
/** * Do an overflow check for all elements in every pool. * * @see memp_overflow_check_element for a description of the check */ static void ICACHE_FLASH_ATTR memp_overflow_check_all(void) { u16_t i, j; struct memp *p; p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_overflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_underflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } }
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p; u16_t offset = 0; offset += 16; /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)rt_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); if (p == RT_NULL) return RT_NULL; /* Set up internal structure of the pbuf. */ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); p->len = length; return p; }
/** * Do an overflow check for all elements in every pool. * * @see memp_overflow_check_element for a description of the check */ static void memp_overflow_check_all(void) { u16_t i, j; struct memp *p; #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp*)memp_bases[i]; #endif /* MEMP_SEPARATE_POOLS */ p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_overflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp*)memp_bases[i]; #endif /* MEMP_SEPARATE_POOLS */ p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_underflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } }
/** * Do an overflow check for all elements in every pool. * * @see memp_overflow_check_element for a description of the check */ static void memp_overflow_check_all(void) { u16_t i, j; struct memp *p; p = LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element(p, memp_sizes[i]); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]); } } }
void memp_initialize_pbuf_list(void) { assert(memp_memory != NULL); struct memp *memp; u16_t i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } memp = LWIP_MEM_ALIGN(memp_memory); /* printf("memp_init: total types of pools %d\n", MEMP_MAX ); printf("memp_init: total types of pools %d, memp_mem %p\n", MEMP_MAX, memp_memory); printf("memp_init: total types of pools %d, memp %p\n", MEMP_MAX, memp); */ memp->next = NULL; /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; /* printf("memp_init: %" PRIu16 "(%s) size %" PRIu16 " num %" PRIu16 "\n", i, memp_desc[i], memp_sizes[i], memp_num[i]); */ /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = NULL; memp->next = memp_tab[i]; memp_tab[i] = memp; memp = (struct memp *) ((u8_t *) memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } } // Set how many free pbuf_pools are there // printf("memp_num[PBUF_POOL] %" PRIu16 "\n", memp_num[MEMP_MAX - 1]); pbuf_pool_counter = 0; #if MEMP_OVERFLOW_CHECK memp_overflow_init(); /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ // mem_barrelfish_register_buf(RX_BUFFER_ID, memp_memory_size); }
/** * Allocate a block of memory with a minimum of 'size' bytes. * * @param size is the minimum size of the requested block in bytes. * @return pointer to allocated memory or NULL if no free memory was found. * * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). */ void * mem_malloc(mem_size_t size) { void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); if (ret == NULL) { MEM_STATS_INC(err); } else { LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); #if LWIP_STATS && MEM_STATS *(mem_size_t*)ret = size; ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE; MEM_STATS_INC_USED(used, size); #endif } return ret; }
/** * Do an overflow check for all elements in every pool. * * @see memp_overflow_check_element for a description of the check */ static void memp_overflow_check_all(void) { u16_t i, j; struct memp *p; SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); for (i = 0; i < MEMP_MAX; ++i) { p = (struct memp*)LWIP_MEM_ALIGN(memp_pools[i]->base); for (j = 0; j < memp_pools[i]->num; ++j) { memp_overflow_check_element_overflow(p, memp_pools[i]); memp_overflow_check_element_underflow(p, memp_pools[i]); p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED)); } } SYS_ARCH_UNPROTECT(old_level); }
/** * Zero the heap and initialize start, end and lowest-free */ void mem_init(LWIP_MEM_CFG *mem_cfg) { struct mem *mem; BOOL en = mem_cfg->enable; UINT8 *start = mem_cfg->start; UINT32 length = LWIP_MEM_ALIGN_SIZE(mem_cfg->length); LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); if(en == TRUE) { ram_heap = (UINT8 *)start; MEM_SIZE_ALIGNED = (length - (2*SIZEOF_STRUCT_MEM) - MEM_ALIGNMENT); } else { ram_heap = (UINT8 *)MALLOC(MEM_SIZE); MEM_SIZE_ALIGNED = (MEM_SIZE - (2*SIZEOF_STRUCT_MEM) - MEM_ALIGNMENT); } /* align the heap */ ram = LWIP_MEM_ALIGN(ram_heap); /* initialize the start of the heap */ mem = (struct mem *)ram; mem->next = MEM_SIZE_ALIGNED; mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; ram_end->used = 1; ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; mem_sem = sys_sem_new(1); /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; #if MEM_STATS lwip_stats.mem.avail = MEM_SIZE_ALIGNED; #endif /* MEM_STATS */ }
void memp_init_pool(const struct memp_desc *desc) { int i; struct memp *memp; *desc->tab = NULL; memp = (struct memp*)LWIP_MEM_ALIGN(desc->base); /* create a linked list of memp elements */ for (i = 0; i < desc->num; ++i) { memp->next = *desc->tab; *desc->tab = memp; memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } #if MEMP_OVERFLOW_CHECK memp_overflow_init(desc); #endif /* MEMP_OVERFLOW_CHECK */ }
/** * Initialize the restricted areas of all memp elements in every pool. */ static void ICACHE_FLASH_ATTR memp_overflow_init(void) { u16_t i, j; struct memp *p; u8_t *m; p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); #endif #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); #endif p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } }
/** * @ingroup pbuf * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * * 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 layer flag to define header size * @param length size of the pbuf's payload * @param type this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. 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: no buffer memory is allocated for the pbuf, even for * protocol headers. 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. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ switch (layer) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; break; case PBUF_RAW_TX: /* add room for encapsulating link layer headers (e.g. 802.11) */ offset = PBUF_LINK_ENCAPSULATION_HLEN; break; case PBUF_RAW: /* no offset (e.g. RX buffers or chain successors) */ offset = 0; break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } 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; } 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; } /* 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); /* bug #50040: Check for integer overflow when calculating alloc_len */ if (alloc_len < LWIP_MEM_ALIGN_SIZE(length)) { return NULL; } /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)mem_malloc(alloc_len); } 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; }
int core0_main(void) { udp_pcb_t * udp; ip_addr_t addr; pbuf_t *p = (void*)0;//(pbuf_t *)pbuf_alloc_special(MEMP_PBUF); uint16 idx; uint16 total; /* * !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!! * Enable the watchdog in the demo if it is required and also service the watchdog periodically * */ IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword()); IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword()); /* Initialise the application state */ g_AppCpu0.info.pllFreq = IfxScuCcu_getPllFrequency(); g_AppCpu0.info.cpuFreq = IfxScuCcu_getCpuFrequency(IfxCpu_getCoreId()); g_AppCpu0.info.sysFreq = IfxScuCcu_getSpbFrequency(); g_AppCpu0.info.stmFreq = IfxStm_getFrequency(&MODULE_STM0); report.position = 0; IfxPort_Io_initModule(&conf); for (idx = 0; idx < conf.size; idx++) { IfxPort_Io_ConfigPin *tbl = &conf.pinTable[idx]; IfxPort_setPinHigh(tbl->pin->port, tbl->pin->pinIndex); // P33.0 = 0 } initStm0(); /* Enable the global interrupts of this CPU */ IfxCpu_enableInterrupts(); /* Demo init */ wMultican_init(); Ifx_Lwip_Config config; IP4_ADDR(&config.ipAddr, 192, 168, 7, 123); IP4_ADDR(&config.netMask, 255, 255, 255, 0); IP4_ADDR(&config.gateway, 192, 168, 7, 6); MAC_ADDR(&config.ethAddr, 0x00, 0x20, 0x30, 0x40, 0x50, 0x60); Ifx_Lwip_init(&config); addr.addr8[3] = 6; addr.addr8[2] = 7; addr.addr8[1] = 168; addr.addr8[0] = 192; /* background endless loop */ IfxPort_setPinHigh(&MODULE_P33, 6); // P33.0 = 0 total = Ifx_g_Eth.config.phyLink(); if (total == 1) { report.phy_link = 1; } else { report.phy_link = 0; } ethRam = NULL_PTR; udp = udp_new(); while (TRUE) { Ifx_Lwip_pollTimerFlags(); Ifx_Lwip_pollReceiveFlags(); if (total != Ifx_g_Eth.config.phyLink()) { total = Ifx_g_Eth.config.phyLink(); if (total == 1) { IfxPort_setPinLow(&MODULE_P33, 6); netif_set_up(&Ifx_g_Lwip.netif); IfxEth_startTransmitter(Ifx_g_Lwip.netif.state); } else { netif_set_down(&Ifx_g_Lwip.netif); IfxPort_setPinHigh(&MODULE_P33, 6); } } report.phy_link = total; report.mdio_stat = IfxEth_Phy_Pef7071_MIIState(); report.ethRam = ethRam!=NULL?1:0; wMultiCanNode0Demo_run(report, 0); if ((stat & 0x0003) != 0x01) { IfxPort_setPinLow(&MODULE_P33, 7); } else { IfxPort_setPinHigh(&MODULE_P33, 7); } if (Ifx_g_Eth.config.phyLink() && (ethRam = IfxEth_getTransmitBuffer(&Ifx_g_Eth))) { p = (pbuf_t *)memp_malloc(MEMP_PBUF); if (p != NULL) { p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)ethRam)); p->len = 100; p->tot_len = p->len; p->next = NULL; p->ref = 1; p->type = PBUF_REF; udp_sendto_if(udp, p, &addr, 5001, &Ifx_g_Lwip.netif); pbuf_free(p); IfxPort_setPinLow(&MODULE_P33, 8); // P33.0 = 0 } } else { IfxPort_setPinHigh(&MODULE_P33, 8); // P33.0 = 0 } REGRESSION_RUN_STOP_PASS; } udp_remove(udp); return 0; }
/** * Thread-safe variant of lwip_gethostbyname: instead of using a static * buffer, this function takes buffer and errno pointers as arguments * and uses these for the result. * * @param name the hostname to resolve * @param ret pre-allocated struct where to store the result * @param buf pre-allocated buffer where to store additional data * @param buflen the size of buf * @param result pointer to a hostent pointer that is set to ret on success * and set to zero on error * @param h_errnop pointer to an int where to store errors (instead of modifying * the global h_errno) * @return 0 on success, non-zero on error, additional error information * is stored in *h_errnop instead of h_errno to be thread-safe */ int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) { err_t err; struct gethostbyname_r_helper *h; char *hostname; size_t namelen; int lh_errno; if (h_errnop == NULL) { /* ensure h_errnop is never NULL */ h_errnop = &lh_errno; } if (result == NULL) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } /* first thing to do: set *result to nothing */ *result = NULL; if ((name == NULL) || (ret == NULL) || (buf == NULL)) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } namelen = strlen(name); if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { /* buf can't hold the data needed + a copy of name */ *h_errnop = ERANGE; return -1; } h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); /* query host IP address */ err = netconn_gethostbyname(name, &h->addr); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); *h_errnop = HOST_NOT_FOUND; return -1; } /* copy the hostname into buf */ MEMCPY(hostname, name, namelen); hostname[namelen] = 0; /* fill hostent */ h->addr_list[0] = &h->addr; h->addr_list[1] = NULL; h->aliases = NULL; ret->h_name = hostname; ret->h_aliases = &h->aliases; ret->h_addrtype = AF_INET; ret->h_length = sizeof(ip_addr_t); ret->h_addr_list = (char**)&h->addr_list; /* set result != NULL */ *result = ret; /* return success */ return 0; }
/** * Fragment an IP datagram if too large for the netif. * * Chop the datagram in MTU sized chunks and send them in order * by using a fixed size static memory buffer (PBUF_REF) or * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). * * @param p ip packet to send * @param netif the netif on which to send * @param dest destination ip address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) { struct pbuf *rambuf; #if IP_FRAG_USES_STATIC_BUF struct pbuf *header; #else #if !LWIP_NETIF_TX_SINGLE_PBUF struct pbuf *newpbuf; #endif struct ip_hdr *original_iphdr; #endif struct ip_hdr *iphdr; u16_t nfb; u16_t left, cop; u16_t mtu = netif->mtu; u16_t ofo, omf; u16_t last; u16_t poff = IP_HLEN; u16_t tmp; #if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF u16_t newpbuflen = 0; u16_t left_to_copy; #endif /* Get a RAM based MTU sized pbuf */ #if IP_FRAG_USES_STATIC_BUF /* When using a static buffer, we use a PBUF_REF, which we will * use to reference the packet (without link header). * Layer and length is irrelevant. */ rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); if (rambuf == NULL) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); return ERR_MEM; } rambuf->tot_len = rambuf->len = mtu; rambuf->payload = LWIP_MEM_ALIGN((void *)buf); /* Copy the IP header in it */ iphdr = (struct ip_hdr *)rambuf->payload; SMEMCPY(iphdr, p->payload, IP_HLEN); #else /* IP_FRAG_USES_STATIC_BUF */ original_iphdr = (struct ip_hdr *)p->payload; iphdr = original_iphdr; #endif /* IP_FRAG_USES_STATIC_BUF */ /* Save original offset */ tmp = ntohs(IPH_OFFSET(iphdr)); ofo = tmp & IP_OFFMASK; omf = tmp & IP_MF; left = p->tot_len - IP_HLEN; nfb = (mtu - IP_HLEN) / 8; while (left) { last = (left <= mtu - IP_HLEN); /* Set new offset and MF flag */ tmp = omf | (IP_OFFMASK & (ofo)); if (!last) { tmp = tmp | IP_MF; } /* Fill this fragment */ cop = last ? left : nfb * 8; #if IP_FRAG_USES_STATIC_BUF poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); #else /* IP_FRAG_USES_STATIC_BUF */ #if LWIP_NETIF_TX_SINGLE_PBUF rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); /* make room for the IP header */ if(pbuf_header(rambuf, IP_HLEN)) { pbuf_free(rambuf); return ERR_MEM; } /* fill in the IP header */ SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = rambuf->payload; #else /* LWIP_NETIF_TX_SINGLE_PBUF */ /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link and IP header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, * but limited to the size of an mtu. */ rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP_HLEN))); SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = (struct ip_hdr *)rambuf->payload; /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; p->len -= poff; left_to_copy = cop; while (left_to_copy) { struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } pcr = ip_frag_alloc_pbuf_custom_ref(); if (pcr == NULL) { pbuf_free(rambuf); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); if (newpbuf == NULL) { ip_frag_free_pbuf_custom_ref(pcr); pbuf_free(rambuf); return ERR_MEM; } pbuf_ref(p); pcr->original = p; pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; if (left_to_copy) { p = p->next; } } poff = newpbuflen; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /* Correct header */ IPH_OFFSET_SET(iphdr, htons(tmp)); IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); IPH_CHKSUM_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #if IP_FRAG_USES_STATIC_BUF if (last) { pbuf_realloc(rambuf, left + IP_HLEN); } /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then * free it.A PBUF_ROM style pbuf for which pbuf_header * worked would make things simpler. */ header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); if (header != NULL) { pbuf_chain(header, rambuf); netif->output(netif, header, dest); IPFRAG_STATS_INC(ip_frag.xmit); snmp_inc_ipfragcreates(); pbuf_free(header); } else { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); pbuf_free(rambuf); return ERR_MEM; } #else /* IP_FRAG_USES_STATIC_BUF */ /* No need for separate header pbuf - we allowed room for it in rambuf * when allocated. */ netif->output(netif, rambuf, dest); IPFRAG_STATS_INC(ip_frag.xmit); /* Unfortunately we can't reuse rambuf - the hardware may still be * using the buffer. Instead we free it (and the ensuing chain) and * recreate it next time round the loop. If we're lucky the hardware * will have already sent the packet, the free will really free, and * there will be zero memory penalty. */ pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ left -= cop; ofo += nfb; } #if IP_FRAG_USES_STATIC_BUF pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ snmp_inc_ipfragoks(); return ERR_OK; }
/** * @ingroup pbuf * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * * 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 layer header size * @param length size of the pbuf's payload * @param type this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. 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: no buffer memory is allocated for the pbuf, even for * protocol headers. 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. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p; u16_t offset = (u16_t)layer; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); switch (type) { case PBUF_REF: /* fall through */ case PBUF_ROM: p = pbuf_alloc_reference(NULL, length, type); break; case PBUF_POOL: { struct pbuf *q, *last; u16_t rem_len; /* remaining length */ p = NULL; last = NULL; rem_len = length; do { u16_t qlen; 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; } qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), rem_len, qlen, type, 0); 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 = (u16_t)(rem_len - qlen); offset = 0; } while (rem_len > 0); break; } case PBUF_RAM: { u16_t payload_len = (u16_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length)); mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len); /* bug #50040: Check for integer overflow when calculating alloc_len */ if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) || (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) { return NULL; } /* 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, 0); LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); break; } default: LWIP_ASSERT("pbuf_alloc: erroneous type", 0); return NULL; } LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); return p; }
/** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * * 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 layer flag to define header size * @param length size of the pbuf's payload * @param type this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. 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: no buffer memory is allocated for the pbuf, even for * protocol headers. 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. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ offset = 0; switch (layer) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset += PBUF_TRANSPORT_HLEN; /* FALLTHROUGH */ case PBUF_IP: /* add room for IP layer header */ offset += PBUF_IP_HLEN; /* FALLTHROUGH */ case PBUF_LINK: /* add room for link layer header */ offset += PBUF_LINK_HLEN; #ifdef PBUF_RSV_FOR_WLAN /* * 1. LINK_HLEN 14Byte will be remove in WLAN layer * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes. * 3. encryption needs exra 4 bytes ahead of actual data payload, and require * DAddr and SAddr to be 4-byte aligned. * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice... * 5. LCC add 6 bytes more, We don't consider WAPI yet... * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be * matter is ether_hdr is not 4B aligned. * * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned * * 1. lwip * | empty 30B | eth_hdr (14B) | payload ...| * total: 44B ahead payload * 2. net80211 * | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...| * total: 40B ahead sec_rsv and 44B ahead payload * */ offset += EP_OFFSET; //remove LINK hdr in wlan #endif /* PBUF_RSV_FOR_WLAN */ break; case PBUF_RAW: #ifdef PBUF_RSV_FOR_WLAN /* * RAW pbuf suppose */ offset += EP_OFFSET; //remove LINK hdr in wlan #endif /* PBUF_RAW */ break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } 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; /* 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 unsuccesfully */ return NULL; } 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; } /* end of chain */ /*r->next = NULL;*/ break; case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); 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; p->eb = NULL; LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); break; #ifdef EBUF_LWIP case PBUF_ESF_RX: #endif /* ESF_LWIP */ /* 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; }
/* layer是pbuf_layer类型,预留不同的首部空间。可以是 * PBUF_TRANSPORT, * PBUF_IP, * PBUF_LINK, * PBUF_RAW * length是要申请的数据区长度 * type是要申请的pbuf类型,可以是 * PBUF_RAM * PBUF_ROM * PBUF_REF * PBUF_POOL */ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ offset = 0; /* 根据申请层次不同,选择不同的预留空间 */ switch (layer) { /* 传输层预留TCP首部空间,注意这里没有break;,继续累加 */ case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset += PBUF_TRANSPORT_HLEN; /* FALLTHROUGH */ /* 预留网络层首部空间 */ case PBUF_IP: /* add room for IP layer header */ offset += PBUF_IP_HLEN; /* FALLTHROUGH */ /* 预留链路层首部空间 */ case PBUF_LINK: /* add room for link layer header */ offset += PBUF_LINK_HLEN; break; /* 不预留首部空间 */ case PBUF_RAW: break; /* 层次参数错误,返回错误信息 */ default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } /* 根据要申请的type,分配具体类型的pbuf */ switch (type) { /* 在内存池分配pbuf和数据区 * PBUF_POOL类型可能需要分配多个MEMP_PBUF_POOL,以满足申请的空间 */ case PBUF_POOL: /* allocate head of pbuf chain into p */ /* MEMP_PBUF_POOL申请的大小是pbuf结构+PBUF_POOL_BUFSIZE。 * PBUF_POOL_BUFSIZE是1460(TCP的MSS)+20+20+14=1514, */ p = memp_malloc(MEMP_PBUF_POOL); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); /* 分配失败,则返回NULL */ if (p == NULL) { PBUF_POOL_IS_EMPTY(); return NULL; } /* 初始化type和next字段 */ p->type = type; p->next = NULL; /* make the payload pointer point 'offset' bytes into pbuf data memory */ /* 设置数据字段指针,预留出pbuf和offset大小 */ 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 */ /* 设置pbuf链表第一个pbuf中的tot_len字段 */ p->tot_len = length; /* set the length of the first pbuf in the chain */ /* 第一个pbuf中的数据段长度是PBUF_POOL_BUFSIZE(1514) - 预留大小 */ 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) */ /* 引用次数设为1 */ p->ref = 1; /* now allocate the tail of the pbuf chain */ /* 检查分配的第一个pbuf空间是否满足申请的length,不满足则继续申请,构造 * pbuf链表 */ /* remember first pbuf for linkage in next iteration */ /* r是pbuf上最后一个节点指针,用于把新节点放入链表 * p是pbuf链表头节点指针 */ r = p; /* remaining length to be allocated */ /* 还需申请的空间 */ rem_len = length - p->len; /* any remaining pbufs to be allocated? */ /* 仍然需要申请 */ while (rem_len > 0) { /* 申请新的pbuf,包括pbuf结构大小+1514 */ q = memp_malloc(MEMP_PBUF_POOL); /* 申请失败,则释放pbuf链表所有节点 */ if (q == NULL) { PBUF_POOL_IS_EMPTY(); /* free chain so far allocated */ pbuf_free(p); /* bail out unsuccesfully */ return NULL; } /* 设置新申请节点的类型 */ q->type = type; q->flags = 0; /* 新节点next指针设为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 */ /* 新节点本身数据段长度 * 新节点数据段可承载的最大长度可能大于要申请的长度, * 所以len要设置为实际申请的长度和最大长度的最小值 */ 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 */ /* 保存pbuf最后一个节点指针 */ r = q; } /* end of chain */ /*r->next = NULL;*/ break; /* 在内存堆分配pbuf结构和数据区域 */ case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ /* 申请总大小是pbuf结构大小+offset+数据区域大小 */ p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); if (p == NULL) { /* 申请失败,则返回NULL */ return NULL; } /* Set up internal structure of the pbuf. */ /* 设置pbuf的数据区指针 */ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); /* 从内存堆分配的pbuf只需要一个,不需要链表。因为第一个节点就可以获得要申请的数据区长度 * 数据区总长度 */ 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? */ /* PBUF_ROM和PBUF_REF类型,只分配PBUF结构,payload指向的数据区不需申请 */ case PBUF_ROM: /* pbuf references existing (externally allocated) RAM payload? */ case PBUF_REF: /* only allocate memory for the pbuf structure */ /* 从内存池中申请MEMP_PBUF类型的内存,详见memp_std.h */ p = memp_malloc(MEMP_PBUF); /* 申请失败,则返回NULL */ 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; } /* 设置pbuf结构字段 */ /* caller must set this field properly, afterwards */ /* PBUF_ROM和PBUF_REF类型的pbuf,必须由调用者设置payload字段 */ 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 */ /* 除了PBUF_POOL类型,都没有设置ref。在这里同一设置ref */ 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; }
/** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * * 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 layer flag to define header size * @param length size of the pbuf's payload * @param type this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. 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: no buffer memory is allocated for the pbuf, even for * protocol headers. 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. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type) { struct pbuf *p, *q, *r; uint16_t offset; int32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%" U16_F ")\n", length)); /* determine header offset */ switch (layer) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_HLEN; break; case PBUF_RAW: offset = 0; break; default: return NULL; } 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; /* make the payload pointer point 'offset' bytes into pbuf data memory */ p->payload = LWIP_MEM_ALIGN((void *)((uint8_t *) p + (SIZEOF_STRUCT_PBUF + offset))); /* 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)); /* 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 unsuccesfully */ return NULL; } 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 */ q->tot_len = (uint16_t) rem_len; /* this pbuf length is pool size, unless smaller sized tail */ q->len = LWIP_MIN((uint16_t) rem_len, PBUF_POOL_BUFSIZE_ALIGNED); q->payload = (void *)((uint8_t *) q + SIZEOF_STRUCT_PBUF); q->ref = 1; /* calculate remaining length to be allocated */ rem_len -= q->len; /* remember this pbuf for linkage in next iteration */ r = q; } /* end of chain */ /*r->next = NULL; */ break; case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf *)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); if (p == NULL) { return NULL; } /* Set up internal structure of the pbuf. */ p->payload = LWIP_MEM_ALIGN((void *)((uint8_t *) p + SIZEOF_STRUCT_PBUF + offset)); p->len = p->tot_len = length; p->next = NULL; p->type = type; 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: 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; }