Esempio n. 1
0
/**
 * Allocates a pbuf.
 *
 * 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 flag 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 l, u16_t length, pbuf_flag flag)
{
  struct pbuf *p, *q, *r;
  u16_t offset;
  s32_t rem_len; /* remaining length */
  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u)\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_alloc: bad pbuf layer", 0);
    return NULL;
  }

  switch (flag) {
  case PBUF_POOL:
    /* allocate head of pbuf chain into p */
    p = pbuf_pool_alloc();
    LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
    if (p == NULL) {
#if PBUF_STATS
      ++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
      return NULL;
    }
    p->next = NULL;

    /* make the payload pointer point 'offset' bytes into pbuf data memory */
    p->payload = 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 = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;
    /* 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 = pbuf_pool_alloc();
      if (q == NULL) {
       LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
#if PBUF_STATS
        ++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
        /* free chain so far allocated */
        pbuf_free(p);
        /* bail out unsuccesfully */
        return NULL;
      }
      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 = rem_len;
      /* this pbuf length is pool size, unless smaller sized tail */
      q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
      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);
      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 = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));
    if (p == NULL) {
      return NULL;
    }
    /* Set up internal structure of the pbuf. */
    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
    p->len = p->tot_len = length;
    p->next = NULL;
    p->flags = PBUF_FLAG_RAM;

    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
    break;
  /* pbuf references existing (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 = memp_malloc(MEMP_PBUF);
    if (p == NULL) {
      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == 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->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);
    break;
  default:
    LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);
    return NULL;
  }
  /* set reference count */
  p->ref = 1;
  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u) == %p\n", length, (void *)p));
  return p;
}
Esempio n. 2
0
/*-----------------------------------------------------------------------------------*/
struct pbuf *
pbuf_alloc(pbuf_layer l, uint16_t size, pbuf_flag flag)
{
  struct pbuf *p, *q, *r;
  uint16_t offset;
  int32_t rsize;

  offset = 0;
  switch(l) {
	  case PBUF_TRANSPORT:
		  offset += PBUF_TRANSPORT_HLEN;
		  /* FALLTHROUGH */
	  case PBUF_IP:
		  offset += PBUF_IP_HLEN;
		  offset += PBUF_LINK_HLEN;
		  /* FALLTHROUGH */
	  case PBUF_LINK:
		  break;
	  case PBUF_RAW:
		  break;
	  default:
		  ASSERT("pbuf_alloc: bad pbuf layer", 0);
		  return NULL;
  }

  switch(flag)
  {
	  case PBUF_POOL:
		  /* Allocate head of pbuf chain into p. */
		  p = pbuf_pool_alloc();
		  if(p == NULL) {
#ifdef PBUF_STATS
			  ++stats.pbuf.err;
#endif /* PBUF_STATS */
			  return NULL;
		  }
		  p->next = NULL;

		  /* Set the payload pointer so that it points offset bytes into
			 pbuf data memory. */
		  p->payload = MEM_ALIGN((void *)((uint8_t *)p + (sizeof(struct pbuf) + offset)));

		  /* The total length of the pbuf is the requested size. */
		  p->tot_len = size;

		  /* Set the length of the first pbuf is the chain. */
		  p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size;

		  p->flags = PBUF_FLAG_POOL;

		  /* Allocate the tail of the pbuf chain. */
		  r = p;
		  rsize = size - p->len;
		  while(rsize > 0) {
			  q = pbuf_pool_alloc();
			  if(q == NULL) {
				  DEBUGF(PBUF_DEBUG, ("pbuf_alloc: Out of pbufs in pool,\n"));
#ifdef PBUF_STATS
				  ++stats.pbuf.err;
#endif /* PBUF_STATS */
				  pbuf_pool_free(p);
				  return NULL;
			  }
			  q->next = NULL;
			  r->next = q;
			  q->len = rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize;
			  q->flags = PBUF_FLAG_POOL;
			  q->payload = (void *)((uint8_t *)q + sizeof(struct pbuf));
			  r = q;
			  q->ref = 1;
			  q = q->next;
			  rsize -= PBUF_POOL_BUFSIZE;
		  }
		  r->next = NULL;

		  ASSERT("pbuf_alloc: pbuf->payload properly aligned",
				  ((uint32_t)p->payload % MEM_ALIGNMENT) == 0);
		  break;
	  case PBUF_RAM:
		  /* If pbuf is to be allocated in RAM, allocate memory for it. */
		  p = (struct pbuf*)mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset));
		  if(p == NULL)
		  { return NULL; }

		  /* Set up internal structure of the pbuf. */
		  p->payload = MEM_ALIGN((void *)((uint8_t *)p + sizeof(struct pbuf) + offset));
		  p->len = p->tot_len = size;
		  p->next = NULL;
		  p->flags = PBUF_FLAG_RAM;

		  ASSERT("pbuf_alloc: pbuf->payload properly aligned",
				  ((uint32_t)p->payload % MEM_ALIGNMENT) == 0);
		  break;
	  case PBUF_ROM:
		  /* If the pbuf should point to ROM, we only need to allocate
			 memory for the pbuf structure. */
		  p = (struct pbuf*)memp_mallocp(MEMP_PBUF);
		  if(p == NULL) {
			  return NULL;
		  }
		  p->payload = NULL;
		  p->len = p->tot_len = size;
		  p->next = NULL;
		  p->flags = PBUF_FLAG_ROM;
		  break;
	  default:
		  ASSERT("pbuf_alloc: erroneous flag", 0);
		  return NULL;
  }
  p->ref = 1;
  return p;
}