* @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
| 221 | * is the first pbuf of a pbuf chain. |
| 222 | */ |
| 223 | struct pbuf * |
| 224 | pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) |
| 225 | { |
| 226 | struct pbuf *p; |
| 227 | u16_t offset = (u16_t)layer; |
| 228 | LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); |
| 229 | |
| 230 | switch (type) { |
| 231 | case PBUF_REF: /* fall through */ |
| 232 | case PBUF_ROM: |
| 233 | p = pbuf_alloc_reference(NULL, length, type); |
| 234 | break; |
| 235 | case PBUF_POOL: { |
| 236 | struct pbuf *q, *last; |
| 237 | u16_t rem_len; /* remaining length */ |
| 238 | p = NULL; |
| 239 | last = NULL; |
| 240 | rem_len = length; |
| 241 | do { |
| 242 | u16_t qlen; |
| 243 | q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); |
| 244 | if (q == NULL) { |
| 245 | PBUF_POOL_IS_EMPTY(); |
| 246 | /* free chain so far allocated */ |
| 247 | if (p) { |
| 248 | pbuf_free(p); |
| 249 | } |
| 250 | /* bail out unsuccessfully */ |
| 251 | return NULL; |
| 252 | } |
| 253 | qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); |
| 254 | pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), |
| 255 | rem_len, qlen, type, 0); |
| 256 | LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", |
| 257 | ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); |
| 258 | LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", |
| 259 | (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); |
| 260 | if (p == NULL) { |
| 261 | /* allocated head of pbuf chain (into p) */ |
| 262 | p = q; |
| 263 | } else { |
| 264 | /* make previous pbuf point to this pbuf */ |
| 265 | last->next = q; |
| 266 | } |
| 267 | last = q; |
| 268 | rem_len = (u16_t)(rem_len - qlen); |
| 269 | offset = 0; |
| 270 | } while (rem_len > 0); |
| 271 | break; |
| 272 | } |
| 273 | case PBUF_RAM: { |
| 274 | u16_t payload_len = (u16_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length)); |
| 275 | mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len); |
| 276 | |
| 277 | /* bug #50040: Check for integer overflow when calculating alloc_len */ |
| 278 | if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) || |
| 279 | (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) { |
| 280 | return NULL; |