My fork of the HTTPServer (working)

Dependents:   DGWWebServer LAN2

Committer:
screamer
Date:
Mon Aug 06 09:23:14 2012 +0000
Revision:
0:7a64fbb4069d
[mbed] converted /DGWWebServer/HTTPServer

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:7a64fbb4069d 1 /**
screamer 0:7a64fbb4069d 2 * @file
screamer 0:7a64fbb4069d 3 * Packet buffer management
screamer 0:7a64fbb4069d 4 *
screamer 0:7a64fbb4069d 5 * Packets are built from the pbuf data structure. It supports dynamic
screamer 0:7a64fbb4069d 6 * memory allocation for packet contents or can reference externally
screamer 0:7a64fbb4069d 7 * managed packet contents both in RAM and ROM. Quick allocation for
screamer 0:7a64fbb4069d 8 * incoming packets is provided through pools with fixed sized pbufs.
screamer 0:7a64fbb4069d 9 *
screamer 0:7a64fbb4069d 10 * A packet may span over multiple pbufs, chained as a singly linked
screamer 0:7a64fbb4069d 11 * list. This is called a "pbuf chain".
screamer 0:7a64fbb4069d 12 *
screamer 0:7a64fbb4069d 13 * Multiple packets may be queued, also using this singly linked list.
screamer 0:7a64fbb4069d 14 * This is called a "packet queue".
screamer 0:7a64fbb4069d 15 *
screamer 0:7a64fbb4069d 16 * So, a packet queue consists of one or more pbuf chains, each of
screamer 0:7a64fbb4069d 17 * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
screamer 0:7a64fbb4069d 18 * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
screamer 0:7a64fbb4069d 19 *
screamer 0:7a64fbb4069d 20 * The differences between a pbuf chain and a packet queue are very
screamer 0:7a64fbb4069d 21 * precise but subtle.
screamer 0:7a64fbb4069d 22 *
screamer 0:7a64fbb4069d 23 * The last pbuf of a packet has a ->tot_len field that equals the
screamer 0:7a64fbb4069d 24 * ->len field. It can be found by traversing the list. If the last
screamer 0:7a64fbb4069d 25 * pbuf of a packet has a ->next field other than NULL, more packets
screamer 0:7a64fbb4069d 26 * are on the queue.
screamer 0:7a64fbb4069d 27 *
screamer 0:7a64fbb4069d 28 * Therefore, looping through a pbuf of a single packet, has an
screamer 0:7a64fbb4069d 29 * loop end condition (tot_len == p->len), NOT (next == NULL).
screamer 0:7a64fbb4069d 30 */
screamer 0:7a64fbb4069d 31
screamer 0:7a64fbb4069d 32 /*
screamer 0:7a64fbb4069d 33 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
screamer 0:7a64fbb4069d 34 * All rights reserved.
screamer 0:7a64fbb4069d 35 *
screamer 0:7a64fbb4069d 36 * Redistribution and use in source and binary forms, with or without modification,
screamer 0:7a64fbb4069d 37 * are permitted provided that the following conditions are met:
screamer 0:7a64fbb4069d 38 *
screamer 0:7a64fbb4069d 39 * 1. Redistributions of source code must retain the above copyright notice,
screamer 0:7a64fbb4069d 40 * this list of conditions and the following disclaimer.
screamer 0:7a64fbb4069d 41 * 2. Redistributions in binary form must reproduce the above copyright notice,
screamer 0:7a64fbb4069d 42 * this list of conditions and the following disclaimer in the documentation
screamer 0:7a64fbb4069d 43 * and/or other materials provided with the distribution.
screamer 0:7a64fbb4069d 44 * 3. The name of the author may not be used to endorse or promote products
screamer 0:7a64fbb4069d 45 * derived from this software without specific prior written permission.
screamer 0:7a64fbb4069d 46 *
screamer 0:7a64fbb4069d 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
screamer 0:7a64fbb4069d 48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
screamer 0:7a64fbb4069d 49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
screamer 0:7a64fbb4069d 50 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
screamer 0:7a64fbb4069d 51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
screamer 0:7a64fbb4069d 52 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
screamer 0:7a64fbb4069d 53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
screamer 0:7a64fbb4069d 54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
screamer 0:7a64fbb4069d 55 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
screamer 0:7a64fbb4069d 56 * OF SUCH DAMAGE.
screamer 0:7a64fbb4069d 57 *
screamer 0:7a64fbb4069d 58 * This file is part of the lwIP TCP/IP stack.
screamer 0:7a64fbb4069d 59 *
screamer 0:7a64fbb4069d 60 * Author: Adam Dunkels <adam@sics.se>
screamer 0:7a64fbb4069d 61 *
screamer 0:7a64fbb4069d 62 */
screamer 0:7a64fbb4069d 63
screamer 0:7a64fbb4069d 64 #include "lwip/opt.h"
screamer 0:7a64fbb4069d 65
screamer 0:7a64fbb4069d 66 #include "lwip/stats.h"
screamer 0:7a64fbb4069d 67 #include "lwip/def.h"
screamer 0:7a64fbb4069d 68 #include "lwip/mem.h"
screamer 0:7a64fbb4069d 69 #include "lwip/memp.h"
screamer 0:7a64fbb4069d 70 #include "lwip/pbuf.h"
screamer 0:7a64fbb4069d 71 #include "lwip/sys.h"
screamer 0:7a64fbb4069d 72 #include "arch/perf.h"
screamer 0:7a64fbb4069d 73 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 74 #include "lwip/tcp.h"
screamer 0:7a64fbb4069d 75 #endif
screamer 0:7a64fbb4069d 76
screamer 0:7a64fbb4069d 77 #include <string.h>
screamer 0:7a64fbb4069d 78
screamer 0:7a64fbb4069d 79 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
screamer 0:7a64fbb4069d 80 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
screamer 0:7a64fbb4069d 81 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
screamer 0:7a64fbb4069d 82 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
screamer 0:7a64fbb4069d 83
screamer 0:7a64fbb4069d 84 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 85 #define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0)
screamer 0:7a64fbb4069d 86 #else
screamer 0:7a64fbb4069d 87 #define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0)
screamer 0:7a64fbb4069d 88 #endif
screamer 0:7a64fbb4069d 89
screamer 0:7a64fbb4069d 90
screamer 0:7a64fbb4069d 91 #if TCP_QUEUE_OOSEQ
screamer 0:7a64fbb4069d 92 /**
screamer 0:7a64fbb4069d 93 * Attempt to reclaim some memory from queued out-of-sequence TCP segments
screamer 0:7a64fbb4069d 94 * if we run out of pool pbufs. It's better to give priority to new packets
screamer 0:7a64fbb4069d 95 * if we're running out.
screamer 0:7a64fbb4069d 96 *
screamer 0:7a64fbb4069d 97 * @return the allocated pbuf.
screamer 0:7a64fbb4069d 98 */
screamer 0:7a64fbb4069d 99 static struct pbuf *
screamer 0:7a64fbb4069d 100 alloc_pool_pbuf(void)
screamer 0:7a64fbb4069d 101 {
screamer 0:7a64fbb4069d 102 struct tcp_pcb *pcb;
screamer 0:7a64fbb4069d 103 struct pbuf *p;
screamer 0:7a64fbb4069d 104
screamer 0:7a64fbb4069d 105 retry:
screamer 0:7a64fbb4069d 106 p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
screamer 0:7a64fbb4069d 107 if (NULL == p) {
screamer 0:7a64fbb4069d 108 for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
screamer 0:7a64fbb4069d 109 if (NULL != pcb->ooseq) {
screamer 0:7a64fbb4069d 110 tcp_segs_free(pcb->ooseq);
screamer 0:7a64fbb4069d 111 pcb->ooseq = NULL;
screamer 0:7a64fbb4069d 112 goto retry;
screamer 0:7a64fbb4069d 113 }
screamer 0:7a64fbb4069d 114 }
screamer 0:7a64fbb4069d 115 }
screamer 0:7a64fbb4069d 116 return p;
screamer 0:7a64fbb4069d 117 }
screamer 0:7a64fbb4069d 118 #endif /* TCP_QUEUE_OOSEQ */
screamer 0:7a64fbb4069d 119
screamer 0:7a64fbb4069d 120 /**
screamer 0:7a64fbb4069d 121 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
screamer 0:7a64fbb4069d 122 *
screamer 0:7a64fbb4069d 123 * The actual memory allocated for the pbuf is determined by the
screamer 0:7a64fbb4069d 124 * layer at which the pbuf is allocated and the requested size
screamer 0:7a64fbb4069d 125 * (from the size parameter).
screamer 0:7a64fbb4069d 126 *
screamer 0:7a64fbb4069d 127 * @param layer flag to define header size
screamer 0:7a64fbb4069d 128 * @param length size of the pbuf's payload
screamer 0:7a64fbb4069d 129 * @param type this parameter decides how and where the pbuf
screamer 0:7a64fbb4069d 130 * should be allocated as follows:
screamer 0:7a64fbb4069d 131 *
screamer 0:7a64fbb4069d 132 * - PBUF_RAM: buffer memory for pbuf is allocated as one large
screamer 0:7a64fbb4069d 133 * chunk. This includes protocol headers as well.
screamer 0:7a64fbb4069d 134 * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
screamer 0:7a64fbb4069d 135 * protocol headers. Additional headers must be prepended
screamer 0:7a64fbb4069d 136 * by allocating another pbuf and chain in to the front of
screamer 0:7a64fbb4069d 137 * the ROM pbuf. It is assumed that the memory used is really
screamer 0:7a64fbb4069d 138 * similar to ROM in that it is immutable and will not be
screamer 0:7a64fbb4069d 139 * changed. Memory which is dynamic should generally not
screamer 0:7a64fbb4069d 140 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
screamer 0:7a64fbb4069d 141 * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
screamer 0:7a64fbb4069d 142 * protocol headers. It is assumed that the pbuf is only
screamer 0:7a64fbb4069d 143 * being used in a single thread. If the pbuf gets queued,
screamer 0:7a64fbb4069d 144 * then pbuf_take should be called to copy the buffer.
screamer 0:7a64fbb4069d 145 * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
screamer 0:7a64fbb4069d 146 * the pbuf pool that is allocated during pbuf_init().
screamer 0:7a64fbb4069d 147 *
screamer 0:7a64fbb4069d 148 * @return the allocated pbuf. If multiple pbufs where allocated, this
screamer 0:7a64fbb4069d 149 * is the first pbuf of a pbuf chain.
screamer 0:7a64fbb4069d 150 */
screamer 0:7a64fbb4069d 151 struct pbuf *
screamer 0:7a64fbb4069d 152 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
screamer 0:7a64fbb4069d 153 {
screamer 0:7a64fbb4069d 154 struct pbuf *p, *q, *r;
screamer 0:7a64fbb4069d 155 u16_t offset;
screamer 0:7a64fbb4069d 156 s32_t rem_len; /* remaining length */
screamer 0:7a64fbb4069d 157 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
screamer 0:7a64fbb4069d 158
screamer 0:7a64fbb4069d 159 /* determine header offset */
screamer 0:7a64fbb4069d 160 offset = 0;
screamer 0:7a64fbb4069d 161 switch (layer) {
screamer 0:7a64fbb4069d 162 case PBUF_TRANSPORT:
screamer 0:7a64fbb4069d 163 /* add room for transport (often TCP) layer header */
screamer 0:7a64fbb4069d 164 offset += PBUF_TRANSPORT_HLEN;
screamer 0:7a64fbb4069d 165 /* FALLTHROUGH */
screamer 0:7a64fbb4069d 166 case PBUF_IP:
screamer 0:7a64fbb4069d 167 /* add room for IP layer header */
screamer 0:7a64fbb4069d 168 offset += PBUF_IP_HLEN;
screamer 0:7a64fbb4069d 169 /* FALLTHROUGH */
screamer 0:7a64fbb4069d 170 case PBUF_LINK:
screamer 0:7a64fbb4069d 171 /* add room for link layer header */
screamer 0:7a64fbb4069d 172 offset += PBUF_LINK_HLEN;
screamer 0:7a64fbb4069d 173 break;
screamer 0:7a64fbb4069d 174 case PBUF_RAW:
screamer 0:7a64fbb4069d 175 break;
screamer 0:7a64fbb4069d 176 default:
screamer 0:7a64fbb4069d 177 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
screamer 0:7a64fbb4069d 178 return NULL;
screamer 0:7a64fbb4069d 179 }
screamer 0:7a64fbb4069d 180
screamer 0:7a64fbb4069d 181 switch (type) {
screamer 0:7a64fbb4069d 182 case PBUF_POOL:
screamer 0:7a64fbb4069d 183 /* allocate head of pbuf chain into p */
screamer 0:7a64fbb4069d 184 ALLOC_POOL_PBUF(p);
screamer 0:7a64fbb4069d 185 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
screamer 0:7a64fbb4069d 186 if (p == NULL) {
screamer 0:7a64fbb4069d 187 return NULL;
screamer 0:7a64fbb4069d 188 }
screamer 0:7a64fbb4069d 189 p->type = type;
screamer 0:7a64fbb4069d 190 p->next = NULL;
screamer 0:7a64fbb4069d 191
screamer 0:7a64fbb4069d 192 /* make the payload pointer point 'offset' bytes into pbuf data memory */
screamer 0:7a64fbb4069d 193 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
screamer 0:7a64fbb4069d 194 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
screamer 0:7a64fbb4069d 195 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
screamer 0:7a64fbb4069d 196 /* the total length of the pbuf chain is the requested size */
screamer 0:7a64fbb4069d 197 p->tot_len = length;
screamer 0:7a64fbb4069d 198 /* set the length of the first pbuf in the chain */
screamer 0:7a64fbb4069d 199 p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
screamer 0:7a64fbb4069d 200 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
screamer 0:7a64fbb4069d 201 ((u8_t*)p->payload + p->len <=
screamer 0:7a64fbb4069d 202 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
screamer 0:7a64fbb4069d 203 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", p->len != 0);
screamer 0:7a64fbb4069d 204 /* set reference count (needed here in case we fail) */
screamer 0:7a64fbb4069d 205 p->ref = 1;
screamer 0:7a64fbb4069d 206
screamer 0:7a64fbb4069d 207 /* now allocate the tail of the pbuf chain */
screamer 0:7a64fbb4069d 208
screamer 0:7a64fbb4069d 209 /* remember first pbuf for linkage in next iteration */
screamer 0:7a64fbb4069d 210 r = p;
screamer 0:7a64fbb4069d 211 /* remaining length to be allocated */
screamer 0:7a64fbb4069d 212 rem_len = length - p->len;
screamer 0:7a64fbb4069d 213 /* any remaining pbufs to be allocated? */
screamer 0:7a64fbb4069d 214 while (rem_len > 0) {
screamer 0:7a64fbb4069d 215 ALLOC_POOL_PBUF(q);
screamer 0:7a64fbb4069d 216 if (q == NULL) {
screamer 0:7a64fbb4069d 217 /* free chain so far allocated */
screamer 0:7a64fbb4069d 218 pbuf_free(p);
screamer 0:7a64fbb4069d 219 /* bail out unsuccesfully */
screamer 0:7a64fbb4069d 220 return NULL;
screamer 0:7a64fbb4069d 221 }
screamer 0:7a64fbb4069d 222 q->type = type;
screamer 0:7a64fbb4069d 223 q->flags = 0;
screamer 0:7a64fbb4069d 224 q->next = NULL;
screamer 0:7a64fbb4069d 225 /* make previous pbuf point to this pbuf */
screamer 0:7a64fbb4069d 226 r->next = q;
screamer 0:7a64fbb4069d 227 /* set total length of this pbuf and next in chain */
screamer 0:7a64fbb4069d 228 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
screamer 0:7a64fbb4069d 229 q->tot_len = (u16_t)rem_len;
screamer 0:7a64fbb4069d 230 /* this pbuf length is pool size, unless smaller sized tail */
screamer 0:7a64fbb4069d 231 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
screamer 0:7a64fbb4069d 232 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
screamer 0:7a64fbb4069d 233 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
screamer 0:7a64fbb4069d 234 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
screamer 0:7a64fbb4069d 235 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
screamer 0:7a64fbb4069d 236 ((u8_t*)p->payload + p->len <=
screamer 0:7a64fbb4069d 237 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
screamer 0:7a64fbb4069d 238 q->ref = 1;
screamer 0:7a64fbb4069d 239 /* calculate remaining length to be allocated */
screamer 0:7a64fbb4069d 240 rem_len -= q->len;
screamer 0:7a64fbb4069d 241 /* remember this pbuf for linkage in next iteration */
screamer 0:7a64fbb4069d 242 r = q;
screamer 0:7a64fbb4069d 243 }
screamer 0:7a64fbb4069d 244 /* end of chain */
screamer 0:7a64fbb4069d 245 /*r->next = NULL;*/
screamer 0:7a64fbb4069d 246
screamer 0:7a64fbb4069d 247 break;
screamer 0:7a64fbb4069d 248 case PBUF_RAM:
screamer 0:7a64fbb4069d 249 /* If pbuf is to be allocated in RAM, allocate memory for it. */
screamer 0:7a64fbb4069d 250 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
screamer 0:7a64fbb4069d 251 if (p == NULL) {
screamer 0:7a64fbb4069d 252 return NULL;
screamer 0:7a64fbb4069d 253 }
screamer 0:7a64fbb4069d 254 /* Set up internal structure of the pbuf. */
screamer 0:7a64fbb4069d 255 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
screamer 0:7a64fbb4069d 256 p->len = p->tot_len = length;
screamer 0:7a64fbb4069d 257 p->next = NULL;
screamer 0:7a64fbb4069d 258 p->type = type;
screamer 0:7a64fbb4069d 259
screamer 0:7a64fbb4069d 260 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
screamer 0:7a64fbb4069d 261 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
screamer 0:7a64fbb4069d 262 break;
screamer 0:7a64fbb4069d 263 /* pbuf references existing (non-volatile static constant) ROM payload? */
screamer 0:7a64fbb4069d 264 case PBUF_ROM:
screamer 0:7a64fbb4069d 265 /* pbuf references existing (externally allocated) RAM payload? */
screamer 0:7a64fbb4069d 266 case PBUF_REF:
screamer 0:7a64fbb4069d 267 /* only allocate memory for the pbuf structure */
screamer 0:7a64fbb4069d 268 p = (struct pbuf *)(memp_malloc(MEMP_PBUF)); // static_cast<struct pbuf *>(x)
screamer 0:7a64fbb4069d 269 if (p == NULL) {
screamer 0:7a64fbb4069d 270 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
screamer 0:7a64fbb4069d 271 (type == PBUF_ROM) ? "ROM" : "REF"));
screamer 0:7a64fbb4069d 272 return NULL;
screamer 0:7a64fbb4069d 273 }
screamer 0:7a64fbb4069d 274 /* caller must set this field properly, afterwards */
screamer 0:7a64fbb4069d 275 p->payload = NULL;
screamer 0:7a64fbb4069d 276 p->len = p->tot_len = length;
screamer 0:7a64fbb4069d 277 p->next = NULL;
screamer 0:7a64fbb4069d 278 p->type = type;
screamer 0:7a64fbb4069d 279 break;
screamer 0:7a64fbb4069d 280 default:
screamer 0:7a64fbb4069d 281 LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
screamer 0:7a64fbb4069d 282 return NULL;
screamer 0:7a64fbb4069d 283 }
screamer 0:7a64fbb4069d 284 /* set reference count */
screamer 0:7a64fbb4069d 285 p->ref = 1;
screamer 0:7a64fbb4069d 286 /* set flags */
screamer 0:7a64fbb4069d 287 p->flags = 0;
screamer 0:7a64fbb4069d 288 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
screamer 0:7a64fbb4069d 289 return p;
screamer 0:7a64fbb4069d 290 }
screamer 0:7a64fbb4069d 291
screamer 0:7a64fbb4069d 292
screamer 0:7a64fbb4069d 293 /**
screamer 0:7a64fbb4069d 294 * Shrink a pbuf chain to a desired length.
screamer 0:7a64fbb4069d 295 *
screamer 0:7a64fbb4069d 296 * @param p pbuf to shrink.
screamer 0:7a64fbb4069d 297 * @param new_len desired new length of pbuf chain
screamer 0:7a64fbb4069d 298 *
screamer 0:7a64fbb4069d 299 * Depending on the desired length, the first few pbufs in a chain might
screamer 0:7a64fbb4069d 300 * be skipped and left unchanged. The new last pbuf in the chain will be
screamer 0:7a64fbb4069d 301 * resized, and any remaining pbufs will be freed.
screamer 0:7a64fbb4069d 302 *
screamer 0:7a64fbb4069d 303 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
screamer 0:7a64fbb4069d 304 * @note May not be called on a packet queue.
screamer 0:7a64fbb4069d 305 *
screamer 0:7a64fbb4069d 306 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
screamer 0:7a64fbb4069d 307 */
screamer 0:7a64fbb4069d 308 void
screamer 0:7a64fbb4069d 309 pbuf_realloc(struct pbuf *p, u16_t new_len)
screamer 0:7a64fbb4069d 310 {
screamer 0:7a64fbb4069d 311 struct pbuf *q;
screamer 0:7a64fbb4069d 312 u16_t rem_len; /* remaining length */
screamer 0:7a64fbb4069d 313 s32_t grow;
screamer 0:7a64fbb4069d 314
screamer 0:7a64fbb4069d 315 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
screamer 0:7a64fbb4069d 316 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
screamer 0:7a64fbb4069d 317 p->type == PBUF_ROM ||
screamer 0:7a64fbb4069d 318 p->type == PBUF_RAM ||
screamer 0:7a64fbb4069d 319 p->type == PBUF_REF);
screamer 0:7a64fbb4069d 320
screamer 0:7a64fbb4069d 321 /* desired length larger than current length? */
screamer 0:7a64fbb4069d 322 if (new_len >= p->tot_len) {
screamer 0:7a64fbb4069d 323 /* enlarging not yet supported */
screamer 0:7a64fbb4069d 324 return;
screamer 0:7a64fbb4069d 325 }
screamer 0:7a64fbb4069d 326
screamer 0:7a64fbb4069d 327 /* the pbuf chain grows by (new_len - p->tot_len) bytes
screamer 0:7a64fbb4069d 328 * (which may be negative in case of shrinking) */
screamer 0:7a64fbb4069d 329 grow = new_len - p->tot_len;
screamer 0:7a64fbb4069d 330
screamer 0:7a64fbb4069d 331 /* first, step over any pbufs that should remain in the chain */
screamer 0:7a64fbb4069d 332 rem_len = new_len;
screamer 0:7a64fbb4069d 333 q = p;
screamer 0:7a64fbb4069d 334 /* should this pbuf be kept? */
screamer 0:7a64fbb4069d 335 while (rem_len > q->len) {
screamer 0:7a64fbb4069d 336 /* decrease remaining length by pbuf length */
screamer 0:7a64fbb4069d 337 rem_len -= q->len;
screamer 0:7a64fbb4069d 338 /* decrease total length indicator */
screamer 0:7a64fbb4069d 339 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
screamer 0:7a64fbb4069d 340 q->tot_len += (u16_t)grow;
screamer 0:7a64fbb4069d 341 /* proceed to next pbuf in chain */
screamer 0:7a64fbb4069d 342 q = q->next;
screamer 0:7a64fbb4069d 343 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
screamer 0:7a64fbb4069d 344 }
screamer 0:7a64fbb4069d 345 /* we have now reached the new last pbuf (in q) */
screamer 0:7a64fbb4069d 346 /* rem_len == desired length for pbuf q */
screamer 0:7a64fbb4069d 347
screamer 0:7a64fbb4069d 348 /* shrink allocated memory for PBUF_RAM */
screamer 0:7a64fbb4069d 349 /* (other types merely adjust their length fields */
screamer 0:7a64fbb4069d 350 if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
screamer 0:7a64fbb4069d 351 /* reallocate and adjust the length of the pbuf that will be split */
screamer 0:7a64fbb4069d 352 q = (struct pbuf *)(mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len)); // static_cast<struct pbuf *>(x)
screamer 0:7a64fbb4069d 353 LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
screamer 0:7a64fbb4069d 354 }
screamer 0:7a64fbb4069d 355 /* adjust length fields for new last pbuf */
screamer 0:7a64fbb4069d 356 q->len = rem_len;
screamer 0:7a64fbb4069d 357 q->tot_len = q->len;
screamer 0:7a64fbb4069d 358
screamer 0:7a64fbb4069d 359 /* any remaining pbufs in chain? */
screamer 0:7a64fbb4069d 360 if (q->next != NULL) {
screamer 0:7a64fbb4069d 361 /* free remaining pbufs in chain */
screamer 0:7a64fbb4069d 362 pbuf_free(q->next);
screamer 0:7a64fbb4069d 363 }
screamer 0:7a64fbb4069d 364 /* q is last packet in chain */
screamer 0:7a64fbb4069d 365 q->next = NULL;
screamer 0:7a64fbb4069d 366
screamer 0:7a64fbb4069d 367 }
screamer 0:7a64fbb4069d 368
screamer 0:7a64fbb4069d 369 /**
screamer 0:7a64fbb4069d 370 * Adjusts the payload pointer to hide or reveal headers in the payload.
screamer 0:7a64fbb4069d 371 *
screamer 0:7a64fbb4069d 372 * Adjusts the ->payload pointer so that space for a header
screamer 0:7a64fbb4069d 373 * (dis)appears in the pbuf payload.
screamer 0:7a64fbb4069d 374 *
screamer 0:7a64fbb4069d 375 * The ->payload, ->tot_len and ->len fields are adjusted.
screamer 0:7a64fbb4069d 376 *
screamer 0:7a64fbb4069d 377 * @param p pbuf to change the header size.
screamer 0:7a64fbb4069d 378 * @param header_size_increment Number of bytes to increment header size which
screamer 0:7a64fbb4069d 379 * increases the size of the pbuf. New space is on the front.
screamer 0:7a64fbb4069d 380 * (Using a negative value decreases the header size.)
screamer 0:7a64fbb4069d 381 * If hdr_size_inc is 0, this function does nothing and returns succesful.
screamer 0:7a64fbb4069d 382 *
screamer 0:7a64fbb4069d 383 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
screamer 0:7a64fbb4069d 384 * the call will fail. A check is made that the increase in header size does
screamer 0:7a64fbb4069d 385 * not move the payload pointer in front of the start of the buffer.
screamer 0:7a64fbb4069d 386 * @return non-zero on failure, zero on success.
screamer 0:7a64fbb4069d 387 *
screamer 0:7a64fbb4069d 388 */
screamer 0:7a64fbb4069d 389 u8_t
screamer 0:7a64fbb4069d 390 pbuf_header(struct pbuf *p, s16_t header_size_increment)
screamer 0:7a64fbb4069d 391 {
screamer 0:7a64fbb4069d 392 u16_t type;
screamer 0:7a64fbb4069d 393 void *payload;
screamer 0:7a64fbb4069d 394 u16_t increment_magnitude;
screamer 0:7a64fbb4069d 395
screamer 0:7a64fbb4069d 396 LWIP_ASSERT("p != NULL", p != NULL);
screamer 0:7a64fbb4069d 397 if ((header_size_increment == 0) || (p == NULL))
screamer 0:7a64fbb4069d 398 return 0;
screamer 0:7a64fbb4069d 399
screamer 0:7a64fbb4069d 400 if (header_size_increment < 0){
screamer 0:7a64fbb4069d 401 increment_magnitude = -header_size_increment;
screamer 0:7a64fbb4069d 402 /* Check that we aren't going to move off the end of the pbuf */
screamer 0:7a64fbb4069d 403 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
screamer 0:7a64fbb4069d 404 } else {
screamer 0:7a64fbb4069d 405 increment_magnitude = header_size_increment;
screamer 0:7a64fbb4069d 406 #if 0
screamer 0:7a64fbb4069d 407 /* Can't assert these as some callers speculatively call
screamer 0:7a64fbb4069d 408 pbuf_header() to see if it's OK. Will return 1 below instead. */
screamer 0:7a64fbb4069d 409 /* Check that we've got the correct type of pbuf to work with */
screamer 0:7a64fbb4069d 410 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
screamer 0:7a64fbb4069d 411 p->type == PBUF_RAM || p->type == PBUF_POOL);
screamer 0:7a64fbb4069d 412 /* Check that we aren't going to move off the beginning of the pbuf */
screamer 0:7a64fbb4069d 413 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
screamer 0:7a64fbb4069d 414 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
screamer 0:7a64fbb4069d 415 #endif
screamer 0:7a64fbb4069d 416 }
screamer 0:7a64fbb4069d 417
screamer 0:7a64fbb4069d 418 type = p->type;
screamer 0:7a64fbb4069d 419 /* remember current payload pointer */
screamer 0:7a64fbb4069d 420 payload = p->payload;
screamer 0:7a64fbb4069d 421
screamer 0:7a64fbb4069d 422 /* pbuf types containing payloads? */
screamer 0:7a64fbb4069d 423 if (type == PBUF_RAM || type == PBUF_POOL) {
screamer 0:7a64fbb4069d 424 /* set new payload pointer */
screamer 0:7a64fbb4069d 425 p->payload = (u8_t *)p->payload - header_size_increment;
screamer 0:7a64fbb4069d 426 /* boundary check fails? */
screamer 0:7a64fbb4069d 427 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
screamer 0:7a64fbb4069d 428 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
screamer 0:7a64fbb4069d 429 (void *)p->payload,
screamer 0:7a64fbb4069d 430 (void *)(p + 1)));\
screamer 0:7a64fbb4069d 431 /* restore old payload pointer */
screamer 0:7a64fbb4069d 432 p->payload = payload;
screamer 0:7a64fbb4069d 433 /* bail out unsuccesfully */
screamer 0:7a64fbb4069d 434 return 1;
screamer 0:7a64fbb4069d 435 }
screamer 0:7a64fbb4069d 436 /* pbuf types refering to external payloads? */
screamer 0:7a64fbb4069d 437 } else if (type == PBUF_REF || type == PBUF_ROM) {
screamer 0:7a64fbb4069d 438 /* hide a header in the payload? */
screamer 0:7a64fbb4069d 439 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
screamer 0:7a64fbb4069d 440 /* increase payload pointer */
screamer 0:7a64fbb4069d 441 p->payload = (u8_t *)p->payload - header_size_increment;
screamer 0:7a64fbb4069d 442 } else {
screamer 0:7a64fbb4069d 443 /* cannot expand payload to front (yet!)
screamer 0:7a64fbb4069d 444 * bail out unsuccesfully */
screamer 0:7a64fbb4069d 445 return 1;
screamer 0:7a64fbb4069d 446 }
screamer 0:7a64fbb4069d 447 }
screamer 0:7a64fbb4069d 448 else {
screamer 0:7a64fbb4069d 449 /* Unknown type */
screamer 0:7a64fbb4069d 450 LWIP_ASSERT("bad pbuf type", 0);
screamer 0:7a64fbb4069d 451 return 1;
screamer 0:7a64fbb4069d 452 }
screamer 0:7a64fbb4069d 453 /* modify pbuf length fields */
screamer 0:7a64fbb4069d 454 p->len += header_size_increment;
screamer 0:7a64fbb4069d 455 p->tot_len += header_size_increment;
screamer 0:7a64fbb4069d 456
screamer 0:7a64fbb4069d 457 LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
screamer 0:7a64fbb4069d 458 (void *)payload, (void *)p->payload, header_size_increment));
screamer 0:7a64fbb4069d 459
screamer 0:7a64fbb4069d 460 return 0;
screamer 0:7a64fbb4069d 461 }
screamer 0:7a64fbb4069d 462
screamer 0:7a64fbb4069d 463 /**
screamer 0:7a64fbb4069d 464 * Dereference a pbuf chain or queue and deallocate any no-longer-used
screamer 0:7a64fbb4069d 465 * pbufs at the head of this chain or queue.
screamer 0:7a64fbb4069d 466 *
screamer 0:7a64fbb4069d 467 * Decrements the pbuf reference count. If it reaches zero, the pbuf is
screamer 0:7a64fbb4069d 468 * deallocated.
screamer 0:7a64fbb4069d 469 *
screamer 0:7a64fbb4069d 470 * For a pbuf chain, this is repeated for each pbuf in the chain,
screamer 0:7a64fbb4069d 471 * up to the first pbuf which has a non-zero reference count after
screamer 0:7a64fbb4069d 472 * decrementing. So, when all reference counts are one, the whole
screamer 0:7a64fbb4069d 473 * chain is free'd.
screamer 0:7a64fbb4069d 474 *
screamer 0:7a64fbb4069d 475 * @param p The pbuf (chain) to be dereferenced.
screamer 0:7a64fbb4069d 476 *
screamer 0:7a64fbb4069d 477 * @return the number of pbufs that were de-allocated
screamer 0:7a64fbb4069d 478 * from the head of the chain.
screamer 0:7a64fbb4069d 479 *
screamer 0:7a64fbb4069d 480 * @note MUST NOT be called on a packet queue (Not verified to work yet).
screamer 0:7a64fbb4069d 481 * @note the reference counter of a pbuf equals the number of pointers
screamer 0:7a64fbb4069d 482 * that refer to the pbuf (or into the pbuf).
screamer 0:7a64fbb4069d 483 *
screamer 0:7a64fbb4069d 484 * @internal examples:
screamer 0:7a64fbb4069d 485 *
screamer 0:7a64fbb4069d 486 * Assuming existing chains a->b->c with the following reference
screamer 0:7a64fbb4069d 487 * counts, calling pbuf_free(a) results in:
screamer 0:7a64fbb4069d 488 *
screamer 0:7a64fbb4069d 489 * 1->2->3 becomes ...1->3
screamer 0:7a64fbb4069d 490 * 3->3->3 becomes 2->3->3
screamer 0:7a64fbb4069d 491 * 1->1->2 becomes ......1
screamer 0:7a64fbb4069d 492 * 2->1->1 becomes 1->1->1
screamer 0:7a64fbb4069d 493 * 1->1->1 becomes .......
screamer 0:7a64fbb4069d 494 *
screamer 0:7a64fbb4069d 495 */
screamer 0:7a64fbb4069d 496 u8_t
screamer 0:7a64fbb4069d 497 pbuf_free(struct pbuf *p)
screamer 0:7a64fbb4069d 498 {
screamer 0:7a64fbb4069d 499 u16_t type;
screamer 0:7a64fbb4069d 500 struct pbuf *q;
screamer 0:7a64fbb4069d 501 u8_t count;
screamer 0:7a64fbb4069d 502
screamer 0:7a64fbb4069d 503 if (p == NULL) {
screamer 0:7a64fbb4069d 504 LWIP_ASSERT("p != NULL", p != NULL);
screamer 0:7a64fbb4069d 505 /* if assertions are disabled, proceed with debug output */
screamer 0:7a64fbb4069d 506 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
screamer 0:7a64fbb4069d 507 return 0;
screamer 0:7a64fbb4069d 508 }
screamer 0:7a64fbb4069d 509 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
screamer 0:7a64fbb4069d 510
screamer 0:7a64fbb4069d 511 PERF_START;
screamer 0:7a64fbb4069d 512
screamer 0:7a64fbb4069d 513 LWIP_ASSERT("pbuf_free: sane type",
screamer 0:7a64fbb4069d 514 p->type == PBUF_RAM || p->type == PBUF_ROM ||
screamer 0:7a64fbb4069d 515 p->type == PBUF_REF || p->type == PBUF_POOL);
screamer 0:7a64fbb4069d 516
screamer 0:7a64fbb4069d 517 count = 0;
screamer 0:7a64fbb4069d 518 /* de-allocate all consecutive pbufs from the head of the chain that
screamer 0:7a64fbb4069d 519 * obtain a zero reference count after decrementing*/
screamer 0:7a64fbb4069d 520 while (p != NULL) {
screamer 0:7a64fbb4069d 521 u16_t ref;
screamer 0:7a64fbb4069d 522 SYS_ARCH_DECL_PROTECT(old_level);
screamer 0:7a64fbb4069d 523 /* Since decrementing ref cannot be guaranteed to be a single machine operation
screamer 0:7a64fbb4069d 524 * we must protect it. We put the new ref into a local variable to prevent
screamer 0:7a64fbb4069d 525 * further protection. */
screamer 0:7a64fbb4069d 526 SYS_ARCH_PROTECT(old_level);
screamer 0:7a64fbb4069d 527 /* all pbufs in a chain are referenced at least once */
screamer 0:7a64fbb4069d 528 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
screamer 0:7a64fbb4069d 529 /* decrease reference count (number of pointers to pbuf) */
screamer 0:7a64fbb4069d 530 ref = --(p->ref);
screamer 0:7a64fbb4069d 531 SYS_ARCH_UNPROTECT(old_level);
screamer 0:7a64fbb4069d 532 /* this pbuf is no longer referenced to? */
screamer 0:7a64fbb4069d 533 if (ref == 0) {
screamer 0:7a64fbb4069d 534 /* remember next pbuf in chain for next iteration */
screamer 0:7a64fbb4069d 535 q = p->next;
screamer 0:7a64fbb4069d 536 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
screamer 0:7a64fbb4069d 537 type = p->type;
screamer 0:7a64fbb4069d 538 /* is this a pbuf from the pool? */
screamer 0:7a64fbb4069d 539 if (type == PBUF_POOL) {
screamer 0:7a64fbb4069d 540 memp_free(MEMP_PBUF_POOL, p);
screamer 0:7a64fbb4069d 541 /* is this a ROM or RAM referencing pbuf? */
screamer 0:7a64fbb4069d 542 } else if (type == PBUF_ROM || type == PBUF_REF) {
screamer 0:7a64fbb4069d 543 memp_free(MEMP_PBUF, p);
screamer 0:7a64fbb4069d 544 /* type == PBUF_RAM */
screamer 0:7a64fbb4069d 545 } else {
screamer 0:7a64fbb4069d 546 mem_free(p);
screamer 0:7a64fbb4069d 547 }
screamer 0:7a64fbb4069d 548 count++;
screamer 0:7a64fbb4069d 549 /* proceed to next pbuf */
screamer 0:7a64fbb4069d 550 p = q;
screamer 0:7a64fbb4069d 551 /* p->ref > 0, this pbuf is still referenced to */
screamer 0:7a64fbb4069d 552 /* (and so the remaining pbufs in chain as well) */
screamer 0:7a64fbb4069d 553 } else {
screamer 0:7a64fbb4069d 554 LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
screamer 0:7a64fbb4069d 555 /* stop walking through the chain */
screamer 0:7a64fbb4069d 556 p = NULL;
screamer 0:7a64fbb4069d 557 }
screamer 0:7a64fbb4069d 558 }
screamer 0:7a64fbb4069d 559 PERF_STOP("pbuf_free");
screamer 0:7a64fbb4069d 560 /* return number of de-allocated pbufs */
screamer 0:7a64fbb4069d 561 return count;
screamer 0:7a64fbb4069d 562 }
screamer 0:7a64fbb4069d 563
screamer 0:7a64fbb4069d 564 /**
screamer 0:7a64fbb4069d 565 * Count number of pbufs in a chain
screamer 0:7a64fbb4069d 566 *
screamer 0:7a64fbb4069d 567 * @param p first pbuf of chain
screamer 0:7a64fbb4069d 568 * @return the number of pbufs in a chain
screamer 0:7a64fbb4069d 569 */
screamer 0:7a64fbb4069d 570
screamer 0:7a64fbb4069d 571 u8_t
screamer 0:7a64fbb4069d 572 pbuf_clen(struct pbuf *p)
screamer 0:7a64fbb4069d 573 {
screamer 0:7a64fbb4069d 574 u8_t len;
screamer 0:7a64fbb4069d 575
screamer 0:7a64fbb4069d 576 len = 0;
screamer 0:7a64fbb4069d 577 while (p != NULL) {
screamer 0:7a64fbb4069d 578 ++len;
screamer 0:7a64fbb4069d 579 p = p->next;
screamer 0:7a64fbb4069d 580 }
screamer 0:7a64fbb4069d 581 return len;
screamer 0:7a64fbb4069d 582 }
screamer 0:7a64fbb4069d 583
screamer 0:7a64fbb4069d 584 /**
screamer 0:7a64fbb4069d 585 * Increment the reference count of the pbuf.
screamer 0:7a64fbb4069d 586 *
screamer 0:7a64fbb4069d 587 * @param p pbuf to increase reference counter of
screamer 0:7a64fbb4069d 588 *
screamer 0:7a64fbb4069d 589 */
screamer 0:7a64fbb4069d 590 void
screamer 0:7a64fbb4069d 591 pbuf_ref(struct pbuf *p)
screamer 0:7a64fbb4069d 592 {
screamer 0:7a64fbb4069d 593 SYS_ARCH_DECL_PROTECT(old_level);
screamer 0:7a64fbb4069d 594 /* pbuf given? */
screamer 0:7a64fbb4069d 595 if (p != NULL) {
screamer 0:7a64fbb4069d 596 SYS_ARCH_PROTECT(old_level);
screamer 0:7a64fbb4069d 597 ++(p->ref);
screamer 0:7a64fbb4069d 598 SYS_ARCH_UNPROTECT(old_level);
screamer 0:7a64fbb4069d 599 }
screamer 0:7a64fbb4069d 600 }
screamer 0:7a64fbb4069d 601
screamer 0:7a64fbb4069d 602 /**
screamer 0:7a64fbb4069d 603 * Concatenate two pbufs (each may be a pbuf chain) and take over
screamer 0:7a64fbb4069d 604 * the caller's reference of the tail pbuf.
screamer 0:7a64fbb4069d 605 *
screamer 0:7a64fbb4069d 606 * @note The caller MAY NOT reference the tail pbuf afterwards.
screamer 0:7a64fbb4069d 607 * Use pbuf_chain() for that purpose.
screamer 0:7a64fbb4069d 608 *
screamer 0:7a64fbb4069d 609 * @see pbuf_chain()
screamer 0:7a64fbb4069d 610 */
screamer 0:7a64fbb4069d 611
screamer 0:7a64fbb4069d 612 void
screamer 0:7a64fbb4069d 613 pbuf_cat(struct pbuf *h, struct pbuf *t)
screamer 0:7a64fbb4069d 614 {
screamer 0:7a64fbb4069d 615 struct pbuf *p;
screamer 0:7a64fbb4069d 616
screamer 0:7a64fbb4069d 617 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
screamer 0:7a64fbb4069d 618 ((h != NULL) && (t != NULL)), return;);
screamer 0:7a64fbb4069d 619
screamer 0:7a64fbb4069d 620 /* proceed to last pbuf of chain */
screamer 0:7a64fbb4069d 621 for (p = h; p->next != NULL; p = p->next) {
screamer 0:7a64fbb4069d 622 /* add total length of second chain to all totals of first chain */
screamer 0:7a64fbb4069d 623 p->tot_len += t->tot_len;
screamer 0:7a64fbb4069d 624 }
screamer 0:7a64fbb4069d 625 /* { p is last pbuf of first h chain, p->next == NULL } */
screamer 0:7a64fbb4069d 626 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
screamer 0:7a64fbb4069d 627 LWIP_ASSERT("p->next == NULL", p->next == NULL);
screamer 0:7a64fbb4069d 628 /* add total length of second chain to last pbuf total of first chain */
screamer 0:7a64fbb4069d 629 p->tot_len += t->tot_len;
screamer 0:7a64fbb4069d 630 /* chain last pbuf of head (p) with first of tail (t) */
screamer 0:7a64fbb4069d 631 p->next = t;
screamer 0:7a64fbb4069d 632 /* p->next now references t, but the caller will drop its reference to t,
screamer 0:7a64fbb4069d 633 * so netto there is no change to the reference count of t.
screamer 0:7a64fbb4069d 634 */
screamer 0:7a64fbb4069d 635 }
screamer 0:7a64fbb4069d 636
screamer 0:7a64fbb4069d 637 /**
screamer 0:7a64fbb4069d 638 * Chain two pbufs (or pbuf chains) together.
screamer 0:7a64fbb4069d 639 *
screamer 0:7a64fbb4069d 640 * The caller MUST call pbuf_free(t) once it has stopped
screamer 0:7a64fbb4069d 641 * using it. Use pbuf_cat() instead if you no longer use t.
screamer 0:7a64fbb4069d 642 *
screamer 0:7a64fbb4069d 643 * @param h head pbuf (chain)
screamer 0:7a64fbb4069d 644 * @param t tail pbuf (chain)
screamer 0:7a64fbb4069d 645 * @note The pbufs MUST belong to the same packet.
screamer 0:7a64fbb4069d 646 * @note MAY NOT be called on a packet queue.
screamer 0:7a64fbb4069d 647 *
screamer 0:7a64fbb4069d 648 * The ->tot_len fields of all pbufs of the head chain are adjusted.
screamer 0:7a64fbb4069d 649 * The ->next field of the last pbuf of the head chain is adjusted.
screamer 0:7a64fbb4069d 650 * The ->ref field of the first pbuf of the tail chain is adjusted.
screamer 0:7a64fbb4069d 651 *
screamer 0:7a64fbb4069d 652 */
screamer 0:7a64fbb4069d 653 void
screamer 0:7a64fbb4069d 654 pbuf_chain(struct pbuf *h, struct pbuf *t)
screamer 0:7a64fbb4069d 655 {
screamer 0:7a64fbb4069d 656 pbuf_cat(h, t);
screamer 0:7a64fbb4069d 657 /* t is now referenced by h */
screamer 0:7a64fbb4069d 658 pbuf_ref(t);
screamer 0:7a64fbb4069d 659 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
screamer 0:7a64fbb4069d 660 }
screamer 0:7a64fbb4069d 661
screamer 0:7a64fbb4069d 662 /**
screamer 0:7a64fbb4069d 663 * Dechains the first pbuf from its succeeding pbufs in the chain.
screamer 0:7a64fbb4069d 664 *
screamer 0:7a64fbb4069d 665 * Makes p->tot_len field equal to p->len.
screamer 0:7a64fbb4069d 666 * @param p pbuf to dechain
screamer 0:7a64fbb4069d 667 * @return remainder of the pbuf chain, or NULL if it was de-allocated.
screamer 0:7a64fbb4069d 668 * @note May not be called on a packet queue.
screamer 0:7a64fbb4069d 669 */
screamer 0:7a64fbb4069d 670 struct pbuf *
screamer 0:7a64fbb4069d 671 pbuf_dechain(struct pbuf *p)
screamer 0:7a64fbb4069d 672 {
screamer 0:7a64fbb4069d 673 struct pbuf *q;
screamer 0:7a64fbb4069d 674 u8_t tail_gone = 1;
screamer 0:7a64fbb4069d 675 /* tail */
screamer 0:7a64fbb4069d 676 q = p->next;
screamer 0:7a64fbb4069d 677 /* pbuf has successor in chain? */
screamer 0:7a64fbb4069d 678 if (q != NULL) {
screamer 0:7a64fbb4069d 679 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
screamer 0:7a64fbb4069d 680 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
screamer 0:7a64fbb4069d 681 /* enforce invariant if assertion is disabled */
screamer 0:7a64fbb4069d 682 q->tot_len = p->tot_len - p->len;
screamer 0:7a64fbb4069d 683 /* decouple pbuf from remainder */
screamer 0:7a64fbb4069d 684 p->next = NULL;
screamer 0:7a64fbb4069d 685 /* total length of pbuf p is its own length only */
screamer 0:7a64fbb4069d 686 p->tot_len = p->len;
screamer 0:7a64fbb4069d 687 /* q is no longer referenced by p, free it */
screamer 0:7a64fbb4069d 688 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
screamer 0:7a64fbb4069d 689 tail_gone = pbuf_free(q);
screamer 0:7a64fbb4069d 690 if (tail_gone > 0) {
screamer 0:7a64fbb4069d 691 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
screamer 0:7a64fbb4069d 692 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
screamer 0:7a64fbb4069d 693 }
screamer 0:7a64fbb4069d 694 /* return remaining tail or NULL if deallocated */
screamer 0:7a64fbb4069d 695 }
screamer 0:7a64fbb4069d 696 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
screamer 0:7a64fbb4069d 697 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
screamer 0:7a64fbb4069d 698 return ((tail_gone > 0) ? NULL : q);
screamer 0:7a64fbb4069d 699 }
screamer 0:7a64fbb4069d 700
screamer 0:7a64fbb4069d 701 /**
screamer 0:7a64fbb4069d 702 *
screamer 0:7a64fbb4069d 703 * Create PBUF_RAM copies of pbufs.
screamer 0:7a64fbb4069d 704 *
screamer 0:7a64fbb4069d 705 * Used to queue packets on behalf of the lwIP stack, such as
screamer 0:7a64fbb4069d 706 * ARP based queueing.
screamer 0:7a64fbb4069d 707 *
screamer 0:7a64fbb4069d 708 * @note You MUST explicitly use p = pbuf_take(p);
screamer 0:7a64fbb4069d 709 *
screamer 0:7a64fbb4069d 710 * @note Only one packet is copied, no packet queue!
screamer 0:7a64fbb4069d 711 *
screamer 0:7a64fbb4069d 712 * @param p_to pbuf destination of the copy
screamer 0:7a64fbb4069d 713 * @param p_from pbuf source of the copy
screamer 0:7a64fbb4069d 714 *
screamer 0:7a64fbb4069d 715 * @return ERR_OK if pbuf was copied
screamer 0:7a64fbb4069d 716 * ERR_ARG if one of the pbufs is NULL or p_to is not big
screamer 0:7a64fbb4069d 717 * enough to hold p_from
screamer 0:7a64fbb4069d 718 */
screamer 0:7a64fbb4069d 719 err_t
screamer 0:7a64fbb4069d 720 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
screamer 0:7a64fbb4069d 721 {
screamer 0:7a64fbb4069d 722 u16_t offset_to=0, offset_from=0, len;
screamer 0:7a64fbb4069d 723
screamer 0:7a64fbb4069d 724 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",
screamer 0:7a64fbb4069d 725 (void*)p_to, (void*)p_from));
screamer 0:7a64fbb4069d 726
screamer 0:7a64fbb4069d 727 /* is the target big enough to hold the source? */
screamer 0:7a64fbb4069d 728 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
screamer 0:7a64fbb4069d 729 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
screamer 0:7a64fbb4069d 730
screamer 0:7a64fbb4069d 731 /* iterate through pbuf chain */
screamer 0:7a64fbb4069d 732 do
screamer 0:7a64fbb4069d 733 {
screamer 0:7a64fbb4069d 734 LWIP_ASSERT("p_to != NULL", p_to != NULL);
screamer 0:7a64fbb4069d 735 /* copy one part of the original chain */
screamer 0:7a64fbb4069d 736 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
screamer 0:7a64fbb4069d 737 /* complete current p_from fits into current p_to */
screamer 0:7a64fbb4069d 738 len = p_from->len - offset_from;
screamer 0:7a64fbb4069d 739 } else {
screamer 0:7a64fbb4069d 740 /* current p_from does not fit into current p_to */
screamer 0:7a64fbb4069d 741 len = p_to->len - offset_to;
screamer 0:7a64fbb4069d 742 }
screamer 0:7a64fbb4069d 743 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
screamer 0:7a64fbb4069d 744 offset_to += len;
screamer 0:7a64fbb4069d 745 offset_from += len;
screamer 0:7a64fbb4069d 746 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
screamer 0:7a64fbb4069d 747 if (offset_to == p_to->len) {
screamer 0:7a64fbb4069d 748 /* on to next p_to (if any) */
screamer 0:7a64fbb4069d 749 offset_to = 0;
screamer 0:7a64fbb4069d 750 p_to = p_to->next;
screamer 0:7a64fbb4069d 751 }
screamer 0:7a64fbb4069d 752 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
screamer 0:7a64fbb4069d 753 if (offset_from >= p_from->len) {
screamer 0:7a64fbb4069d 754 /* on to next p_from (if any) */
screamer 0:7a64fbb4069d 755 offset_from = 0;
screamer 0:7a64fbb4069d 756 p_from = p_from->next;
screamer 0:7a64fbb4069d 757 }
screamer 0:7a64fbb4069d 758
screamer 0:7a64fbb4069d 759 if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
screamer 0:7a64fbb4069d 760 /* don't copy more than one packet! */
screamer 0:7a64fbb4069d 761 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
screamer 0:7a64fbb4069d 762 (p_from->next == NULL), return ERR_VAL;);
screamer 0:7a64fbb4069d 763 }
screamer 0:7a64fbb4069d 764 if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
screamer 0:7a64fbb4069d 765 /* don't copy more than one packet! */
screamer 0:7a64fbb4069d 766 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
screamer 0:7a64fbb4069d 767 (p_to->next == NULL), return ERR_VAL;);
screamer 0:7a64fbb4069d 768 }
screamer 0:7a64fbb4069d 769 } while (p_from);
screamer 0:7a64fbb4069d 770 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
screamer 0:7a64fbb4069d 771 return ERR_OK;
screamer 0:7a64fbb4069d 772 }
screamer 0:7a64fbb4069d 773
screamer 0:7a64fbb4069d 774 /**
screamer 0:7a64fbb4069d 775 * Copy (part of) the contents of a packet buffer
screamer 0:7a64fbb4069d 776 * to an application supplied buffer.
screamer 0:7a64fbb4069d 777 *
screamer 0:7a64fbb4069d 778 * @param buf the pbuf from which to copy data
screamer 0:7a64fbb4069d 779 * @param dataptr the application supplied buffer
screamer 0:7a64fbb4069d 780 * @param len length of data to copy (dataptr must be big enough). No more
screamer 0:7a64fbb4069d 781 * than buf->tot_len will be copied, irrespective of len
screamer 0:7a64fbb4069d 782 * @param offset offset into the packet buffer from where to begin copying len bytes
screamer 0:7a64fbb4069d 783 * @return the number of bytes copied, or 0 on failure
screamer 0:7a64fbb4069d 784 */
screamer 0:7a64fbb4069d 785 u16_t
screamer 0:7a64fbb4069d 786 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
screamer 0:7a64fbb4069d 787 {
screamer 0:7a64fbb4069d 788 struct pbuf *p;
screamer 0:7a64fbb4069d 789 u16_t left;
screamer 0:7a64fbb4069d 790 u16_t buf_copy_len;
screamer 0:7a64fbb4069d 791 u16_t copied_total = 0;
screamer 0:7a64fbb4069d 792
screamer 0:7a64fbb4069d 793 LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
screamer 0:7a64fbb4069d 794 LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
screamer 0:7a64fbb4069d 795
screamer 0:7a64fbb4069d 796 left = 0;
screamer 0:7a64fbb4069d 797
screamer 0:7a64fbb4069d 798 if((buf == NULL) || (dataptr == NULL)) {
screamer 0:7a64fbb4069d 799 return 0;
screamer 0:7a64fbb4069d 800 }
screamer 0:7a64fbb4069d 801
screamer 0:7a64fbb4069d 802 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
screamer 0:7a64fbb4069d 803 for(p = buf; len != 0 && p != NULL; p = p->next) {
screamer 0:7a64fbb4069d 804 if ((offset != 0) && (offset >= p->len)) {
screamer 0:7a64fbb4069d 805 /* don't copy from this buffer -> on to the next */
screamer 0:7a64fbb4069d 806 offset -= p->len;
screamer 0:7a64fbb4069d 807 } else {
screamer 0:7a64fbb4069d 808 /* copy from this buffer. maybe only partially. */
screamer 0:7a64fbb4069d 809 buf_copy_len = p->len - offset;
screamer 0:7a64fbb4069d 810 if (buf_copy_len > len)
screamer 0:7a64fbb4069d 811 buf_copy_len = len;
screamer 0:7a64fbb4069d 812 /* copy the necessary parts of the buffer */
screamer 0:7a64fbb4069d 813 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
screamer 0:7a64fbb4069d 814 copied_total += buf_copy_len;
screamer 0:7a64fbb4069d 815 left += buf_copy_len;
screamer 0:7a64fbb4069d 816 len -= buf_copy_len;
screamer 0:7a64fbb4069d 817 offset = 0;
screamer 0:7a64fbb4069d 818 }
screamer 0:7a64fbb4069d 819 }
screamer 0:7a64fbb4069d 820 return copied_total;
screamer 0:7a64fbb4069d 821 }