Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1 /**
segundo 0:ac1725ba162c 2 * @file
segundo 0:ac1725ba162c 3 * Packet buffer management
segundo 0:ac1725ba162c 4 *
segundo 0:ac1725ba162c 5 * Packets are built from the pbuf data structure. It supports dynamic
segundo 0:ac1725ba162c 6 * memory allocation for packet contents or can reference externally
segundo 0:ac1725ba162c 7 * managed packet contents both in RAM and ROM. Quick allocation for
segundo 0:ac1725ba162c 8 * incoming packets is provided through pools with fixed sized pbufs.
segundo 0:ac1725ba162c 9 *
segundo 0:ac1725ba162c 10 * A packet may span over multiple pbufs, chained as a singly linked
segundo 0:ac1725ba162c 11 * list. This is called a "pbuf chain".
segundo 0:ac1725ba162c 12 *
segundo 0:ac1725ba162c 13 * Multiple packets may be queued, also using this singly linked list.
segundo 0:ac1725ba162c 14 * This is called a "packet queue".
segundo 0:ac1725ba162c 15 *
segundo 0:ac1725ba162c 16 * So, a packet queue consists of one or more pbuf chains, each of
segundo 0:ac1725ba162c 17 * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
segundo 0:ac1725ba162c 18 * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
segundo 0:ac1725ba162c 19 *
segundo 0:ac1725ba162c 20 * The differences between a pbuf chain and a packet queue are very
segundo 0:ac1725ba162c 21 * precise but subtle.
segundo 0:ac1725ba162c 22 *
segundo 0:ac1725ba162c 23 * The last pbuf of a packet has a ->tot_len field that equals the
segundo 0:ac1725ba162c 24 * ->len field. It can be found by traversing the list. If the last
segundo 0:ac1725ba162c 25 * pbuf of a packet has a ->next field other than NULL, more packets
segundo 0:ac1725ba162c 26 * are on the queue.
segundo 0:ac1725ba162c 27 *
segundo 0:ac1725ba162c 28 * Therefore, looping through a pbuf of a single packet, has an
segundo 0:ac1725ba162c 29 * loop end condition (tot_len == p->len), NOT (next == NULL).
segundo 0:ac1725ba162c 30 */
segundo 0:ac1725ba162c 31
segundo 0:ac1725ba162c 32 /*
segundo 0:ac1725ba162c 33 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
segundo 0:ac1725ba162c 34 * All rights reserved.
segundo 0:ac1725ba162c 35 *
segundo 0:ac1725ba162c 36 * Redistribution and use in source and binary forms, with or without modification,
segundo 0:ac1725ba162c 37 * are permitted provided that the following conditions are met:
segundo 0:ac1725ba162c 38 *
segundo 0:ac1725ba162c 39 * 1. Redistributions of source code must retain the above copyright notice,
segundo 0:ac1725ba162c 40 * this list of conditions and the following disclaimer.
segundo 0:ac1725ba162c 41 * 2. Redistributions in binary form must reproduce the above copyright notice,
segundo 0:ac1725ba162c 42 * this list of conditions and the following disclaimer in the documentation
segundo 0:ac1725ba162c 43 * and/or other materials provided with the distribution.
segundo 0:ac1725ba162c 44 * 3. The name of the author may not be used to endorse or promote products
segundo 0:ac1725ba162c 45 * derived from this software without specific prior written permission.
segundo 0:ac1725ba162c 46 *
segundo 0:ac1725ba162c 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
segundo 0:ac1725ba162c 48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
segundo 0:ac1725ba162c 49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
segundo 0:ac1725ba162c 50 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
segundo 0:ac1725ba162c 51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
segundo 0:ac1725ba162c 52 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
segundo 0:ac1725ba162c 53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
segundo 0:ac1725ba162c 54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
segundo 0:ac1725ba162c 55 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
segundo 0:ac1725ba162c 56 * OF SUCH DAMAGE.
segundo 0:ac1725ba162c 57 *
segundo 0:ac1725ba162c 58 * This file is part of the lwIP TCP/IP stack.
segundo 0:ac1725ba162c 59 *
segundo 0:ac1725ba162c 60 * Author: Adam Dunkels <adam@sics.se>
segundo 0:ac1725ba162c 61 *
segundo 0:ac1725ba162c 62 */
segundo 0:ac1725ba162c 63
segundo 0:ac1725ba162c 64 #include "lwip/opt.h"
segundo 0:ac1725ba162c 65
segundo 0:ac1725ba162c 66 #include "lwip/stats.h"
segundo 0:ac1725ba162c 67 #include "lwip/def.h"
segundo 0:ac1725ba162c 68 #include "lwip/mem.h"
segundo 0:ac1725ba162c 69 #include "lwip/memp.h"
segundo 0:ac1725ba162c 70 #include "lwip/pbuf.h"
segundo 0:ac1725ba162c 71 #include "lwip/sys.h"
segundo 0:ac1725ba162c 72 #include "arch/perf.h"
segundo 0:ac1725ba162c 73 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 74 #include "lwip/tcp_impl.h"
segundo 0:ac1725ba162c 75 #endif
segundo 0:ac1725ba162c 76 #if LWIP_CHECKSUM_ON_COPY
segundo 0:ac1725ba162c 77 #include "lwip/inet_chksum.h"
segundo 0:ac1725ba162c 78 #endif
segundo 0:ac1725ba162c 79
segundo 0:ac1725ba162c 80 #include <string.h>
segundo 0:ac1725ba162c 81
segundo 0:ac1725ba162c 82 #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
segundo 0:ac1725ba162c 83 /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
segundo 0:ac1725ba162c 84 aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
segundo 0:ac1725ba162c 85 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
segundo 0:ac1725ba162c 86
segundo 0:ac1725ba162c 87 #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
segundo 0:ac1725ba162c 88 #define PBUF_POOL_IS_EMPTY()
segundo 0:ac1725ba162c 89 #else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
segundo 0:ac1725ba162c 90 /** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
segundo 0:ac1725ba162c 91 #ifndef PBUF_POOL_FREE_OOSEQ
segundo 0:ac1725ba162c 92 #define PBUF_POOL_FREE_OOSEQ 1
segundo 0:ac1725ba162c 93 #endif /* PBUF_POOL_FREE_OOSEQ */
segundo 0:ac1725ba162c 94
segundo 0:ac1725ba162c 95 #if PBUF_POOL_FREE_OOSEQ
segundo 0:ac1725ba162c 96 #include "lwip/tcpip.h"
segundo 0:ac1725ba162c 97 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
segundo 0:ac1725ba162c 98 static u8_t pbuf_free_ooseq_queued;
segundo 0:ac1725ba162c 99 /**
segundo 0:ac1725ba162c 100 * Attempt to reclaim some memory from queued out-of-sequence TCP segments
segundo 0:ac1725ba162c 101 * if we run out of pool pbufs. It's better to give priority to new packets
segundo 0:ac1725ba162c 102 * if we're running out.
segundo 0:ac1725ba162c 103 *
segundo 0:ac1725ba162c 104 * This must be done in the correct thread context therefore this function
segundo 0:ac1725ba162c 105 * can only be used with NO_SYS=0 and through tcpip_callback.
segundo 0:ac1725ba162c 106 */
segundo 0:ac1725ba162c 107 static void
segundo 0:ac1725ba162c 108 pbuf_free_ooseq(void* arg)
segundo 0:ac1725ba162c 109 {
segundo 0:ac1725ba162c 110 struct tcp_pcb* pcb;
segundo 0:ac1725ba162c 111 SYS_ARCH_DECL_PROTECT(old_level);
segundo 0:ac1725ba162c 112 LWIP_UNUSED_ARG(arg);
segundo 0:ac1725ba162c 113
segundo 0:ac1725ba162c 114 SYS_ARCH_PROTECT(old_level);
segundo 0:ac1725ba162c 115 pbuf_free_ooseq_queued = 0;
segundo 0:ac1725ba162c 116 SYS_ARCH_UNPROTECT(old_level);
segundo 0:ac1725ba162c 117
segundo 0:ac1725ba162c 118 for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
segundo 0:ac1725ba162c 119 if (NULL != pcb->ooseq) {
segundo 0:ac1725ba162c 120 /** Free the ooseq pbufs of one PCB only */
segundo 0:ac1725ba162c 121 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
segundo 0:ac1725ba162c 122 tcp_segs_free(pcb->ooseq);
segundo 0:ac1725ba162c 123 pcb->ooseq = NULL;
segundo 0:ac1725ba162c 124 return;
segundo 0:ac1725ba162c 125 }
segundo 0:ac1725ba162c 126 }
segundo 0:ac1725ba162c 127 }
segundo 0:ac1725ba162c 128
segundo 0:ac1725ba162c 129 /** Queue a call to pbuf_free_ooseq if not already queued. */
segundo 0:ac1725ba162c 130 static void
segundo 0:ac1725ba162c 131 pbuf_pool_is_empty(void)
segundo 0:ac1725ba162c 132 {
segundo 0:ac1725ba162c 133 u8_t queued;
segundo 0:ac1725ba162c 134 SYS_ARCH_DECL_PROTECT(old_level);
segundo 0:ac1725ba162c 135
segundo 0:ac1725ba162c 136 SYS_ARCH_PROTECT(old_level);
segundo 0:ac1725ba162c 137 queued = pbuf_free_ooseq_queued;
segundo 0:ac1725ba162c 138 pbuf_free_ooseq_queued = 1;
segundo 0:ac1725ba162c 139 SYS_ARCH_UNPROTECT(old_level);
segundo 0:ac1725ba162c 140
segundo 0:ac1725ba162c 141 if(!queued) {
segundo 0:ac1725ba162c 142 /* queue a call to pbuf_free_ooseq if not already queued */
segundo 0:ac1725ba162c 143 if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
segundo 0:ac1725ba162c 144 SYS_ARCH_PROTECT(old_level);
segundo 0:ac1725ba162c 145 pbuf_free_ooseq_queued = 0;
segundo 0:ac1725ba162c 146 SYS_ARCH_UNPROTECT(old_level);
segundo 0:ac1725ba162c 147 }
segundo 0:ac1725ba162c 148 }
segundo 0:ac1725ba162c 149 }
segundo 0:ac1725ba162c 150 #endif /* PBUF_POOL_FREE_OOSEQ */
segundo 0:ac1725ba162c 151 #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
segundo 0:ac1725ba162c 152
segundo 0:ac1725ba162c 153 /**
segundo 0:ac1725ba162c 154 * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
segundo 0:ac1725ba162c 155 *
segundo 0:ac1725ba162c 156 * The actual memory allocated for the pbuf is determined by the
segundo 0:ac1725ba162c 157 * layer at which the pbuf is allocated and the requested size
segundo 0:ac1725ba162c 158 * (from the size parameter).
segundo 0:ac1725ba162c 159 *
segundo 0:ac1725ba162c 160 * @param layer flag to define header size
segundo 0:ac1725ba162c 161 * @param length size of the pbuf's payload
segundo 0:ac1725ba162c 162 * @param type this parameter decides how and where the pbuf
segundo 0:ac1725ba162c 163 * should be allocated as follows:
segundo 0:ac1725ba162c 164 *
segundo 0:ac1725ba162c 165 * - PBUF_RAM: buffer memory for pbuf is allocated as one large
segundo 0:ac1725ba162c 166 * chunk. This includes protocol headers as well.
segundo 0:ac1725ba162c 167 * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
segundo 0:ac1725ba162c 168 * protocol headers. Additional headers must be prepended
segundo 0:ac1725ba162c 169 * by allocating another pbuf and chain in to the front of
segundo 0:ac1725ba162c 170 * the ROM pbuf. It is assumed that the memory used is really
segundo 0:ac1725ba162c 171 * similar to ROM in that it is immutable and will not be
segundo 0:ac1725ba162c 172 * changed. Memory which is dynamic should generally not
segundo 0:ac1725ba162c 173 * be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
segundo 0:ac1725ba162c 174 * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
segundo 0:ac1725ba162c 175 * protocol headers. It is assumed that the pbuf is only
segundo 0:ac1725ba162c 176 * being used in a single thread. If the pbuf gets queued,
segundo 0:ac1725ba162c 177 * then pbuf_take should be called to copy the buffer.
segundo 0:ac1725ba162c 178 * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
segundo 0:ac1725ba162c 179 * the pbuf pool that is allocated during pbuf_init().
segundo 0:ac1725ba162c 180 *
segundo 0:ac1725ba162c 181 * @return the allocated pbuf. If multiple pbufs where allocated, this
segundo 0:ac1725ba162c 182 * is the first pbuf of a pbuf chain.
segundo 0:ac1725ba162c 183 */
segundo 0:ac1725ba162c 184 struct pbuf *
segundo 0:ac1725ba162c 185 pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
segundo 0:ac1725ba162c 186 {
segundo 0:ac1725ba162c 187 struct pbuf *p, *q, *r;
segundo 0:ac1725ba162c 188 u16_t offset;
segundo 0:ac1725ba162c 189 s32_t rem_len; /* remaining length */
segundo 0:ac1725ba162c 190 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
segundo 0:ac1725ba162c 191
segundo 0:ac1725ba162c 192 /* determine header offset */
segundo 0:ac1725ba162c 193 offset = 0;
segundo 0:ac1725ba162c 194 switch (layer) {
segundo 0:ac1725ba162c 195 case PBUF_TRANSPORT:
segundo 0:ac1725ba162c 196 /* add room for transport (often TCP) layer header */
segundo 0:ac1725ba162c 197 offset += PBUF_TRANSPORT_HLEN;
segundo 0:ac1725ba162c 198 /* FALLTHROUGH */
segundo 0:ac1725ba162c 199 case PBUF_IP:
segundo 0:ac1725ba162c 200 /* add room for IP layer header */
segundo 0:ac1725ba162c 201 offset += PBUF_IP_HLEN;
segundo 0:ac1725ba162c 202 /* FALLTHROUGH */
segundo 0:ac1725ba162c 203 case PBUF_LINK:
segundo 0:ac1725ba162c 204 /* add room for link layer header */
segundo 0:ac1725ba162c 205 offset += PBUF_LINK_HLEN;
segundo 0:ac1725ba162c 206 break;
segundo 0:ac1725ba162c 207 case PBUF_RAW:
segundo 0:ac1725ba162c 208 break;
segundo 0:ac1725ba162c 209 default:
segundo 0:ac1725ba162c 210 LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
segundo 0:ac1725ba162c 211 return NULL;
segundo 0:ac1725ba162c 212 }
segundo 0:ac1725ba162c 213
segundo 0:ac1725ba162c 214 switch (type) {
segundo 0:ac1725ba162c 215 case PBUF_POOL:
segundo 0:ac1725ba162c 216 /* allocate head of pbuf chain into p */
segundo 0:ac1725ba162c 217 p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
segundo 0:ac1725ba162c 218 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
segundo 0:ac1725ba162c 219 if (p == NULL) {
segundo 0:ac1725ba162c 220 PBUF_POOL_IS_EMPTY();
segundo 0:ac1725ba162c 221 return NULL;
segundo 0:ac1725ba162c 222 }
segundo 0:ac1725ba162c 223 p->type = type;
segundo 0:ac1725ba162c 224 p->next = NULL;
segundo 0:ac1725ba162c 225
segundo 0:ac1725ba162c 226 /* make the payload pointer point 'offset' bytes into pbuf data memory */
segundo 0:ac1725ba162c 227 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
segundo 0:ac1725ba162c 228 LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
segundo 0:ac1725ba162c 229 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
segundo 0:ac1725ba162c 230 /* the total length of the pbuf chain is the requested size */
segundo 0:ac1725ba162c 231 p->tot_len = length;
segundo 0:ac1725ba162c 232 /* set the length of the first pbuf in the chain */
segundo 0:ac1725ba162c 233 p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
segundo 0:ac1725ba162c 234 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
segundo 0:ac1725ba162c 235 ((u8_t*)p->payload + p->len <=
segundo 0:ac1725ba162c 236 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
segundo 0:ac1725ba162c 237 LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
segundo 0:ac1725ba162c 238 (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
segundo 0:ac1725ba162c 239 /* set reference count (needed here in case we fail) */
segundo 0:ac1725ba162c 240 p->ref = 1;
segundo 0:ac1725ba162c 241
segundo 0:ac1725ba162c 242 /* now allocate the tail of the pbuf chain */
segundo 0:ac1725ba162c 243
segundo 0:ac1725ba162c 244 /* remember first pbuf for linkage in next iteration */
segundo 0:ac1725ba162c 245 r = p;
segundo 0:ac1725ba162c 246 /* remaining length to be allocated */
segundo 0:ac1725ba162c 247 rem_len = length - p->len;
segundo 0:ac1725ba162c 248 /* any remaining pbufs to be allocated? */
segundo 0:ac1725ba162c 249 while (rem_len > 0) {
segundo 0:ac1725ba162c 250 q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
segundo 0:ac1725ba162c 251 if (q == NULL) {
segundo 0:ac1725ba162c 252 PBUF_POOL_IS_EMPTY();
segundo 0:ac1725ba162c 253 /* free chain so far allocated */
segundo 0:ac1725ba162c 254 pbuf_free(p);
segundo 0:ac1725ba162c 255 /* bail out unsuccesfully */
segundo 0:ac1725ba162c 256 return NULL;
segundo 0:ac1725ba162c 257 }
segundo 0:ac1725ba162c 258 q->type = type;
segundo 0:ac1725ba162c 259 q->flags = 0;
segundo 0:ac1725ba162c 260 q->next = NULL;
segundo 0:ac1725ba162c 261 /* make previous pbuf point to this pbuf */
segundo 0:ac1725ba162c 262 r->next = q;
segundo 0:ac1725ba162c 263 /* set total length of this pbuf and next in chain */
segundo 0:ac1725ba162c 264 LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
segundo 0:ac1725ba162c 265 q->tot_len = (u16_t)rem_len;
segundo 0:ac1725ba162c 266 /* this pbuf length is pool size, unless smaller sized tail */
segundo 0:ac1725ba162c 267 q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
segundo 0:ac1725ba162c 268 q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
segundo 0:ac1725ba162c 269 LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
segundo 0:ac1725ba162c 270 ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
segundo 0:ac1725ba162c 271 LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
segundo 0:ac1725ba162c 272 ((u8_t*)p->payload + p->len <=
segundo 0:ac1725ba162c 273 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
segundo 0:ac1725ba162c 274 q->ref = 1;
segundo 0:ac1725ba162c 275 /* calculate remaining length to be allocated */
segundo 0:ac1725ba162c 276 rem_len -= q->len;
segundo 0:ac1725ba162c 277 /* remember this pbuf for linkage in next iteration */
segundo 0:ac1725ba162c 278 r = q;
segundo 0:ac1725ba162c 279 }
segundo 0:ac1725ba162c 280 /* end of chain */
segundo 0:ac1725ba162c 281 /*r->next = NULL;*/
segundo 0:ac1725ba162c 282
segundo 0:ac1725ba162c 283 break;
segundo 0:ac1725ba162c 284 case PBUF_RAM:
segundo 0:ac1725ba162c 285 /* If pbuf is to be allocated in RAM, allocate memory for it. */
segundo 0:ac1725ba162c 286 p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
segundo 0:ac1725ba162c 287 if (p == NULL) {
segundo 0:ac1725ba162c 288 return NULL;
segundo 0:ac1725ba162c 289 }
segundo 0:ac1725ba162c 290 /* Set up internal structure of the pbuf. */
segundo 0:ac1725ba162c 291 p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
segundo 0:ac1725ba162c 292 p->len = p->tot_len = length;
segundo 0:ac1725ba162c 293 p->next = NULL;
segundo 0:ac1725ba162c 294 p->type = type;
segundo 0:ac1725ba162c 295
segundo 0:ac1725ba162c 296 LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
segundo 0:ac1725ba162c 297 ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
segundo 0:ac1725ba162c 298 break;
segundo 0:ac1725ba162c 299 /* pbuf references existing (non-volatile static constant) ROM payload? */
segundo 0:ac1725ba162c 300 case PBUF_ROM:
segundo 0:ac1725ba162c 301 /* pbuf references existing (externally allocated) RAM payload? */
segundo 0:ac1725ba162c 302 case PBUF_REF:
segundo 0:ac1725ba162c 303 /* only allocate memory for the pbuf structure */
segundo 0:ac1725ba162c 304 p = (struct pbuf *)memp_malloc(MEMP_PBUF);
segundo 0:ac1725ba162c 305 if (p == NULL) {
segundo 0:ac1725ba162c 306 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
segundo 0:ac1725ba162c 307 ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
segundo 0:ac1725ba162c 308 (type == PBUF_ROM) ? "ROM" : "REF"));
segundo 0:ac1725ba162c 309 return NULL;
segundo 0:ac1725ba162c 310 }
segundo 0:ac1725ba162c 311 /* caller must set this field properly, afterwards */
segundo 0:ac1725ba162c 312 p->payload = NULL;
segundo 0:ac1725ba162c 313 p->len = p->tot_len = length;
segundo 0:ac1725ba162c 314 p->next = NULL;
segundo 0:ac1725ba162c 315 p->type = type;
segundo 0:ac1725ba162c 316 break;
segundo 0:ac1725ba162c 317 default:
segundo 0:ac1725ba162c 318 LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
segundo 0:ac1725ba162c 319 return NULL;
segundo 0:ac1725ba162c 320 }
segundo 0:ac1725ba162c 321 /* set reference count */
segundo 0:ac1725ba162c 322 p->ref = 1;
segundo 0:ac1725ba162c 323 /* set flags */
segundo 0:ac1725ba162c 324 p->flags = 0;
segundo 0:ac1725ba162c 325 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
segundo 0:ac1725ba162c 326 return p;
segundo 0:ac1725ba162c 327 }
segundo 0:ac1725ba162c 328
segundo 0:ac1725ba162c 329 #if LWIP_SUPPORT_CUSTOM_PBUF
segundo 0:ac1725ba162c 330 /** Initialize a custom pbuf (already allocated).
segundo 0:ac1725ba162c 331 *
segundo 0:ac1725ba162c 332 * @param layer flag to define header size
segundo 0:ac1725ba162c 333 * @param length size of the pbuf's payload
segundo 0:ac1725ba162c 334 * @param type type of the pbuf (only used to treat the pbuf accordingly, as
segundo 0:ac1725ba162c 335 * this function allocates no memory)
segundo 0:ac1725ba162c 336 * @param p pointer to the custom pbuf to initialize (already allocated)
segundo 0:ac1725ba162c 337 * @param payload_mem pointer to the buffer that is used for payload and headers,
segundo 0:ac1725ba162c 338 * must be at least big enough to hold 'length' plus the header size,
segundo 0:ac1725ba162c 339 * may be NULL if set later
segundo 0:ac1725ba162c 340 * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
segundo 0:ac1725ba162c 341 * big enough to hold 'length' plus the header size
segundo 0:ac1725ba162c 342 */
segundo 0:ac1725ba162c 343 struct pbuf*
segundo 0:ac1725ba162c 344 pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
segundo 0:ac1725ba162c 345 void *payload_mem, u16_t payload_mem_len)
segundo 0:ac1725ba162c 346 {
segundo 0:ac1725ba162c 347 u16_t offset;
segundo 0:ac1725ba162c 348 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
segundo 0:ac1725ba162c 349
segundo 0:ac1725ba162c 350 /* determine header offset */
segundo 0:ac1725ba162c 351 offset = 0;
segundo 0:ac1725ba162c 352 switch (l) {
segundo 0:ac1725ba162c 353 case PBUF_TRANSPORT:
segundo 0:ac1725ba162c 354 /* add room for transport (often TCP) layer header */
segundo 0:ac1725ba162c 355 offset += PBUF_TRANSPORT_HLEN;
segundo 0:ac1725ba162c 356 /* FALLTHROUGH */
segundo 0:ac1725ba162c 357 case PBUF_IP:
segundo 0:ac1725ba162c 358 /* add room for IP layer header */
segundo 0:ac1725ba162c 359 offset += PBUF_IP_HLEN;
segundo 0:ac1725ba162c 360 /* FALLTHROUGH */
segundo 0:ac1725ba162c 361 case PBUF_LINK:
segundo 0:ac1725ba162c 362 /* add room for link layer header */
segundo 0:ac1725ba162c 363 offset += PBUF_LINK_HLEN;
segundo 0:ac1725ba162c 364 break;
segundo 0:ac1725ba162c 365 case PBUF_RAW:
segundo 0:ac1725ba162c 366 break;
segundo 0:ac1725ba162c 367 default:
segundo 0:ac1725ba162c 368 LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
segundo 0:ac1725ba162c 369 return NULL;
segundo 0:ac1725ba162c 370 }
segundo 0:ac1725ba162c 371
segundo 0:ac1725ba162c 372 if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
segundo 0:ac1725ba162c 373 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
segundo 0:ac1725ba162c 374 return NULL;
segundo 0:ac1725ba162c 375 }
segundo 0:ac1725ba162c 376
segundo 0:ac1725ba162c 377 p->pbuf.next = NULL;
segundo 0:ac1725ba162c 378 if (payload_mem != NULL) {
segundo 0:ac1725ba162c 379 p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
segundo 0:ac1725ba162c 380 } else {
segundo 0:ac1725ba162c 381 p->pbuf.payload = NULL;
segundo 0:ac1725ba162c 382 }
segundo 0:ac1725ba162c 383 p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
segundo 0:ac1725ba162c 384 p->pbuf.len = p->pbuf.tot_len = length;
segundo 0:ac1725ba162c 385 p->pbuf.type = type;
segundo 0:ac1725ba162c 386 p->pbuf.ref = 1;
segundo 0:ac1725ba162c 387 return &p->pbuf;
segundo 0:ac1725ba162c 388 }
segundo 0:ac1725ba162c 389 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */
segundo 0:ac1725ba162c 390
segundo 0:ac1725ba162c 391 /**
segundo 0:ac1725ba162c 392 * Shrink a pbuf chain to a desired length.
segundo 0:ac1725ba162c 393 *
segundo 0:ac1725ba162c 394 * @param p pbuf to shrink.
segundo 0:ac1725ba162c 395 * @param new_len desired new length of pbuf chain
segundo 0:ac1725ba162c 396 *
segundo 0:ac1725ba162c 397 * Depending on the desired length, the first few pbufs in a chain might
segundo 0:ac1725ba162c 398 * be skipped and left unchanged. The new last pbuf in the chain will be
segundo 0:ac1725ba162c 399 * resized, and any remaining pbufs will be freed.
segundo 0:ac1725ba162c 400 *
segundo 0:ac1725ba162c 401 * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
segundo 0:ac1725ba162c 402 * @note May not be called on a packet queue.
segundo 0:ac1725ba162c 403 *
segundo 0:ac1725ba162c 404 * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
segundo 0:ac1725ba162c 405 */
segundo 0:ac1725ba162c 406 void
segundo 0:ac1725ba162c 407 pbuf_realloc(struct pbuf *p, u16_t new_len)
segundo 0:ac1725ba162c 408 {
segundo 0:ac1725ba162c 409 struct pbuf *q;
segundo 0:ac1725ba162c 410 u16_t rem_len; /* remaining length */
segundo 0:ac1725ba162c 411 s32_t grow;
segundo 0:ac1725ba162c 412
segundo 0:ac1725ba162c 413 LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
segundo 0:ac1725ba162c 414 LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
segundo 0:ac1725ba162c 415 p->type == PBUF_ROM ||
segundo 0:ac1725ba162c 416 p->type == PBUF_RAM ||
segundo 0:ac1725ba162c 417 p->type == PBUF_REF);
segundo 0:ac1725ba162c 418
segundo 0:ac1725ba162c 419 /* desired length larger than current length? */
segundo 0:ac1725ba162c 420 if (new_len >= p->tot_len) {
segundo 0:ac1725ba162c 421 /* enlarging not yet supported */
segundo 0:ac1725ba162c 422 return;
segundo 0:ac1725ba162c 423 }
segundo 0:ac1725ba162c 424
segundo 0:ac1725ba162c 425 /* the pbuf chain grows by (new_len - p->tot_len) bytes
segundo 0:ac1725ba162c 426 * (which may be negative in case of shrinking) */
segundo 0:ac1725ba162c 427 grow = new_len - p->tot_len;
segundo 0:ac1725ba162c 428
segundo 0:ac1725ba162c 429 /* first, step over any pbufs that should remain in the chain */
segundo 0:ac1725ba162c 430 rem_len = new_len;
segundo 0:ac1725ba162c 431 q = p;
segundo 0:ac1725ba162c 432 /* should this pbuf be kept? */
segundo 0:ac1725ba162c 433 while (rem_len > q->len) {
segundo 0:ac1725ba162c 434 /* decrease remaining length by pbuf length */
segundo 0:ac1725ba162c 435 rem_len -= q->len;
segundo 0:ac1725ba162c 436 /* decrease total length indicator */
segundo 0:ac1725ba162c 437 LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
segundo 0:ac1725ba162c 438 q->tot_len += (u16_t)grow;
segundo 0:ac1725ba162c 439 /* proceed to next pbuf in chain */
segundo 0:ac1725ba162c 440 q = q->next;
segundo 0:ac1725ba162c 441 LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
segundo 0:ac1725ba162c 442 }
segundo 0:ac1725ba162c 443 /* we have now reached the new last pbuf (in q) */
segundo 0:ac1725ba162c 444 /* rem_len == desired length for pbuf q */
segundo 0:ac1725ba162c 445
segundo 0:ac1725ba162c 446 /* shrink allocated memory for PBUF_RAM */
segundo 0:ac1725ba162c 447 /* (other types merely adjust their length fields */
segundo 0:ac1725ba162c 448 if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
segundo 0:ac1725ba162c 449 /* reallocate and adjust the length of the pbuf that will be split */
segundo 0:ac1725ba162c 450 q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
segundo 0:ac1725ba162c 451 LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
segundo 0:ac1725ba162c 452 }
segundo 0:ac1725ba162c 453 /* adjust length fields for new last pbuf */
segundo 0:ac1725ba162c 454 q->len = rem_len;
segundo 0:ac1725ba162c 455 q->tot_len = q->len;
segundo 0:ac1725ba162c 456
segundo 0:ac1725ba162c 457 /* any remaining pbufs in chain? */
segundo 0:ac1725ba162c 458 if (q->next != NULL) {
segundo 0:ac1725ba162c 459 /* free remaining pbufs in chain */
segundo 0:ac1725ba162c 460 pbuf_free(q->next);
segundo 0:ac1725ba162c 461 }
segundo 0:ac1725ba162c 462 /* q is last packet in chain */
segundo 0:ac1725ba162c 463 q->next = NULL;
segundo 0:ac1725ba162c 464
segundo 0:ac1725ba162c 465 }
segundo 0:ac1725ba162c 466
segundo 0:ac1725ba162c 467 /**
segundo 0:ac1725ba162c 468 * Adjusts the payload pointer to hide or reveal headers in the payload.
segundo 0:ac1725ba162c 469 *
segundo 0:ac1725ba162c 470 * Adjusts the ->payload pointer so that space for a header
segundo 0:ac1725ba162c 471 * (dis)appears in the pbuf payload.
segundo 0:ac1725ba162c 472 *
segundo 0:ac1725ba162c 473 * The ->payload, ->tot_len and ->len fields are adjusted.
segundo 0:ac1725ba162c 474 *
segundo 0:ac1725ba162c 475 * @param p pbuf to change the header size.
segundo 0:ac1725ba162c 476 * @param header_size_increment Number of bytes to increment header size which
segundo 0:ac1725ba162c 477 * increases the size of the pbuf. New space is on the front.
segundo 0:ac1725ba162c 478 * (Using a negative value decreases the header size.)
segundo 0:ac1725ba162c 479 * If hdr_size_inc is 0, this function does nothing and returns succesful.
segundo 0:ac1725ba162c 480 *
segundo 0:ac1725ba162c 481 * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
segundo 0:ac1725ba162c 482 * the call will fail. A check is made that the increase in header size does
segundo 0:ac1725ba162c 483 * not move the payload pointer in front of the start of the buffer.
segundo 0:ac1725ba162c 484 * @return non-zero on failure, zero on success.
segundo 0:ac1725ba162c 485 *
segundo 0:ac1725ba162c 486 */
segundo 0:ac1725ba162c 487 u8_t
segundo 0:ac1725ba162c 488 pbuf_header(struct pbuf *p, s16_t header_size_increment)
segundo 0:ac1725ba162c 489 {
segundo 0:ac1725ba162c 490 u16_t type;
segundo 0:ac1725ba162c 491 void *payload;
segundo 0:ac1725ba162c 492 u16_t increment_magnitude;
segundo 0:ac1725ba162c 493
segundo 0:ac1725ba162c 494 LWIP_ASSERT("p != NULL", p != NULL);
segundo 0:ac1725ba162c 495 if ((header_size_increment == 0) || (p == NULL)) {
segundo 0:ac1725ba162c 496 return 0;
segundo 0:ac1725ba162c 497 }
segundo 0:ac1725ba162c 498
segundo 0:ac1725ba162c 499 if (header_size_increment < 0){
segundo 0:ac1725ba162c 500 increment_magnitude = -header_size_increment;
segundo 0:ac1725ba162c 501 /* Check that we aren't going to move off the end of the pbuf */
segundo 0:ac1725ba162c 502 LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
segundo 0:ac1725ba162c 503 } else {
segundo 0:ac1725ba162c 504 increment_magnitude = header_size_increment;
segundo 0:ac1725ba162c 505 #if 0
segundo 0:ac1725ba162c 506 /* Can't assert these as some callers speculatively call
segundo 0:ac1725ba162c 507 pbuf_header() to see if it's OK. Will return 1 below instead. */
segundo 0:ac1725ba162c 508 /* Check that we've got the correct type of pbuf to work with */
segundo 0:ac1725ba162c 509 LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
segundo 0:ac1725ba162c 510 p->type == PBUF_RAM || p->type == PBUF_POOL);
segundo 0:ac1725ba162c 511 /* Check that we aren't going to move off the beginning of the pbuf */
segundo 0:ac1725ba162c 512 LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
segundo 0:ac1725ba162c 513 (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
segundo 0:ac1725ba162c 514 #endif
segundo 0:ac1725ba162c 515 }
segundo 0:ac1725ba162c 516
segundo 0:ac1725ba162c 517 type = p->type;
segundo 0:ac1725ba162c 518 /* remember current payload pointer */
segundo 0:ac1725ba162c 519 payload = p->payload;
segundo 0:ac1725ba162c 520
segundo 0:ac1725ba162c 521 /* pbuf types containing payloads? */
segundo 0:ac1725ba162c 522 if (type == PBUF_RAM || type == PBUF_POOL) {
segundo 0:ac1725ba162c 523 /* set new payload pointer */
segundo 0:ac1725ba162c 524 p->payload = (u8_t *)p->payload - header_size_increment;
segundo 0:ac1725ba162c 525 /* boundary check fails? */
segundo 0:ac1725ba162c 526 if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
segundo 0:ac1725ba162c 527 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
segundo 0:ac1725ba162c 528 ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
segundo 0:ac1725ba162c 529 (void *)p->payload, (void *)(p + 1)));
segundo 0:ac1725ba162c 530 /* restore old payload pointer */
segundo 0:ac1725ba162c 531 p->payload = payload;
segundo 0:ac1725ba162c 532 /* bail out unsuccesfully */
segundo 0:ac1725ba162c 533 return 1;
segundo 0:ac1725ba162c 534 }
segundo 0:ac1725ba162c 535 /* pbuf types refering to external payloads? */
segundo 0:ac1725ba162c 536 } else if (type == PBUF_REF || type == PBUF_ROM) {
segundo 0:ac1725ba162c 537 /* hide a header in the payload? */
segundo 0:ac1725ba162c 538 if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
segundo 0:ac1725ba162c 539 /* increase payload pointer */
segundo 0:ac1725ba162c 540 p->payload = (u8_t *)p->payload - header_size_increment;
segundo 0:ac1725ba162c 541 } else {
segundo 0:ac1725ba162c 542 /* cannot expand payload to front (yet!)
segundo 0:ac1725ba162c 543 * bail out unsuccesfully */
segundo 0:ac1725ba162c 544 return 1;
segundo 0:ac1725ba162c 545 }
segundo 0:ac1725ba162c 546 } else {
segundo 0:ac1725ba162c 547 /* Unknown type */
segundo 0:ac1725ba162c 548 LWIP_ASSERT("bad pbuf type", 0);
segundo 0:ac1725ba162c 549 return 1;
segundo 0:ac1725ba162c 550 }
segundo 0:ac1725ba162c 551 /* modify pbuf length fields */
segundo 0:ac1725ba162c 552 p->len += header_size_increment;
segundo 0:ac1725ba162c 553 p->tot_len += header_size_increment;
segundo 0:ac1725ba162c 554
segundo 0:ac1725ba162c 555 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
segundo 0:ac1725ba162c 556 (void *)payload, (void *)p->payload, header_size_increment));
segundo 0:ac1725ba162c 557
segundo 0:ac1725ba162c 558 return 0;
segundo 0:ac1725ba162c 559 }
segundo 0:ac1725ba162c 560
segundo 0:ac1725ba162c 561 /**
segundo 0:ac1725ba162c 562 * Dereference a pbuf chain or queue and deallocate any no-longer-used
segundo 0:ac1725ba162c 563 * pbufs at the head of this chain or queue.
segundo 0:ac1725ba162c 564 *
segundo 0:ac1725ba162c 565 * Decrements the pbuf reference count. If it reaches zero, the pbuf is
segundo 0:ac1725ba162c 566 * deallocated.
segundo 0:ac1725ba162c 567 *
segundo 0:ac1725ba162c 568 * For a pbuf chain, this is repeated for each pbuf in the chain,
segundo 0:ac1725ba162c 569 * up to the first pbuf which has a non-zero reference count after
segundo 0:ac1725ba162c 570 * decrementing. So, when all reference counts are one, the whole
segundo 0:ac1725ba162c 571 * chain is free'd.
segundo 0:ac1725ba162c 572 *
segundo 0:ac1725ba162c 573 * @param p The pbuf (chain) to be dereferenced.
segundo 0:ac1725ba162c 574 *
segundo 0:ac1725ba162c 575 * @return the number of pbufs that were de-allocated
segundo 0:ac1725ba162c 576 * from the head of the chain.
segundo 0:ac1725ba162c 577 *
segundo 0:ac1725ba162c 578 * @note MUST NOT be called on a packet queue (Not verified to work yet).
segundo 0:ac1725ba162c 579 * @note the reference counter of a pbuf equals the number of pointers
segundo 0:ac1725ba162c 580 * that refer to the pbuf (or into the pbuf).
segundo 0:ac1725ba162c 581 *
segundo 0:ac1725ba162c 582 * @internal examples:
segundo 0:ac1725ba162c 583 *
segundo 0:ac1725ba162c 584 * Assuming existing chains a->b->c with the following reference
segundo 0:ac1725ba162c 585 * counts, calling pbuf_free(a) results in:
segundo 0:ac1725ba162c 586 *
segundo 0:ac1725ba162c 587 * 1->2->3 becomes ...1->3
segundo 0:ac1725ba162c 588 * 3->3->3 becomes 2->3->3
segundo 0:ac1725ba162c 589 * 1->1->2 becomes ......1
segundo 0:ac1725ba162c 590 * 2->1->1 becomes 1->1->1
segundo 0:ac1725ba162c 591 * 1->1->1 becomes .......
segundo 0:ac1725ba162c 592 *
segundo 0:ac1725ba162c 593 */
segundo 0:ac1725ba162c 594 u8_t
segundo 0:ac1725ba162c 595 pbuf_free(struct pbuf *p)
segundo 0:ac1725ba162c 596 {
segundo 0:ac1725ba162c 597 u16_t type;
segundo 0:ac1725ba162c 598 struct pbuf *q;
segundo 0:ac1725ba162c 599 u8_t count;
segundo 0:ac1725ba162c 600
segundo 0:ac1725ba162c 601 if (p == NULL) {
segundo 0:ac1725ba162c 602 LWIP_ASSERT("p != NULL", p != NULL);
segundo 0:ac1725ba162c 603 /* if assertions are disabled, proceed with debug output */
segundo 0:ac1725ba162c 604 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
segundo 0:ac1725ba162c 605 ("pbuf_free(p == NULL) was called.\n"));
segundo 0:ac1725ba162c 606 return 0;
segundo 0:ac1725ba162c 607 }
segundo 0:ac1725ba162c 608 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
segundo 0:ac1725ba162c 609
segundo 0:ac1725ba162c 610 PERF_START;
segundo 0:ac1725ba162c 611
segundo 0:ac1725ba162c 612 LWIP_ASSERT("pbuf_free: sane type",
segundo 0:ac1725ba162c 613 p->type == PBUF_RAM || p->type == PBUF_ROM ||
segundo 0:ac1725ba162c 614 p->type == PBUF_REF || p->type == PBUF_POOL);
segundo 0:ac1725ba162c 615
segundo 0:ac1725ba162c 616 count = 0;
segundo 0:ac1725ba162c 617 /* de-allocate all consecutive pbufs from the head of the chain that
segundo 0:ac1725ba162c 618 * obtain a zero reference count after decrementing*/
segundo 0:ac1725ba162c 619 while (p != NULL) {
segundo 0:ac1725ba162c 620 u16_t ref;
segundo 0:ac1725ba162c 621 SYS_ARCH_DECL_PROTECT(old_level);
segundo 0:ac1725ba162c 622 /* Since decrementing ref cannot be guaranteed to be a single machine operation
segundo 0:ac1725ba162c 623 * we must protect it. We put the new ref into a local variable to prevent
segundo 0:ac1725ba162c 624 * further protection. */
segundo 0:ac1725ba162c 625 SYS_ARCH_PROTECT(old_level);
segundo 0:ac1725ba162c 626 /* all pbufs in a chain are referenced at least once */
segundo 0:ac1725ba162c 627 LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
segundo 0:ac1725ba162c 628 /* decrease reference count (number of pointers to pbuf) */
segundo 0:ac1725ba162c 629 ref = --(p->ref);
segundo 0:ac1725ba162c 630 SYS_ARCH_UNPROTECT(old_level);
segundo 0:ac1725ba162c 631 /* this pbuf is no longer referenced to? */
segundo 0:ac1725ba162c 632 if (ref == 0) {
segundo 0:ac1725ba162c 633 /* remember next pbuf in chain for next iteration */
segundo 0:ac1725ba162c 634 q = p->next;
segundo 0:ac1725ba162c 635 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
segundo 0:ac1725ba162c 636 type = p->type;
segundo 0:ac1725ba162c 637 #if LWIP_SUPPORT_CUSTOM_PBUF
segundo 0:ac1725ba162c 638 /* is this a custom pbuf? */
segundo 0:ac1725ba162c 639 if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
segundo 0:ac1725ba162c 640 struct pbuf_custom *pc = (struct pbuf_custom*)p;
segundo 0:ac1725ba162c 641 LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
segundo 0:ac1725ba162c 642 pc->custom_free_function(p);
segundo 0:ac1725ba162c 643 } else
segundo 0:ac1725ba162c 644 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */
segundo 0:ac1725ba162c 645 {
segundo 0:ac1725ba162c 646 /* is this a pbuf from the pool? */
segundo 0:ac1725ba162c 647 if (type == PBUF_POOL) {
segundo 0:ac1725ba162c 648 memp_free(MEMP_PBUF_POOL, p);
segundo 0:ac1725ba162c 649 /* is this a ROM or RAM referencing pbuf? */
segundo 0:ac1725ba162c 650 } else if (type == PBUF_ROM || type == PBUF_REF) {
segundo 0:ac1725ba162c 651 memp_free(MEMP_PBUF, p);
segundo 0:ac1725ba162c 652 /* type == PBUF_RAM */
segundo 0:ac1725ba162c 653 } else {
segundo 0:ac1725ba162c 654 mem_free(p);
segundo 0:ac1725ba162c 655 }
segundo 0:ac1725ba162c 656 }
segundo 0:ac1725ba162c 657 count++;
segundo 0:ac1725ba162c 658 /* proceed to next pbuf */
segundo 0:ac1725ba162c 659 p = q;
segundo 0:ac1725ba162c 660 /* p->ref > 0, this pbuf is still referenced to */
segundo 0:ac1725ba162c 661 /* (and so the remaining pbufs in chain as well) */
segundo 0:ac1725ba162c 662 } else {
segundo 0:ac1725ba162c 663 LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
segundo 0:ac1725ba162c 664 /* stop walking through the chain */
segundo 0:ac1725ba162c 665 p = NULL;
segundo 0:ac1725ba162c 666 }
segundo 0:ac1725ba162c 667 }
segundo 0:ac1725ba162c 668 PERF_STOP("pbuf_free");
segundo 0:ac1725ba162c 669 /* return number of de-allocated pbufs */
segundo 0:ac1725ba162c 670 return count;
segundo 0:ac1725ba162c 671 }
segundo 0:ac1725ba162c 672
segundo 0:ac1725ba162c 673 /**
segundo 0:ac1725ba162c 674 * Count number of pbufs in a chain
segundo 0:ac1725ba162c 675 *
segundo 0:ac1725ba162c 676 * @param p first pbuf of chain
segundo 0:ac1725ba162c 677 * @return the number of pbufs in a chain
segundo 0:ac1725ba162c 678 */
segundo 0:ac1725ba162c 679
segundo 0:ac1725ba162c 680 u8_t
segundo 0:ac1725ba162c 681 pbuf_clen(struct pbuf *p)
segundo 0:ac1725ba162c 682 {
segundo 0:ac1725ba162c 683 u8_t len;
segundo 0:ac1725ba162c 684
segundo 0:ac1725ba162c 685 len = 0;
segundo 0:ac1725ba162c 686 while (p != NULL) {
segundo 0:ac1725ba162c 687 ++len;
segundo 0:ac1725ba162c 688 p = p->next;
segundo 0:ac1725ba162c 689 }
segundo 0:ac1725ba162c 690 return len;
segundo 0:ac1725ba162c 691 }
segundo 0:ac1725ba162c 692
segundo 0:ac1725ba162c 693 /**
segundo 0:ac1725ba162c 694 * Increment the reference count of the pbuf.
segundo 0:ac1725ba162c 695 *
segundo 0:ac1725ba162c 696 * @param p pbuf to increase reference counter of
segundo 0:ac1725ba162c 697 *
segundo 0:ac1725ba162c 698 */
segundo 0:ac1725ba162c 699 void
segundo 0:ac1725ba162c 700 pbuf_ref(struct pbuf *p)
segundo 0:ac1725ba162c 701 {
segundo 0:ac1725ba162c 702 SYS_ARCH_DECL_PROTECT(old_level);
segundo 0:ac1725ba162c 703 /* pbuf given? */
segundo 0:ac1725ba162c 704 if (p != NULL) {
segundo 0:ac1725ba162c 705 SYS_ARCH_PROTECT(old_level);
segundo 0:ac1725ba162c 706 ++(p->ref);
segundo 0:ac1725ba162c 707 SYS_ARCH_UNPROTECT(old_level);
segundo 0:ac1725ba162c 708 }
segundo 0:ac1725ba162c 709 }
segundo 0:ac1725ba162c 710
segundo 0:ac1725ba162c 711 /**
segundo 0:ac1725ba162c 712 * Concatenate two pbufs (each may be a pbuf chain) and take over
segundo 0:ac1725ba162c 713 * the caller's reference of the tail pbuf.
segundo 0:ac1725ba162c 714 *
segundo 0:ac1725ba162c 715 * @note The caller MAY NOT reference the tail pbuf afterwards.
segundo 0:ac1725ba162c 716 * Use pbuf_chain() for that purpose.
segundo 0:ac1725ba162c 717 *
segundo 0:ac1725ba162c 718 * @see pbuf_chain()
segundo 0:ac1725ba162c 719 */
segundo 0:ac1725ba162c 720
segundo 0:ac1725ba162c 721 void
segundo 0:ac1725ba162c 722 pbuf_cat(struct pbuf *h, struct pbuf *t)
segundo 0:ac1725ba162c 723 {
segundo 0:ac1725ba162c 724 struct pbuf *p;
segundo 0:ac1725ba162c 725
segundo 0:ac1725ba162c 726 LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
segundo 0:ac1725ba162c 727 ((h != NULL) && (t != NULL)), return;);
segundo 0:ac1725ba162c 728
segundo 0:ac1725ba162c 729 /* proceed to last pbuf of chain */
segundo 0:ac1725ba162c 730 for (p = h; p->next != NULL; p = p->next) {
segundo 0:ac1725ba162c 731 /* add total length of second chain to all totals of first chain */
segundo 0:ac1725ba162c 732 p->tot_len += t->tot_len;
segundo 0:ac1725ba162c 733 }
segundo 0:ac1725ba162c 734 /* { p is last pbuf of first h chain, p->next == NULL } */
segundo 0:ac1725ba162c 735 LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
segundo 0:ac1725ba162c 736 LWIP_ASSERT("p->next == NULL", p->next == NULL);
segundo 0:ac1725ba162c 737 /* add total length of second chain to last pbuf total of first chain */
segundo 0:ac1725ba162c 738 p->tot_len += t->tot_len;
segundo 0:ac1725ba162c 739 /* chain last pbuf of head (p) with first of tail (t) */
segundo 0:ac1725ba162c 740 p->next = t;
segundo 0:ac1725ba162c 741 /* p->next now references t, but the caller will drop its reference to t,
segundo 0:ac1725ba162c 742 * so netto there is no change to the reference count of t.
segundo 0:ac1725ba162c 743 */
segundo 0:ac1725ba162c 744 }
segundo 0:ac1725ba162c 745
segundo 0:ac1725ba162c 746 /**
segundo 0:ac1725ba162c 747 * Chain two pbufs (or pbuf chains) together.
segundo 0:ac1725ba162c 748 *
segundo 0:ac1725ba162c 749 * The caller MUST call pbuf_free(t) once it has stopped
segundo 0:ac1725ba162c 750 * using it. Use pbuf_cat() instead if you no longer use t.
segundo 0:ac1725ba162c 751 *
segundo 0:ac1725ba162c 752 * @param h head pbuf (chain)
segundo 0:ac1725ba162c 753 * @param t tail pbuf (chain)
segundo 0:ac1725ba162c 754 * @note The pbufs MUST belong to the same packet.
segundo 0:ac1725ba162c 755 * @note MAY NOT be called on a packet queue.
segundo 0:ac1725ba162c 756 *
segundo 0:ac1725ba162c 757 * The ->tot_len fields of all pbufs of the head chain are adjusted.
segundo 0:ac1725ba162c 758 * The ->next field of the last pbuf of the head chain is adjusted.
segundo 0:ac1725ba162c 759 * The ->ref field of the first pbuf of the tail chain is adjusted.
segundo 0:ac1725ba162c 760 *
segundo 0:ac1725ba162c 761 */
segundo 0:ac1725ba162c 762 void
segundo 0:ac1725ba162c 763 pbuf_chain(struct pbuf *h, struct pbuf *t)
segundo 0:ac1725ba162c 764 {
segundo 0:ac1725ba162c 765 pbuf_cat(h, t);
segundo 0:ac1725ba162c 766 /* t is now referenced by h */
segundo 0:ac1725ba162c 767 pbuf_ref(t);
segundo 0:ac1725ba162c 768 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
segundo 0:ac1725ba162c 769 }
segundo 0:ac1725ba162c 770
segundo 0:ac1725ba162c 771 /**
segundo 0:ac1725ba162c 772 * Dechains the first pbuf from its succeeding pbufs in the chain.
segundo 0:ac1725ba162c 773 *
segundo 0:ac1725ba162c 774 * Makes p->tot_len field equal to p->len.
segundo 0:ac1725ba162c 775 * @param p pbuf to dechain
segundo 0:ac1725ba162c 776 * @return remainder of the pbuf chain, or NULL if it was de-allocated.
segundo 0:ac1725ba162c 777 * @note May not be called on a packet queue.
segundo 0:ac1725ba162c 778 */
segundo 0:ac1725ba162c 779 struct pbuf *
segundo 0:ac1725ba162c 780 pbuf_dechain(struct pbuf *p)
segundo 0:ac1725ba162c 781 {
segundo 0:ac1725ba162c 782 struct pbuf *q;
segundo 0:ac1725ba162c 783 u8_t tail_gone = 1;
segundo 0:ac1725ba162c 784 /* tail */
segundo 0:ac1725ba162c 785 q = p->next;
segundo 0:ac1725ba162c 786 /* pbuf has successor in chain? */
segundo 0:ac1725ba162c 787 if (q != NULL) {
segundo 0:ac1725ba162c 788 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
segundo 0:ac1725ba162c 789 LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
segundo 0:ac1725ba162c 790 /* enforce invariant if assertion is disabled */
segundo 0:ac1725ba162c 791 q->tot_len = p->tot_len - p->len;
segundo 0:ac1725ba162c 792 /* decouple pbuf from remainder */
segundo 0:ac1725ba162c 793 p->next = NULL;
segundo 0:ac1725ba162c 794 /* total length of pbuf p is its own length only */
segundo 0:ac1725ba162c 795 p->tot_len = p->len;
segundo 0:ac1725ba162c 796 /* q is no longer referenced by p, free it */
segundo 0:ac1725ba162c 797 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
segundo 0:ac1725ba162c 798 tail_gone = pbuf_free(q);
segundo 0:ac1725ba162c 799 if (tail_gone > 0) {
segundo 0:ac1725ba162c 800 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
segundo 0:ac1725ba162c 801 ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
segundo 0:ac1725ba162c 802 }
segundo 0:ac1725ba162c 803 /* return remaining tail or NULL if deallocated */
segundo 0:ac1725ba162c 804 }
segundo 0:ac1725ba162c 805 /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
segundo 0:ac1725ba162c 806 LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
segundo 0:ac1725ba162c 807 return ((tail_gone > 0) ? NULL : q);
segundo 0:ac1725ba162c 808 }
segundo 0:ac1725ba162c 809
segundo 0:ac1725ba162c 810 /**
segundo 0:ac1725ba162c 811 *
segundo 0:ac1725ba162c 812 * Create PBUF_RAM copies of pbufs.
segundo 0:ac1725ba162c 813 *
segundo 0:ac1725ba162c 814 * Used to queue packets on behalf of the lwIP stack, such as
segundo 0:ac1725ba162c 815 * ARP based queueing.
segundo 0:ac1725ba162c 816 *
segundo 0:ac1725ba162c 817 * @note You MUST explicitly use p = pbuf_take(p);
segundo 0:ac1725ba162c 818 *
segundo 0:ac1725ba162c 819 * @note Only one packet is copied, no packet queue!
segundo 0:ac1725ba162c 820 *
segundo 0:ac1725ba162c 821 * @param p_to pbuf destination of the copy
segundo 0:ac1725ba162c 822 * @param p_from pbuf source of the copy
segundo 0:ac1725ba162c 823 *
segundo 0:ac1725ba162c 824 * @return ERR_OK if pbuf was copied
segundo 0:ac1725ba162c 825 * ERR_ARG if one of the pbufs is NULL or p_to is not big
segundo 0:ac1725ba162c 826 * enough to hold p_from
segundo 0:ac1725ba162c 827 */
segundo 0:ac1725ba162c 828 err_t
segundo 0:ac1725ba162c 829 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
segundo 0:ac1725ba162c 830 {
segundo 0:ac1725ba162c 831 u16_t offset_to=0, offset_from=0, len;
segundo 0:ac1725ba162c 832
segundo 0:ac1725ba162c 833 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
segundo 0:ac1725ba162c 834 (void*)p_to, (void*)p_from));
segundo 0:ac1725ba162c 835
segundo 0:ac1725ba162c 836 /* is the target big enough to hold the source? */
segundo 0:ac1725ba162c 837 LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
segundo 0:ac1725ba162c 838 (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
segundo 0:ac1725ba162c 839
segundo 0:ac1725ba162c 840 /* iterate through pbuf chain */
segundo 0:ac1725ba162c 841 do
segundo 0:ac1725ba162c 842 {
segundo 0:ac1725ba162c 843 LWIP_ASSERT("p_to != NULL", p_to != NULL);
segundo 0:ac1725ba162c 844 /* copy one part of the original chain */
segundo 0:ac1725ba162c 845 if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
segundo 0:ac1725ba162c 846 /* complete current p_from fits into current p_to */
segundo 0:ac1725ba162c 847 len = p_from->len - offset_from;
segundo 0:ac1725ba162c 848 } else {
segundo 0:ac1725ba162c 849 /* current p_from does not fit into current p_to */
segundo 0:ac1725ba162c 850 len = p_to->len - offset_to;
segundo 0:ac1725ba162c 851 }
segundo 0:ac1725ba162c 852 MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
segundo 0:ac1725ba162c 853 offset_to += len;
segundo 0:ac1725ba162c 854 offset_from += len;
segundo 0:ac1725ba162c 855 LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
segundo 0:ac1725ba162c 856 if (offset_to == p_to->len) {
segundo 0:ac1725ba162c 857 /* on to next p_to (if any) */
segundo 0:ac1725ba162c 858 offset_to = 0;
segundo 0:ac1725ba162c 859 p_to = p_to->next;
segundo 0:ac1725ba162c 860 }
segundo 0:ac1725ba162c 861 LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
segundo 0:ac1725ba162c 862 if (offset_from >= p_from->len) {
segundo 0:ac1725ba162c 863 /* on to next p_from (if any) */
segundo 0:ac1725ba162c 864 offset_from = 0;
segundo 0:ac1725ba162c 865 p_from = p_from->next;
segundo 0:ac1725ba162c 866 }
segundo 0:ac1725ba162c 867
segundo 0:ac1725ba162c 868 if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
segundo 0:ac1725ba162c 869 /* don't copy more than one packet! */
segundo 0:ac1725ba162c 870 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
segundo 0:ac1725ba162c 871 (p_from->next == NULL), return ERR_VAL;);
segundo 0:ac1725ba162c 872 }
segundo 0:ac1725ba162c 873 if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
segundo 0:ac1725ba162c 874 /* don't copy more than one packet! */
segundo 0:ac1725ba162c 875 LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
segundo 0:ac1725ba162c 876 (p_to->next == NULL), return ERR_VAL;);
segundo 0:ac1725ba162c 877 }
segundo 0:ac1725ba162c 878 } while (p_from);
segundo 0:ac1725ba162c 879 LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
segundo 0:ac1725ba162c 880 return ERR_OK;
segundo 0:ac1725ba162c 881 }
segundo 0:ac1725ba162c 882
segundo 0:ac1725ba162c 883 /**
segundo 0:ac1725ba162c 884 * Copy (part of) the contents of a packet buffer
segundo 0:ac1725ba162c 885 * to an application supplied buffer.
segundo 0:ac1725ba162c 886 *
segundo 0:ac1725ba162c 887 * @param buf the pbuf from which to copy data
segundo 0:ac1725ba162c 888 * @param dataptr the application supplied buffer
segundo 0:ac1725ba162c 889 * @param len length of data to copy (dataptr must be big enough). No more
segundo 0:ac1725ba162c 890 * than buf->tot_len will be copied, irrespective of len
segundo 0:ac1725ba162c 891 * @param offset offset into the packet buffer from where to begin copying len bytes
segundo 0:ac1725ba162c 892 * @return the number of bytes copied, or 0 on failure
segundo 0:ac1725ba162c 893 */
segundo 0:ac1725ba162c 894 u16_t
segundo 0:ac1725ba162c 895 pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
segundo 0:ac1725ba162c 896 {
segundo 0:ac1725ba162c 897 struct pbuf *p;
segundo 0:ac1725ba162c 898 u16_t left;
segundo 0:ac1725ba162c 899 u16_t buf_copy_len;
segundo 0:ac1725ba162c 900 u16_t copied_total = 0;
segundo 0:ac1725ba162c 901
segundo 0:ac1725ba162c 902 LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
segundo 0:ac1725ba162c 903 LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
segundo 0:ac1725ba162c 904
segundo 0:ac1725ba162c 905 left = 0;
segundo 0:ac1725ba162c 906
segundo 0:ac1725ba162c 907 if((buf == NULL) || (dataptr == NULL)) {
segundo 0:ac1725ba162c 908 return 0;
segundo 0:ac1725ba162c 909 }
segundo 0:ac1725ba162c 910
segundo 0:ac1725ba162c 911 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
segundo 0:ac1725ba162c 912 for(p = buf; len != 0 && p != NULL; p = p->next) {
segundo 0:ac1725ba162c 913 if ((offset != 0) && (offset >= p->len)) {
segundo 0:ac1725ba162c 914 /* don't copy from this buffer -> on to the next */
segundo 0:ac1725ba162c 915 offset -= p->len;
segundo 0:ac1725ba162c 916 } else {
segundo 0:ac1725ba162c 917 /* copy from this buffer. maybe only partially. */
segundo 0:ac1725ba162c 918 buf_copy_len = p->len - offset;
segundo 0:ac1725ba162c 919 if (buf_copy_len > len)
segundo 0:ac1725ba162c 920 buf_copy_len = len;
segundo 0:ac1725ba162c 921 /* copy the necessary parts of the buffer */
segundo 0:ac1725ba162c 922 MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
segundo 0:ac1725ba162c 923 copied_total += buf_copy_len;
segundo 0:ac1725ba162c 924 left += buf_copy_len;
segundo 0:ac1725ba162c 925 len -= buf_copy_len;
segundo 0:ac1725ba162c 926 offset = 0;
segundo 0:ac1725ba162c 927 }
segundo 0:ac1725ba162c 928 }
segundo 0:ac1725ba162c 929 return copied_total;
segundo 0:ac1725ba162c 930 }
segundo 0:ac1725ba162c 931
segundo 0:ac1725ba162c 932 /**
segundo 0:ac1725ba162c 933 * Copy application supplied data into a pbuf.
segundo 0:ac1725ba162c 934 * This function can only be used to copy the equivalent of buf->tot_len data.
segundo 0:ac1725ba162c 935 *
segundo 0:ac1725ba162c 936 * @param buf pbuf to fill with data
segundo 0:ac1725ba162c 937 * @param dataptr application supplied data buffer
segundo 0:ac1725ba162c 938 * @param len length of the application supplied data buffer
segundo 0:ac1725ba162c 939 *
segundo 0:ac1725ba162c 940 * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
segundo 0:ac1725ba162c 941 */
segundo 0:ac1725ba162c 942 err_t
segundo 0:ac1725ba162c 943 pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
segundo 0:ac1725ba162c 944 {
segundo 0:ac1725ba162c 945 struct pbuf *p;
segundo 0:ac1725ba162c 946 u16_t buf_copy_len;
segundo 0:ac1725ba162c 947 u16_t total_copy_len = len;
segundo 0:ac1725ba162c 948 u16_t copied_total = 0;
segundo 0:ac1725ba162c 949
segundo 0:ac1725ba162c 950 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
segundo 0:ac1725ba162c 951 LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
segundo 0:ac1725ba162c 952
segundo 0:ac1725ba162c 953 if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
segundo 0:ac1725ba162c 954 return ERR_ARG;
segundo 0:ac1725ba162c 955 }
segundo 0:ac1725ba162c 956
segundo 0:ac1725ba162c 957 /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
segundo 0:ac1725ba162c 958 for(p = buf; total_copy_len != 0; p = p->next) {
segundo 0:ac1725ba162c 959 LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
segundo 0:ac1725ba162c 960 buf_copy_len = total_copy_len;
segundo 0:ac1725ba162c 961 if (buf_copy_len > p->len) {
segundo 0:ac1725ba162c 962 /* this pbuf cannot hold all remaining data */
segundo 0:ac1725ba162c 963 buf_copy_len = p->len;
segundo 0:ac1725ba162c 964 }
segundo 0:ac1725ba162c 965 /* copy the necessary parts of the buffer */
segundo 0:ac1725ba162c 966 MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
segundo 0:ac1725ba162c 967 total_copy_len -= buf_copy_len;
segundo 0:ac1725ba162c 968 copied_total += buf_copy_len;
segundo 0:ac1725ba162c 969 }
segundo 0:ac1725ba162c 970 LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
segundo 0:ac1725ba162c 971 return ERR_OK;
segundo 0:ac1725ba162c 972 }
segundo 0:ac1725ba162c 973
segundo 0:ac1725ba162c 974 /**
segundo 0:ac1725ba162c 975 * Creates a single pbuf out of a queue of pbufs.
segundo 0:ac1725ba162c 976 *
segundo 0:ac1725ba162c 977 * @remark: Either the source pbuf 'p' is freed by this function or the original
segundo 0:ac1725ba162c 978 * pbuf 'p' is returned, therefore the caller has to check the result!
segundo 0:ac1725ba162c 979 *
segundo 0:ac1725ba162c 980 * @param p the source pbuf
segundo 0:ac1725ba162c 981 * @param layer pbuf_layer of the new pbuf
segundo 0:ac1725ba162c 982 *
segundo 0:ac1725ba162c 983 * @return a new, single pbuf (p->next is NULL)
segundo 0:ac1725ba162c 984 * or the old pbuf if allocation fails
segundo 0:ac1725ba162c 985 */
segundo 0:ac1725ba162c 986 struct pbuf*
segundo 0:ac1725ba162c 987 pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
segundo 0:ac1725ba162c 988 {
segundo 0:ac1725ba162c 989 struct pbuf *q;
segundo 0:ac1725ba162c 990 err_t err;
segundo 0:ac1725ba162c 991 if (p->next == NULL) {
segundo 0:ac1725ba162c 992 return p;
segundo 0:ac1725ba162c 993 }
segundo 0:ac1725ba162c 994 q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
segundo 0:ac1725ba162c 995 if (q == NULL) {
segundo 0:ac1725ba162c 996 /* @todo: what do we do now? */
segundo 0:ac1725ba162c 997 return p;
segundo 0:ac1725ba162c 998 }
segundo 0:ac1725ba162c 999 err = pbuf_copy(q, p);
segundo 0:ac1725ba162c 1000 LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
segundo 0:ac1725ba162c 1001 pbuf_free(p);
segundo 0:ac1725ba162c 1002 return q;
segundo 0:ac1725ba162c 1003 }
segundo 0:ac1725ba162c 1004
segundo 0:ac1725ba162c 1005 #if LWIP_CHECKSUM_ON_COPY
segundo 0:ac1725ba162c 1006 /**
segundo 0:ac1725ba162c 1007 * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
segundo 0:ac1725ba162c 1008 * the checksum while copying
segundo 0:ac1725ba162c 1009 *
segundo 0:ac1725ba162c 1010 * @param p the pbuf to copy data into
segundo 0:ac1725ba162c 1011 * @param start_offset offset of p->payload where to copy the data to
segundo 0:ac1725ba162c 1012 * @param dataptr data to copy into the pbuf
segundo 0:ac1725ba162c 1013 * @param len length of data to copy into the pbuf
segundo 0:ac1725ba162c 1014 * @param chksum pointer to the checksum which is updated
segundo 0:ac1725ba162c 1015 * @return ERR_OK if successful, another error if the data does not fit
segundo 0:ac1725ba162c 1016 * within the (first) pbuf (no pbuf queues!)
segundo 0:ac1725ba162c 1017 */
segundo 0:ac1725ba162c 1018 err_t
segundo 0:ac1725ba162c 1019 pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
segundo 0:ac1725ba162c 1020 u16_t len, u16_t *chksum)
segundo 0:ac1725ba162c 1021 {
segundo 0:ac1725ba162c 1022 u32_t acc;
segundo 0:ac1725ba162c 1023 u16_t copy_chksum;
segundo 0:ac1725ba162c 1024 char *dst_ptr;
segundo 0:ac1725ba162c 1025 LWIP_ASSERT("p != NULL", p != NULL);
segundo 0:ac1725ba162c 1026 LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
segundo 0:ac1725ba162c 1027 LWIP_ASSERT("chksum != NULL", chksum != NULL);
segundo 0:ac1725ba162c 1028 LWIP_ASSERT("len != 0", len != 0);
segundo 0:ac1725ba162c 1029
segundo 0:ac1725ba162c 1030 if ((start_offset >= p->len) || (start_offset + len > p->len)) {
segundo 0:ac1725ba162c 1031 return ERR_ARG;
segundo 0:ac1725ba162c 1032 }
segundo 0:ac1725ba162c 1033
segundo 0:ac1725ba162c 1034 dst_ptr = ((char*)p->payload) + start_offset;
segundo 0:ac1725ba162c 1035 copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
segundo 0:ac1725ba162c 1036 if ((start_offset & 1) != 0) {
segundo 0:ac1725ba162c 1037 copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
segundo 0:ac1725ba162c 1038 }
segundo 0:ac1725ba162c 1039 acc = *chksum;
segundo 0:ac1725ba162c 1040 acc += copy_chksum;
segundo 0:ac1725ba162c 1041 *chksum = FOLD_U32T(acc);
segundo 0:ac1725ba162c 1042 return ERR_OK;
segundo 0:ac1725ba162c 1043 }
segundo 0:ac1725ba162c 1044 #endif /* LWIP_CHECKSUM_ON_COPY */
segundo 0:ac1725ba162c 1045
segundo 0:ac1725ba162c 1046 /** Get one byte from the specified position in a pbuf
segundo 0:ac1725ba162c 1047 * WARNING: returns zero for offset >= p->tot_len
segundo 0:ac1725ba162c 1048 *
segundo 0:ac1725ba162c 1049 * @param p pbuf to parse
segundo 0:ac1725ba162c 1050 * @param offset offset into p of the byte to return
segundo 0:ac1725ba162c 1051 * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
segundo 0:ac1725ba162c 1052 */
segundo 0:ac1725ba162c 1053 u8_t
segundo 0:ac1725ba162c 1054 pbuf_get_at(struct pbuf* p, u16_t offset)
segundo 0:ac1725ba162c 1055 {
segundo 0:ac1725ba162c 1056 u16_t copy_from = offset;
segundo 0:ac1725ba162c 1057 struct pbuf* q = p;
segundo 0:ac1725ba162c 1058
segundo 0:ac1725ba162c 1059 /* get the correct pbuf */
segundo 0:ac1725ba162c 1060 while ((q != NULL) && (q->len <= copy_from)) {
segundo 0:ac1725ba162c 1061 copy_from -= q->len;
segundo 0:ac1725ba162c 1062 q = q->next;
segundo 0:ac1725ba162c 1063 }
segundo 0:ac1725ba162c 1064 /* return requested data if pbuf is OK */
segundo 0:ac1725ba162c 1065 if ((q != NULL) && (q->len > copy_from)) {
segundo 0:ac1725ba162c 1066 return ((u8_t*)q->payload)[copy_from];
segundo 0:ac1725ba162c 1067 }
segundo 0:ac1725ba162c 1068 return 0;
segundo 0:ac1725ba162c 1069 }
segundo 0:ac1725ba162c 1070
segundo 0:ac1725ba162c 1071 /** Compare pbuf contents at specified offset with memory s2, both of length n
segundo 0:ac1725ba162c 1072 *
segundo 0:ac1725ba162c 1073 * @param p pbuf to compare
segundo 0:ac1725ba162c 1074 * @param offset offset into p at wich to start comparing
segundo 0:ac1725ba162c 1075 * @param s2 buffer to compare
segundo 0:ac1725ba162c 1076 * @param n length of buffer to compare
segundo 0:ac1725ba162c 1077 * @return zero if equal, nonzero otherwise
segundo 0:ac1725ba162c 1078 * (0xffff if p is too short, diffoffset+1 otherwise)
segundo 0:ac1725ba162c 1079 */
segundo 0:ac1725ba162c 1080 u16_t
segundo 0:ac1725ba162c 1081 pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
segundo 0:ac1725ba162c 1082 {
segundo 0:ac1725ba162c 1083 u16_t start = offset;
segundo 0:ac1725ba162c 1084 struct pbuf* q = p;
segundo 0:ac1725ba162c 1085
segundo 0:ac1725ba162c 1086 /* get the correct pbuf */
segundo 0:ac1725ba162c 1087 while ((q != NULL) && (q->len <= start)) {
segundo 0:ac1725ba162c 1088 start -= q->len;
segundo 0:ac1725ba162c 1089 q = q->next;
segundo 0:ac1725ba162c 1090 }
segundo 0:ac1725ba162c 1091 /* return requested data if pbuf is OK */
segundo 0:ac1725ba162c 1092 if ((q != NULL) && (q->len > start)) {
segundo 0:ac1725ba162c 1093 u16_t i;
segundo 0:ac1725ba162c 1094 for(i = 0; i < n; i++) {
segundo 0:ac1725ba162c 1095 u8_t a = pbuf_get_at(q, start + i);
segundo 0:ac1725ba162c 1096 u8_t b = ((u8_t*)s2)[i];
segundo 0:ac1725ba162c 1097 if (a != b) {
segundo 0:ac1725ba162c 1098 return i+1;
segundo 0:ac1725ba162c 1099 }
segundo 0:ac1725ba162c 1100 }
segundo 0:ac1725ba162c 1101 return 0;
segundo 0:ac1725ba162c 1102 }
segundo 0:ac1725ba162c 1103 return 0xffff;
segundo 0:ac1725ba162c 1104 }
segundo 0:ac1725ba162c 1105
segundo 0:ac1725ba162c 1106 /** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
segundo 0:ac1725ba162c 1107 * start_offset.
segundo 0:ac1725ba162c 1108 *
segundo 0:ac1725ba162c 1109 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
segundo 0:ac1725ba162c 1110 * return value 'not found'
segundo 0:ac1725ba162c 1111 * @param mem search for the contents of this buffer
segundo 0:ac1725ba162c 1112 * @param mem_len length of 'mem'
segundo 0:ac1725ba162c 1113 * @param start_offset offset into p at which to start searching
segundo 0:ac1725ba162c 1114 * @return 0xFFFF if substr was not found in p or the index where it was found
segundo 0:ac1725ba162c 1115 */
segundo 0:ac1725ba162c 1116 u16_t
segundo 0:ac1725ba162c 1117 pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
segundo 0:ac1725ba162c 1118 {
segundo 0:ac1725ba162c 1119 u16_t i;
segundo 0:ac1725ba162c 1120 u16_t max = p->tot_len - mem_len;
segundo 0:ac1725ba162c 1121 if (p->tot_len >= mem_len + start_offset) {
segundo 0:ac1725ba162c 1122 for(i = start_offset; i <= max; ) {
segundo 0:ac1725ba162c 1123 u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
segundo 0:ac1725ba162c 1124 if (plus == 0) {
segundo 0:ac1725ba162c 1125 return i;
segundo 0:ac1725ba162c 1126 } else {
segundo 0:ac1725ba162c 1127 i += plus;
segundo 0:ac1725ba162c 1128 }
segundo 0:ac1725ba162c 1129 }
segundo 0:ac1725ba162c 1130 }
segundo 0:ac1725ba162c 1131 return 0xFFFF;
segundo 0:ac1725ba162c 1132 }
segundo 0:ac1725ba162c 1133
segundo 0:ac1725ba162c 1134 /** Find occurrence of substr with length substr_len in pbuf p, start at offset
segundo 0:ac1725ba162c 1135 * start_offset
segundo 0:ac1725ba162c 1136 * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
segundo 0:ac1725ba162c 1137 * the pbuf/source string!
segundo 0:ac1725ba162c 1138 *
segundo 0:ac1725ba162c 1139 * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
segundo 0:ac1725ba162c 1140 * return value 'not found'
segundo 0:ac1725ba162c 1141 * @param substr string to search for in p, maximum length is 0xFFFE
segundo 0:ac1725ba162c 1142 * @return 0xFFFF if substr was not found in p or the index where it was found
segundo 0:ac1725ba162c 1143 */
segundo 0:ac1725ba162c 1144 u16_t
segundo 0:ac1725ba162c 1145 pbuf_strstr(struct pbuf* p, const char* substr)
segundo 0:ac1725ba162c 1146 {
segundo 0:ac1725ba162c 1147 size_t substr_len;
segundo 0:ac1725ba162c 1148 if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
segundo 0:ac1725ba162c 1149 return 0xFFFF;
segundo 0:ac1725ba162c 1150 }
segundo 0:ac1725ba162c 1151 substr_len = strlen(substr);
segundo 0:ac1725ba162c 1152 if (substr_len >= 0xFFFF) {
segundo 0:ac1725ba162c 1153 return 0xFFFF;
segundo 0:ac1725ba162c 1154 }
segundo 0:ac1725ba162c 1155 return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
segundo 0:ac1725ba162c 1156 }