private static pbuf tcp_pbuf_prealloc(pbuf_layer layer, ushort length, ushort mx, out ushort os, tcp_pcb pcb, byte api, byte fst) { os = 0; return lwip.pbuf_alloc(layer, length, pbuf_type.PBUF_RAM); }
/** * Creates a single pbuf out of a queue of pbufs. * * @remark: Either the source pbuf 'p' is freed by this function or the original * pbuf 'p' is returned, therefore the caller has to check the result! * * @param p the source pbuf * @param layer pbuf_layer of the new pbuf * * @return a new, single pbuf (p.next is null) * or the old pbuf if allocation fails */ public pbuf pbuf_coalesce(pbuf p, pbuf_layer layer) { pbuf q; err_t err; if (p.next == null) { return p; } q = pbuf_alloc(layer, p.tot_len, pbuf_type.PBUF_RAM); if (q == null) { /* @todo: what do we do now? */ return p; } err = pbuf_copy(q, p); lwip.LWIP_ASSERT("pbuf_copy failed", err == err_t.ERR_OK); pbuf_free(p); return q; }
/** * Allocate a pbuf_type.PBUF_RAM pbuf, perhaps with extra space at the end. * * This function is like lwip.pbuf_alloc(layer, length, pbuf_type.PBUF_RAM) except * there may be extra bytes available at the end. * * @param layer flag to define header size. * @param length size of the pbuf's payload. * @param max_length maximum usable size of payload+oversize. * @param oversize pointer to a ushort that will receive the number of usable tail bytes. * @param pcb The TCP connection that willo enqueue the pbuf. * @param apiflags API flags given to tcp_write. * @param first_seg true when this pbuf will be used in the first enqueued segment. * @param */ private pbuf tcp_pbuf_prealloc(pbuf_layer layer, ushort length, ushort max_length, ref ushort oversize, tcp_pcb pcb, byte apiflags, byte first_seg) { pbuf p; ushort alloc = length; #if LWIP_NETIF_TX_SINGLE_PBUF //LWIP_UNUSED_ARG(max_length); //LWIP_UNUSED_ARG(pcb); //LWIP_UNUSED_ARG(apiflags); //LWIP_UNUSED_ARG(first_seg); /* always create MSS-sized pbufs */ alloc = max_length; #else // LWIP_NETIF_TX_SINGLE_PBUF if (length < max_length) { /* Should we allocate an oversized pbuf, or just the minimum * length required? If tcp_write is going to be called again * before this segment is transmitted, we want the oversized * buffer. If the segment will be transmitted immediately, we can * save memory by allocating only length. We use a simple * heuristic based on the following information: * * Did the user set TCP_WRITE_FLAG_MORE? * * Will the Nagle algorithm defer transmission of this segment? */ if ((apiflags & tcp.TCP_WRITE_FLAG_MORE) != 0 || ((pcb.flags & tcp_pcb.TF_NODELAY) == 0 && (first_seg == 0 || pcb.unsent != null || pcb.unacked != null))) { alloc = (ushort)Math.Min(max_length, lwip.LWIP_MEM_ALIGN_SIZE(length + opt.TCP_OVERSIZE)); } } #endif // LWIP_NETIF_TX_SINGLE_PBUF p = lwip.pbuf_alloc(layer, alloc, pbuf_type.PBUF_RAM); if (p == null) { return null; } lwip.LWIP_ASSERT("need unchained pbuf", p.next == null); oversize = (ushort)(p.len - length); /* trim p.len to the currently used size */ p.len = p.tot_len = length; return p; }
/** * Allocates a pbuf of the given type (possibly a chain for pbuf_type.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_type.PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - pbuf_type.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_type.PBUF_ROM pbufs. Use pbuf_type.PBUF_REF instead. * - pbuf_type.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_type.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. */ public pbuf pbuf_alloc(pbuf_layer layer, ushort length, pbuf_type type) { pbuf p, q, r; ushort offset; int rem_len; /* remaining length */ lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc(length={0})\n", length); /* determine header offset */ switch (layer) { case pbuf_layer.PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset = opt.PBUF_LINK_HLEN + pbuf.PBUF_IP_HLEN + pbuf.PBUF_TRANSPORT_HLEN; break; case pbuf_layer.PBUF_IP: /* add room for IP layer header */ offset = opt.PBUF_LINK_HLEN + pbuf.PBUF_IP_HLEN; break; case pbuf_layer.PBUF_LINK: /* add room for link layer header */ offset = opt.PBUF_LINK_HLEN; break; case pbuf_layer.PBUF_RAW: offset = 0; break; default: lwip.LWIP_ASSERT("pbuf_alloc: bad pbuf layer", false); return null; } switch (type) { case pbuf_type.PBUF_POOL: /* allocate head of pbuf chain into p */ p = new pbuf(this, memp_malloc(mempb_t.MEMP_PBUF_POOL)); lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc: allocated pbuf {0}\n", 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.LWIP_MEM_ALIGN((p + (pbuf.SIZEOF_STRUCT_PBUF + offset))); lwip.LWIP_ASSERT("pbuf_alloc: pbuf p.payload properly aligned", (p.payload.offset % opt.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 = Math.Min(length, (ushort)(pbuf.PBUF_POOL_BUFSIZE_ALIGNED - lwip.LWIP_MEM_ALIGN_SIZE(offset))); lwip.LWIP_ASSERT("check p.payload + p.len does not overflow pbuf", (p.payload + p.len <= p + pbuf.SIZEOF_STRUCT_PBUF + pbuf.PBUF_POOL_BUFSIZE_ALIGNED)); lwip.LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than opt.MEM_ALIGNMENT", (pbuf.PBUF_POOL_BUFSIZE_ALIGNED - lwip.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 = new pbuf(this, memp_malloc(mempb_t.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.LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); q.tot_len = (ushort)rem_len; /* this pbuf length is pool size, unless smaller sized tail */ q.len = Math.Min((ushort)rem_len, (ushort)pbuf.PBUF_POOL_BUFSIZE_ALIGNED); q.payload = (q + pbuf.SIZEOF_STRUCT_PBUF); lwip.LWIP_ASSERT("pbuf_alloc: pbuf q.payload properly aligned", (q.payload.offset % opt.MEM_ALIGNMENT) == 0); lwip.LWIP_ASSERT("check p.payload + p.len does not overflow pbuf", (p.payload + p.len <= p + pbuf.SIZEOF_STRUCT_PBUF + 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_type.PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = new pbuf(this, mem_malloc(lwip.LWIP_MEM_ALIGN_SIZE((ushort)(pbuf.SIZEOF_STRUCT_PBUF + offset)) + lwip.LWIP_MEM_ALIGN_SIZE(length))); if (p == null) { return null; } /* Set up internal structure of the pbuf. */ p.payload = lwip.LWIP_MEM_ALIGN((p + pbuf.SIZEOF_STRUCT_PBUF + offset)); p.len = p.tot_len = length; p.next = null; p.type = type; lwip.LWIP_ASSERT("pbuf_alloc: pbuf.payload properly aligned", (p.payload.offset % opt.MEM_ALIGNMENT) == 0); break; /* pbuf references existing (non-volatile static constant) ROM payload? */ case pbuf_type.PBUF_ROM: /* pbuf references existing (externally allocated) RAM payload? */ case pbuf_type.PBUF_REF: /* only allocate memory for the pbuf structure */ p = new pbuf(this, memp_malloc(mempb_t.MEMP_PBUF)); if (p == null) { lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_LEVEL_SERIOUS, "pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_{0}.\n", (type == pbuf_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.LWIP_ASSERT("pbuf_alloc: erroneous type", false); return null; } /* set reference count */ p.@ref = 1; /* set flags */ p.flags = 0; lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc(length={0}) == {1}\n", length, p); return p; }