]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_MCF5235_GCC/lwip/src/core/pbuf.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_MCF5235_GCC / lwip / src / core / pbuf.c
1 /**\r
2  * @file\r
3  * Packet buffer management\r
4  *\r
5  * Packets are built from the pbuf data structure. It supports dynamic\r
6  * memory allocation for packet contents or can reference externally\r
7  * managed packet contents both in RAM and ROM. Quick allocation for\r
8  * incoming packets is provided through pools with fixed sized pbufs.\r
9  *\r
10  * A packet may span over multiple pbufs, chained as a singly linked\r
11  * list. This is called a "pbuf chain".\r
12  *\r
13  * Multiple packets may be queued, also using this singly linked list.\r
14  * This is called a "packet queue".\r
15  * \r
16  * So, a packet queue consists of one or more pbuf chains, each of\r
17  * which consist of one or more pbufs. Currently, queues are only\r
18  * supported in a limited section of lwIP, this is the etharp queueing\r
19  * code. Outside of this section no packet queues are supported yet.\r
20  * \r
21  * The differences between a pbuf chain and a packet queue are very\r
22  * precise but subtle. \r
23  *\r
24  * The last pbuf of a packet has a ->tot_len field that equals the\r
25  * ->len field. It can be found by traversing the list. If the last\r
26  * pbuf of a packet has a ->next field other than NULL, more packets\r
27  * are on the queue.\r
28  *\r
29  * Therefore, looping through a pbuf of a single packet, has an\r
30  * loop end condition (tot_len == p->len), NOT (next == NULL).\r
31  */\r
32 \r
33 /*\r
34  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
35  * All rights reserved.\r
36  *\r
37  * Redistribution and use in source and binary forms, with or without modification,\r
38  * are permitted provided that the following conditions are met:\r
39  *\r
40  * 1. Redistributions of source code must retain the above copyright notice,\r
41  *    this list of conditions and the following disclaimer.\r
42  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
43  *    this list of conditions and the following disclaimer in the documentation\r
44  *    and/or other materials provided with the distribution.\r
45  * 3. The name of the author may not be used to endorse or promote products\r
46  *    derived from this software without specific prior written permission.\r
47  *\r
48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
49  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
50  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
51  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
52  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
53  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
56  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
57  * OF SUCH DAMAGE.\r
58  *\r
59  * This file is part of the lwIP TCP/IP stack.\r
60  *\r
61  * Author: Adam Dunkels <adam@sics.se>\r
62  *\r
63  */\r
64 \r
65 #include <string.h>\r
66 \r
67 #include "lwip/opt.h"\r
68 #include "lwip/stats.h"\r
69 #include "lwip/def.h"\r
70 #include "lwip/mem.h"\r
71 #include "lwip/memp.h"\r
72 #include "lwip/pbuf.h"\r
73 #include "lwip/sys.h"\r
74 #include "arch/perf.h"\r
75 \r
76 static u8_t pbuf_pool_memory[MEM_ALIGNMENT - 1 + PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf))];\r
77 \r
78 #if !SYS_LIGHTWEIGHT_PROT\r
79 static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;\r
80 static sys_sem_t pbuf_pool_free_sem;\r
81 #endif\r
82 \r
83 static struct pbuf *pbuf_pool = NULL;\r
84 \r
85 /**\r
86  * Initializes the pbuf module.\r
87  *\r
88  * A large part of memory is allocated for holding the pool of pbufs.\r
89  * The size of the individual pbufs in the pool is given by the size\r
90  * parameter, and the number of pbufs in the pool by the num parameter.\r
91  *\r
92  * After the memory has been allocated, the pbufs are set up. The\r
93  * ->next pointer in each pbuf is set up to point to the next pbuf in\r
94  * the pool.\r
95  *\r
96  */\r
97 void\r
98 pbuf_init(void)\r
99 {\r
100   struct pbuf *p, *q = NULL;\r
101   u16_t i;\r
102 \r
103   pbuf_pool = (struct pbuf *)MEM_ALIGN(pbuf_pool_memory);\r
104 \r
105 #if PBUF_STATS\r
106   lwip_stats.pbuf.avail = PBUF_POOL_SIZE;\r
107 #endif /* PBUF_STATS */\r
108 \r
109   /* Set up ->next pointers to link the pbufs of the pool together */\r
110   p = pbuf_pool;\r
111 \r
112   for(i = 0; i < PBUF_POOL_SIZE; ++i) {\r
113     p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));\r
114     p->len = p->tot_len = PBUF_POOL_BUFSIZE;\r
115     p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));\r
116     p->flags = PBUF_FLAG_POOL;\r
117     q = p;\r
118     p = p->next;\r
119   }\r
120 \r
121   /* The ->next pointer of last pbuf is NULL to indicate that there\r
122      are no more pbufs in the pool */\r
123   q->next = NULL;\r
124 \r
125 #if !SYS_LIGHTWEIGHT_PROT\r
126   pbuf_pool_alloc_lock = 0;\r
127   pbuf_pool_free_lock = 0;\r
128   pbuf_pool_free_sem = sys_sem_new(1);\r
129 #endif\r
130 }\r
131 \r
132 /**\r
133  * @internal only called from pbuf_alloc()\r
134  */\r
135 static struct pbuf *\r
136 pbuf_pool_alloc(void)\r
137 {\r
138   struct pbuf *p = NULL;\r
139 \r
140   SYS_ARCH_DECL_PROTECT(old_level);\r
141   SYS_ARCH_PROTECT(old_level);\r
142 \r
143 #if !SYS_LIGHTWEIGHT_PROT\r
144   /* Next, check the actual pbuf pool, but if the pool is locked, we\r
145      pretend to be out of buffers and return NULL. */\r
146   if (pbuf_pool_free_lock) {\r
147 #if PBUF_STATS\r
148     ++lwip_stats.pbuf.alloc_locked;\r
149 #endif /* PBUF_STATS */\r
150     return NULL;\r
151   }\r
152   pbuf_pool_alloc_lock = 1;\r
153   if (!pbuf_pool_free_lock) {\r
154 #endif /* SYS_LIGHTWEIGHT_PROT */\r
155     p = pbuf_pool;\r
156     if (p) {\r
157       pbuf_pool = p->next;\r
158     }\r
159 #if !SYS_LIGHTWEIGHT_PROT\r
160 #if PBUF_STATS\r
161   } else {\r
162     ++lwip_stats.pbuf.alloc_locked;\r
163 #endif /* PBUF_STATS */\r
164   }\r
165   pbuf_pool_alloc_lock = 0;\r
166 #endif /* SYS_LIGHTWEIGHT_PROT */\r
167 \r
168 #if PBUF_STATS\r
169   if (p != NULL) {\r
170     ++lwip_stats.pbuf.used;\r
171     if (lwip_stats.pbuf.used > lwip_stats.pbuf.max) {\r
172       lwip_stats.pbuf.max = lwip_stats.pbuf.used;\r
173     }\r
174   }\r
175 #endif /* PBUF_STATS */\r
176 \r
177   SYS_ARCH_UNPROTECT(old_level);\r
178   return p;\r
179 }\r
180 \r
181 \r
182 /**\r
183  * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).\r
184  *\r
185  * The actual memory allocated for the pbuf is determined by the\r
186  * layer at which the pbuf is allocated and the requested size\r
187  * (from the size parameter).\r
188  *\r
189  * @param flag this parameter decides how and where the pbuf\r
190  * should be allocated as follows:\r
191  *\r
192  * - PBUF_RAM: buffer memory for pbuf is allocated as one large\r
193  *             chunk. This includes protocol headers as well.\r
194  * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for\r
195  *             protocol headers. Additional headers must be prepended\r
196  *             by allocating another pbuf and chain in to the front of\r
197  *             the ROM pbuf. It is assumed that the memory used is really\r
198  *             similar to ROM in that it is immutable and will not be\r
199  *             changed. Memory which is dynamic should generally not\r
200  *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.\r
201  * - PBUF_REF: no buffer memory is allocated for the pbuf, even for\r
202  *             protocol headers. It is assumed that the pbuf is only\r
203  *             being used in a single thread. If the pbuf gets queued,\r
204  *             then pbuf_take should be called to copy the buffer.\r
205  * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from\r
206  *              the pbuf pool that is allocated during pbuf_init().\r
207  *\r
208  * @return the allocated pbuf. If multiple pbufs where allocated, this\r
209  * is the first pbuf of a pbuf chain.\r
210  */\r
211 struct pbuf *\r
212 pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag)\r
213 {\r
214   struct pbuf *p, *q, *r;\r
215   u16_t offset;\r
216   s32_t rem_len; /* remaining length */\r
217   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));\r
218 \r
219   /* determine header offset */\r
220   offset = 0;\r
221   switch (l) {\r
222   case PBUF_TRANSPORT:\r
223     /* add room for transport (often TCP) layer header */\r
224     offset += PBUF_TRANSPORT_HLEN;\r
225     /* FALLTHROUGH */\r
226   case PBUF_IP:\r
227     /* add room for IP layer header */\r
228     offset += PBUF_IP_HLEN;\r
229     /* FALLTHROUGH */\r
230   case PBUF_LINK:\r
231     /* add room for link layer header */\r
232     offset += PBUF_LINK_HLEN;\r
233     break;\r
234   case PBUF_RAW:\r
235     break;\r
236   default:\r
237     LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);\r
238     return NULL;\r
239   }\r
240 \r
241   switch (flag) {\r
242   case PBUF_POOL:\r
243     /* allocate head of pbuf chain into p */\r
244     p = pbuf_pool_alloc();\r
245     LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));\r
246     if (p == NULL) {\r
247 #if PBUF_STATS\r
248       ++lwip_stats.pbuf.err;\r
249 #endif /* PBUF_STATS */\r
250       return NULL;\r
251     }\r
252     p->next = NULL;\r
253 \r
254     /* make the payload pointer point 'offset' bytes into pbuf data memory */\r
255     p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));\r
256     LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",\r
257             ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
258     /* the total length of the pbuf chain is the requested size */\r
259     p->tot_len = length;\r
260     /* set the length of the first pbuf in the chain */\r
261     p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;\r
262     /* set reference count (needed here in case we fail) */\r
263     p->ref = 1;\r
264 \r
265     /* now allocate the tail of the pbuf chain */\r
266 \r
267     /* remember first pbuf for linkage in next iteration */\r
268     r = p;\r
269     /* remaining length to be allocated */\r
270     rem_len = length - p->len;\r
271     /* any remaining pbufs to be allocated? */\r
272     while (rem_len > 0) {\r
273       q = pbuf_pool_alloc();\r
274       if (q == NULL) {\r
275        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));\r
276 #if PBUF_STATS\r
277         ++lwip_stats.pbuf.err;\r
278 #endif /* PBUF_STATS */\r
279         /* free chain so far allocated */\r
280         pbuf_free(p);\r
281         /* bail out unsuccesfully */\r
282         return NULL;\r
283       }\r
284       q->next = NULL;\r
285       /* make previous pbuf point to this pbuf */\r
286       r->next = q;\r
287       /* set total length of this pbuf and next in chain */\r
288       q->tot_len = rem_len;\r
289       /* this pbuf length is pool size, unless smaller sized tail */\r
290       q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;\r
291       q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));\r
292       LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",\r
293               ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);\r
294       q->ref = 1;\r
295       /* calculate remaining length to be allocated */\r
296       rem_len -= q->len;\r
297       /* remember this pbuf for linkage in next iteration */\r
298       r = q;\r
299     }\r
300     /* end of chain */\r
301     /*r->next = NULL;*/\r
302 \r
303     break;\r
304   case PBUF_RAM:\r
305     /* If pbuf is to be allocated in RAM, allocate memory for it. */\r
306     p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + offset) + MEM_ALIGN_SIZE(length));\r
307     if (p == NULL) {\r
308       return NULL;\r
309     }\r
310     /* Set up internal structure of the pbuf. */\r
311     p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));\r
312     p->len = p->tot_len = length;\r
313     p->next = NULL;\r
314     p->flags = PBUF_FLAG_RAM;\r
315 \r
316     LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",\r
317            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
318     break;\r
319   /* pbuf references existing (non-volatile static constant) ROM payload? */\r
320   case PBUF_ROM:\r
321   /* pbuf references existing (externally allocated) RAM payload? */\r
322   case PBUF_REF:\r
323     /* only allocate memory for the pbuf structure */\r
324     p = memp_malloc(MEMP_PBUF);\r
325     if (p == NULL) {\r
326       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF"));\r
327       return NULL;\r
328     }\r
329     /* caller must set this field properly, afterwards */\r
330     p->payload = NULL;\r
331     p->len = p->tot_len = length;\r
332     p->next = NULL;\r
333     p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);\r
334     break;\r
335   default:\r
336     LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);\r
337     return NULL;\r
338   }\r
339   /* set reference count */\r
340   p->ref = 1;\r
341   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));\r
342   return p;\r
343 }\r
344 \r
345 \r
346 #if PBUF_STATS\r
347 #define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)\r
348 #else /* PBUF_STATS */\r
349 #define DEC_PBUF_STATS\r
350 #endif /* PBUF_STATS */\r
351 \r
352 #define PBUF_POOL_FAST_FREE(p)  do {                                    \\r
353                                   p->next = pbuf_pool;                  \\r
354                                   pbuf_pool = p;                        \\r
355                                   DEC_PBUF_STATS;                       \\r
356                                 } while (0)\r
357 \r
358 #if SYS_LIGHTWEIGHT_PROT\r
359 #define PBUF_POOL_FREE(p)  do {                                         \\r
360                                 SYS_ARCH_DECL_PROTECT(old_level);       \\r
361                                 SYS_ARCH_PROTECT(old_level);            \\r
362                                 PBUF_POOL_FAST_FREE(p);                 \\r
363                                 SYS_ARCH_UNPROTECT(old_level);          \\r
364                                } while (0)\r
365 #else /* SYS_LIGHTWEIGHT_PROT */\r
366 #define PBUF_POOL_FREE(p)  do {                                         \\r
367                              sys_sem_wait(pbuf_pool_free_sem);          \\r
368                              PBUF_POOL_FAST_FREE(p);                    \\r
369                              sys_sem_signal(pbuf_pool_free_sem);        \\r
370                            } while (0)\r
371 #endif /* SYS_LIGHTWEIGHT_PROT */\r
372 \r
373 /**\r
374  * Shrink a pbuf chain to a desired length.\r
375  *\r
376  * @param p pbuf to shrink.\r
377  * @param new_len desired new length of pbuf chain\r
378  *\r
379  * Depending on the desired length, the first few pbufs in a chain might\r
380  * be skipped and left unchanged. The new last pbuf in the chain will be\r
381  * resized, and any remaining pbufs will be freed.\r
382  *\r
383  * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.\r
384  * @note May not be called on a packet queue.\r
385  *\r
386  * @bug Cannot grow the size of a pbuf (chain) (yet).\r
387  */\r
388 void\r
389 pbuf_realloc(struct pbuf *p, u16_t new_len)\r
390 {\r
391   struct pbuf *q;\r
392   u16_t rem_len; /* remaining length */\r
393   s16_t grow;\r
394 \r
395   LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||\r
396               p->flags == PBUF_FLAG_ROM ||\r
397               p->flags == PBUF_FLAG_RAM ||\r
398               p->flags == PBUF_FLAG_REF);\r
399 \r
400   /* desired length larger than current length? */\r
401   if (new_len >= p->tot_len) {\r
402     /* enlarging not yet supported */\r
403     return;\r
404   }\r
405 \r
406   /* the pbuf chain grows by (new_len - p->tot_len) bytes\r
407    * (which may be negative in case of shrinking) */\r
408   grow = new_len - p->tot_len;\r
409 \r
410   /* first, step over any pbufs that should remain in the chain */\r
411   rem_len = new_len;\r
412   q = p;\r
413   /* should this pbuf be kept? */\r
414   while (rem_len > q->len) {\r
415     /* decrease remaining length by pbuf length */\r
416     rem_len -= q->len;\r
417     /* decrease total length indicator */\r
418     q->tot_len += grow;\r
419     /* proceed to next pbuf in chain */\r
420     q = q->next;\r
421   }\r
422   /* we have now reached the new last pbuf (in q) */\r
423   /* rem_len == desired length for pbuf q */\r
424 \r
425   /* shrink allocated memory for PBUF_RAM */\r
426   /* (other types merely adjust their length fields */\r
427   if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {\r
428     /* reallocate and adjust the length of the pbuf that will be split */\r
429     mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);\r
430   }\r
431   /* adjust length fields for new last pbuf */\r
432   q->len = rem_len;\r
433   q->tot_len = q->len;\r
434 \r
435   /* any remaining pbufs in chain? */\r
436   if (q->next != NULL) {\r
437     /* free remaining pbufs in chain */\r
438     pbuf_free(q->next);\r
439   }\r
440   /* q is last packet in chain */\r
441   q->next = NULL;\r
442 \r
443 }\r
444 \r
445 /**\r
446  * Adjusts the payload pointer to hide or reveal headers in the payload.\r
447  *\r
448  * Adjusts the ->payload pointer so that space for a header\r
449  * (dis)appears in the pbuf payload.\r
450  *\r
451  * The ->payload, ->tot_len and ->len fields are adjusted.\r
452  *\r
453  * @param hdr_size_inc Number of bytes to increment header size which\r
454  * increases the size of the pbuf. New space is on the front.\r
455  * (Using a negative value decreases the header size.)\r
456  * If hdr_size_inc is 0, this function does nothing and returns succesful.\r
457  *\r
458  * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so\r
459  * the call will fail. A check is made that the increase in header size does\r
460  * not move the payload pointer in front of the start of the buffer.\r
461  * @return non-zero on failure, zero on success.\r
462  *\r
463  */\r
464 u8_t\r
465 pbuf_header(struct pbuf *p, s16_t header_size_increment)\r
466 {\r
467   void *payload;\r
468 \r
469   LWIP_ASSERT("p != NULL", p != NULL);\r
470   if ((header_size_increment == 0) || (p == NULL)) return 0;\r
471  \r
472   /* remember current payload pointer */\r
473   payload = p->payload;\r
474 \r
475   /* pbuf types containing payloads? */\r
476   if (p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_POOL) {\r
477     /* set new payload pointer */\r
478     p->payload = (u8_t *)p->payload - header_size_increment;\r
479     /* boundary check fails? */\r
480     if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {\r
481       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",\r
482         (void *)p->payload,\r
483         (void *)(p + 1)));\\r
484       /* restore old payload pointer */\r
485       p->payload = payload;\r
486       /* bail out unsuccesfully */\r
487       return 1;\r
488     }\r
489   /* pbuf types refering to external payloads? */\r
490   } else if (p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_ROM) {\r
491     /* hide a header in the payload? */\r
492     if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {\r
493       /* increase payload pointer */\r
494       p->payload = (u8_t *)p->payload - header_size_increment;\r
495     } else {\r
496       /* cannot expand payload to front (yet!)\r
497        * bail out unsuccesfully */\r
498       return 1;\r
499     }\r
500   }\r
501   /* modify pbuf length fields */\r
502   p->len += header_size_increment;\r
503   p->tot_len += header_size_increment;\r
504 \r
505   LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",\r
506     (void *)payload, (void *)p->payload, header_size_increment));\r
507 \r
508   return 0;\r
509 }\r
510 \r
511 /**\r
512  * Dereference a pbuf chain or queue and deallocate any no-longer-used\r
513  * pbufs at the head of this chain or queue.\r
514  *\r
515  * Decrements the pbuf reference count. If it reaches zero, the pbuf is\r
516  * deallocated.\r
517  *\r
518  * For a pbuf chain, this is repeated for each pbuf in the chain,\r
519  * up to the first pbuf which has a non-zero reference count after\r
520  * decrementing. So, when all reference counts are one, the whole\r
521  * chain is free'd.\r
522  *\r
523  * @param pbuf The pbuf (chain) to be dereferenced.\r
524  *\r
525  * @return the number of pbufs that were de-allocated\r
526  * from the head of the chain.\r
527  *\r
528  * @note MUST NOT be called on a packet queue (Not verified to work yet).\r
529  * @note the reference counter of a pbuf equals the number of pointers\r
530  * that refer to the pbuf (or into the pbuf).\r
531  *\r
532  * @internal examples:\r
533  *\r
534  * Assuming existing chains a->b->c with the following reference\r
535  * counts, calling pbuf_free(a) results in:\r
536  * \r
537  * 1->2->3 becomes ...1->3\r
538  * 3->3->3 becomes 2->3->3\r
539  * 1->1->2 becomes ......1\r
540  * 2->1->1 becomes 1->1->1\r
541  * 1->1->1 becomes .......\r
542  *\r
543  */\r
544 u8_t\r
545 pbuf_free(struct pbuf *p)\r
546 {\r
547   struct pbuf *q;\r
548   u8_t count;\r
549   SYS_ARCH_DECL_PROTECT(old_level);\r
550 \r
551   LWIP_ASSERT("p != NULL", p != NULL);\r
552   /* if assertions are disabled, proceed with debug output */\r
553   if (p == NULL) {\r
554     LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));\r
555     return 0;\r
556   }\r
557   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));\r
558 \r
559   PERF_START;\r
560 \r
561   LWIP_ASSERT("pbuf_free: sane flags",\r
562     p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||\r
563     p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);\r
564 \r
565   count = 0;\r
566   /* Since decrementing ref cannot be guaranteed to be a single machine operation\r
567    * we must protect it. Also, the later test of ref must be protected.\r
568    */\r
569   SYS_ARCH_PROTECT(old_level);\r
570   /* de-allocate all consecutive pbufs from the head of the chain that\r
571    * obtain a zero reference count after decrementing*/\r
572   while (p != NULL) {\r
573     /* all pbufs in a chain are referenced at least once */\r
574     LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);\r
575     /* decrease reference count (number of pointers to pbuf) */\r
576     p->ref--;\r
577     /* this pbuf is no longer referenced to? */\r
578     if (p->ref == 0) {\r
579       /* remember next pbuf in chain for next iteration */\r
580       q = p->next;\r
581       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));\r
582       /* is this a pbuf from the pool? */\r
583       if (p->flags == PBUF_FLAG_POOL) {\r
584         p->len = p->tot_len = PBUF_POOL_BUFSIZE;\r
585         p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));\r
586         PBUF_POOL_FREE(p);\r
587       /* is this a ROM or RAM referencing pbuf? */\r
588       } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {\r
589         memp_free(MEMP_PBUF, p);\r
590       /* p->flags == PBUF_FLAG_RAM */\r
591       } else {\r
592         mem_free(p);\r
593       }\r
594       count++;\r
595       /* proceed to next pbuf */\r
596       p = q;\r
597     /* p->ref > 0, this pbuf is still referenced to */\r
598     /* (and so the remaining pbufs in chain as well) */\r
599     } else {\r
600       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref));\r
601       /* stop walking through the chain */\r
602       p = NULL;\r
603     }\r
604   }\r
605   SYS_ARCH_UNPROTECT(old_level);\r
606   PERF_STOP("pbuf_free");\r
607   /* return number of de-allocated pbufs */\r
608   return count;\r
609 }\r
610 \r
611 /**\r
612  * Count number of pbufs in a chain\r
613  *\r
614  * @param p first pbuf of chain\r
615  * @return the number of pbufs in a chain\r
616  */\r
617 \r
618 u8_t\r
619 pbuf_clen(struct pbuf *p)\r
620 {\r
621   u8_t len;\r
622 \r
623   len = 0;\r
624   while (p != NULL) {\r
625     ++len;\r
626     p = p->next;\r
627   }\r
628   return len;\r
629 }\r
630 \r
631 /**\r
632  * Increment the reference count of the pbuf.\r
633  *\r
634  * @param p pbuf to increase reference counter of\r
635  *\r
636  */\r
637 void\r
638 pbuf_ref(struct pbuf *p)\r
639 {\r
640   SYS_ARCH_DECL_PROTECT(old_level);\r
641   /* pbuf given? */\r
642   if (p != NULL) {\r
643     SYS_ARCH_PROTECT(old_level);\r
644     ++(p->ref);\r
645     SYS_ARCH_UNPROTECT(old_level);\r
646   }\r
647 }\r
648 \r
649 /**\r
650  * Concatenate two pbufs (each may be a pbuf chain) and take over\r
651  * the caller's reference of the tail pbuf.\r
652  * \r
653  * @note The caller MAY NOT reference the tail pbuf afterwards.\r
654  * Use pbuf_chain() for that purpose.\r
655  * \r
656  * @see pbuf_chain()\r
657  */\r
658 \r
659 void\r
660 pbuf_cat(struct pbuf *h, struct pbuf *t)\r
661 {\r
662   struct pbuf *p;\r
663 \r
664   LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);\r
665   LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);\r
666   if ((h == NULL) || (t == NULL)) return;\r
667 \r
668   /* proceed to last pbuf of chain */\r
669   for (p = h; p->next != NULL; p = p->next) {\r
670     /* add total length of second chain to all totals of first chain */\r
671     p->tot_len += t->tot_len;\r
672   }\r
673   /* { p is last pbuf of first h chain, p->next == NULL } */\r
674   LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);\r
675   LWIP_ASSERT("p->next == NULL", p->next == NULL);\r
676   /* add total length of second chain to last pbuf total of first chain */\r
677   p->tot_len += t->tot_len;\r
678   /* chain last pbuf of head (p) with first of tail (t) */\r
679   p->next = t;\r
680   /* p->next now references t, but the caller will drop its reference to t,\r
681    * so netto there is no change to the reference count of t.\r
682    */\r
683 }\r
684 \r
685 /**\r
686  * Chain two pbufs (or pbuf chains) together.\r
687  * \r
688  * The caller MUST call pbuf_free(t) once it has stopped\r
689  * using it. Use pbuf_cat() instead if you no longer use t.\r
690  * \r
691  * @param h head pbuf (chain)\r
692  * @param t tail pbuf (chain)\r
693  * @note The pbufs MUST belong to the same packet.\r
694  * @note MAY NOT be called on a packet queue.\r
695  *\r
696  * The ->tot_len fields of all pbufs of the head chain are adjusted.\r
697  * The ->next field of the last pbuf of the head chain is adjusted.\r
698  * The ->ref field of the first pbuf of the tail chain is adjusted.\r
699  *\r
700  */\r
701 void\r
702 pbuf_chain(struct pbuf *h, struct pbuf *t)\r
703 {\r
704   pbuf_cat(h, t);\r
705   /* t is now referenced by h */\r
706   pbuf_ref(t);\r
707   LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));\r
708 }\r
709 \r
710 /* For packet queueing. Note that queued packets MUST be dequeued first\r
711  * using pbuf_dequeue() before calling other pbuf_() functions. */\r
712 #if ARP_QUEUEING\r
713 /**\r
714  * Add a packet to the end of a queue.\r
715  *\r
716  * @param q pointer to first packet on the queue\r
717  * @param n packet to be queued\r
718  *\r
719  * Both packets MUST be given, and must be different.\r
720  */\r
721 void\r
722 pbuf_queue(struct pbuf *p, struct pbuf *n)\r
723 {\r
724 #if PBUF_DEBUG /* remember head of queue */\r
725   struct pbuf *q = p;\r
726 #endif\r
727   /* programmer stupidity checks */\r
728   LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);\r
729   LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);\r
730   LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);\r
731   if ((p == NULL) || (n == NULL) || (p == n)){\r
732     LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));\r
733     return;\r
734   }\r
735 \r
736   /* iterate through all packets on queue */\r
737   while (p->next != NULL) {\r
738 /* be very picky about pbuf chain correctness */\r
739 #if PBUF_DEBUG\r
740     /* iterate through all pbufs in packet */\r
741     while (p->tot_len != p->len) {\r
742       /* make sure invariant condition holds */\r
743       LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
744       /* make sure each packet is complete */\r
745       LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
746       p = p->next;\r
747       /* { p->tot_len == p->len => p is last pbuf of a packet } */\r
748     }\r
749     /* { p is last pbuf of a packet } */\r
750     /* proceed to next packet on queue */\r
751 #endif\r
752     /* proceed to next pbuf */\r
753     if (p->next != NULL) p = p->next;\r
754   }\r
755   /* { p->tot_len == p->len and p->next == NULL } ==>\r
756    * { p is last pbuf of last packet on queue } */\r
757   /* chain last pbuf of queue with n */\r
758   p->next = n;\r
759   /* n is now referenced to by the (packet p in the) queue */\r
760   pbuf_ref(n);\r
761 #if PBUF_DEBUG\r
762   LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,\r
763     ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",\r
764     (void *)n, (void *)p, (void *)q));\r
765 #endif\r
766 }\r
767 \r
768 /**\r
769  * Remove a packet from the head of a queue.\r
770  *\r
771  * The caller MUST reference the remainder of the queue (as returned). The\r
772  * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference\r
773  * from p.\r
774  * \r
775  * @param p pointer to first packet on the queue which will be dequeued.\r
776  * @return first packet on the remaining queue (NULL if no further packets).\r
777  *\r
778  */\r
779 struct pbuf *\r
780 pbuf_dequeue(struct pbuf *p)\r
781 {\r
782   struct pbuf *q;\r
783   LWIP_ASSERT("p != NULL", p != NULL);\r
784 \r
785   /* iterate through all pbufs in packet p */\r
786   while (p->tot_len != p->len) {\r
787     /* make sure invariant condition holds */\r
788     LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
789     /* make sure each packet is complete */\r
790     LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
791     p = p->next;\r
792   }\r
793   /* { p->tot_len == p->len } => p is the last pbuf of the first packet */\r
794   /* remember next packet on queue in q */\r
795   q = p->next;\r
796   /* dequeue packet p from queue */\r
797   p->next = NULL;\r
798   /* any next packet on queue? */\r
799   if (q != NULL) {\r
800     /* although q is no longer referenced by p, it MUST be referenced by\r
801      * the caller, who is maintaining this packet queue. So, we do not call\r
802      * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */\r
803     LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));\r
804   } else {\r
805     LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));\r
806   }\r
807   return q;\r
808 }\r
809 #endif\r
810 \r
811 /**\r
812  *\r
813  * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.\r
814  *\r
815  * Used to queue packets on behalf of the lwIP stack, such as\r
816  * ARP based queueing.\r
817  *\r
818  * Go through a pbuf chain and replace any PBUF_REF buffers\r
819  * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of\r
820  * the referenced data.\r
821  *\r
822  * @note You MUST explicitly use p = pbuf_take(p);\r
823  * The pbuf you give as argument, may have been replaced\r
824  * by a (differently located) copy through pbuf_take()!\r
825  *\r
826  * @note Any replaced pbufs will be freed through pbuf_free().\r
827  * This may deallocate them if they become no longer referenced.\r
828  *\r
829  * @param p Head of pbuf chain to process\r
830  *\r
831  * @return Pointer to head of pbuf chain\r
832  */\r
833 struct pbuf *\r
834 pbuf_take(struct pbuf *p)\r
835 {\r
836   struct pbuf *q , *prev, *head;\r
837   LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);\r
838   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));\r
839 \r
840   prev = NULL;\r
841   head = p;\r
842   /* iterate through pbuf chain */\r
843   do\r
844   {\r
845     /* pbuf is of type PBUF_REF? */\r
846     if (p->flags == PBUF_FLAG_REF) {\r
847       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));\r
848       /* allocate a pbuf (w/ payload) fully in RAM */\r
849       /* PBUF_POOL buffers are faster if we can use them */\r
850       if (p->len <= PBUF_POOL_BUFSIZE) {\r
851         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);\r
852         if (q == NULL) {\r
853           LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));\r
854         }\r
855       } else {\r
856         /* no replacement pbuf yet */\r
857         q = NULL;\r
858         LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));\r
859       }\r
860       /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */\r
861       if (q == NULL) {\r
862         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);\r
863         if (q == NULL) {\r
864           LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));\r
865         }\r
866       }\r
867       /* replacement pbuf could be allocated? */\r
868       if (q != NULL)\r
869       {\r
870         /* copy p to q */\r
871         /* copy successor */\r
872         q->next = p->next;\r
873         /* remove linkage from original pbuf */\r
874         p->next = NULL;\r
875         /* remove linkage to original pbuf */\r
876         if (prev != NULL) {\r
877           /* prev->next == p at this point */\r
878           LWIP_ASSERT("prev->next == p", prev->next == p);\r
879           /* break chain and insert new pbuf instead */\r
880           prev->next = q;\r
881         /* prev == NULL, so we replaced the head pbuf of the chain */\r
882         } else {\r
883           head = q;\r
884         }\r
885         /* copy pbuf payload */\r
886         memcpy(q->payload, p->payload, p->len);\r
887         q->tot_len = p->tot_len;\r
888         q->len = p->len;\r
889         /* in case p was the first pbuf, it is no longer refered to by\r
890          * our caller, as the caller MUST do p = pbuf_take(p);\r
891          * in case p was not the first pbuf, it is no longer refered to\r
892          * by prev. we can safely free the pbuf here.\r
893          * (note that we have set p->next to NULL already so that\r
894          * we will not free the rest of the chain by accident.)\r
895          */\r
896         pbuf_free(p);\r
897         /* do not copy ref, since someone else might be using the old buffer */\r
898         LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));\r
899         p = q;\r
900       } else {\r
901         /* deallocate chain */\r
902         pbuf_free(head);\r
903         LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));\r
904         return NULL;\r
905       }\r
906     /* p->flags != PBUF_FLAG_REF */\r
907     } else {\r
908       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));\r
909     }\r
910     /* remember this pbuf */\r
911     prev = p;\r
912     /* proceed to next pbuf in original chain */\r
913     p = p->next;\r
914   } while (p);\r
915   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));\r
916 \r
917   return head;\r
918 }\r
919 \r
920 /**\r
921  * Dechains the first pbuf from its succeeding pbufs in the chain.\r
922  *\r
923  * Makes p->tot_len field equal to p->len.\r
924  * @param p pbuf to dechain\r
925  * @return remainder of the pbuf chain, or NULL if it was de-allocated.\r
926  * @note May not be called on a packet queue.\r
927  */\r
928 struct pbuf *\r
929 pbuf_dechain(struct pbuf *p)\r
930 {\r
931   struct pbuf *q;\r
932   u8_t tail_gone = 1;\r
933   /* tail */\r
934   q = p->next;\r
935   /* pbuf has successor in chain? */\r
936   if (q != NULL) {\r
937     /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
938     LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);\r
939     /* enforce invariant if assertion is disabled */\r
940     q->tot_len = p->tot_len - p->len;\r
941     /* decouple pbuf from remainder */\r
942     p->next = NULL;\r
943     /* total length of pbuf p is its own length only */\r
944     p->tot_len = p->len;\r
945     /* q is no longer referenced by p, free it */\r
946     LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));\r
947     tail_gone = pbuf_free(q);\r
948     if (tail_gone > 0) {\r
949       LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,\r
950                   ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));\r
951     }\r
952     /* return remaining tail or NULL if deallocated */\r
953   }\r
954   /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
955   LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);\r
956   return (tail_gone > 0? NULL: q);\r
957 }\r