]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/pbuf.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
[freertos] / Demo / Common / ethernet / lwIP / 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 \r
328       return NULL;\r
329     }\r
330     /* caller must set this field properly, afterwards */\r
331     p->payload = NULL;\r
332     p->len = p->tot_len = length;\r
333     p->next = NULL;\r
334     p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);\r
335     break;\r
336   default:\r
337     LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);\r
338     return NULL;\r
339   }\r
340   /* set reference count */\r
341   p->ref = 1;\r
342   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));\r
343   return p;\r
344 }\r
345 \r
346 \r
347 #if PBUF_STATS\r
348 #define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)\r
349 #else /* PBUF_STATS */\r
350 #define DEC_PBUF_STATS\r
351 #endif /* PBUF_STATS */\r
352 \r
353 #define PBUF_POOL_FAST_FREE(p)  do {                                    \\r
354                                   p->next = pbuf_pool;                  \\r
355                                   pbuf_pool = p;                        \\r
356                                   DEC_PBUF_STATS;                       \\r
357                                 } while (0)\r
358 \r
359 #if SYS_LIGHTWEIGHT_PROT\r
360 #define PBUF_POOL_FREE(p)  do {                                         \\r
361                                 SYS_ARCH_DECL_PROTECT(old_level);       \\r
362                                 SYS_ARCH_PROTECT(old_level);            \\r
363                                 PBUF_POOL_FAST_FREE(p);                 \\r
364                                 SYS_ARCH_UNPROTECT(old_level);          \\r
365                                } while (0)\r
366 #else /* SYS_LIGHTWEIGHT_PROT */\r
367 #define PBUF_POOL_FREE(p)  do {                                         \\r
368                              sys_sem_wait(pbuf_pool_free_sem);          \\r
369                              PBUF_POOL_FAST_FREE(p);                    \\r
370                              sys_sem_signal(pbuf_pool_free_sem);        \\r
371                            } while (0)\r
372 #endif /* SYS_LIGHTWEIGHT_PROT */\r
373 \r
374 /**\r
375  * Shrink a pbuf chain to a desired length.\r
376  *\r
377  * @param p pbuf to shrink.\r
378  * @param new_len desired new length of pbuf chain\r
379  *\r
380  * Depending on the desired length, the first few pbufs in a chain might\r
381  * be skipped and left unchanged. The new last pbuf in the chain will be\r
382  * resized, and any remaining pbufs will be freed.\r
383  *\r
384  * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.\r
385  * @note May not be called on a packet queue.\r
386  *\r
387  * @bug Cannot grow the size of a pbuf (chain) (yet).\r
388  */\r
389 void\r
390 pbuf_realloc(struct pbuf *p, u16_t new_len)\r
391 {\r
392   struct pbuf *q;\r
393   u16_t rem_len; /* remaining length */\r
394   s16_t grow;\r
395 \r
396   LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||\r
397               p->flags == PBUF_FLAG_ROM ||\r
398               p->flags == PBUF_FLAG_RAM ||\r
399               p->flags == PBUF_FLAG_REF);\r
400 \r
401   /* desired length larger than current length? */\r
402   if (new_len >= p->tot_len) {\r
403     /* enlarging not yet supported */\r
404     return;\r
405   }\r
406 \r
407   /* the pbuf chain grows by (new_len - p->tot_len) bytes\r
408    * (which may be negative in case of shrinking) */\r
409   grow = new_len - p->tot_len;\r
410 \r
411   /* first, step over any pbufs that should remain in the chain */\r
412   rem_len = new_len;\r
413   q = p;\r
414   /* should this pbuf be kept? */\r
415   while (rem_len > q->len) {\r
416     /* decrease remaining length by pbuf length */\r
417     rem_len -= q->len;\r
418     /* decrease total length indicator */\r
419     q->tot_len += grow;\r
420     /* proceed to next pbuf in chain */\r
421     q = q->next;\r
422   }\r
423   /* we have now reached the new last pbuf (in q) */\r
424   /* rem_len == desired length for pbuf q */\r
425 \r
426   /* shrink allocated memory for PBUF_RAM */\r
427   /* (other types merely adjust their length fields */\r
428   if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {\r
429     /* reallocate and adjust the length of the pbuf that will be split */\r
430     mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);\r
431   }\r
432   /* adjust length fields for new last pbuf */\r
433   q->len = rem_len;\r
434   q->tot_len = q->len;\r
435 \r
436   /* any remaining pbufs in chain? */\r
437   if (q->next != NULL) {\r
438     /* free remaining pbufs in chain */\r
439     pbuf_free(q->next);\r
440   }\r
441   /* q is last packet in chain */\r
442   q->next = NULL;\r
443 \r
444 }\r
445 \r
446 /**\r
447  * Adjusts the payload pointer to hide or reveal headers in the payload.\r
448  *\r
449  * Adjusts the ->payload pointer so that space for a header\r
450  * (dis)appears in the pbuf payload.\r
451  *\r
452  * The ->payload, ->tot_len and ->len fields are adjusted.\r
453  *\r
454  * @param hdr_size_inc Number of bytes to increment header size which\r
455  * increases the size of the pbuf. New space is on the front.\r
456  * (Using a negative value decreases the header size.)\r
457  * If hdr_size_inc is 0, this function does nothing and returns succesful.\r
458  *\r
459  * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so\r
460  * the call will fail. A check is made that the increase in header size does\r
461  * not move the payload pointer in front of the start of the buffer.\r
462  * @return non-zero on failure, zero on success.\r
463  *\r
464  */\r
465 u8_t\r
466 pbuf_header(struct pbuf *p, s16_t header_size_increment)\r
467 {\r
468   u16_t flags;\r
469   void *payload;\r
470 \r
471   LWIP_ASSERT("p != NULL", p != NULL);\r
472   if ((header_size_increment == 0) || (p == NULL)) return 0;\r
473  \r
474   flags = p->flags;\r
475   /* remember current payload pointer */\r
476   payload = p->payload;\r
477 \r
478   /* pbuf types containing payloads? */\r
479   if (flags == PBUF_FLAG_RAM || flags == PBUF_FLAG_POOL) {\r
480     /* set new payload pointer */\r
481     p->payload = (u8_t *)p->payload - header_size_increment;\r
482     /* boundary check fails? */\r
483     if ((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {\r
484       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",\r
485         (void *)p->payload,\r
486         (void *)(p + 1)));\\r
487       /* restore old payload pointer */\r
488       p->payload = payload;\r
489       /* bail out unsuccesfully */\r
490       return 1;\r
491     }\r
492   /* pbuf types refering to external payloads? */\r
493   } else if (flags == PBUF_FLAG_REF || flags == PBUF_FLAG_ROM) {\r
494     /* hide a header in the payload? */\r
495     if ((header_size_increment < 0) && (header_size_increment - p->len <= 0)) {\r
496       /* increase payload pointer */\r
497       p->payload = (u8_t *)p->payload - header_size_increment;\r
498     } else {\r
499       /* cannot expand payload to front (yet!)\r
500        * bail out unsuccesfully */\r
501       return 1;\r
502     }\r
503   }\r
504   /* modify pbuf length fields */\r
505   p->len += header_size_increment;\r
506   p->tot_len += header_size_increment;\r
507 \r
508   LWIP_DEBUGF( PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",\r
509     (void *)payload, (void *)p->payload, header_size_increment));\r
510 \r
511   return 0;\r
512 }\r
513 \r
514 /**\r
515  * Dereference a pbuf chain or queue and deallocate any no-longer-used\r
516  * pbufs at the head of this chain or queue.\r
517  *\r
518  * Decrements the pbuf reference count. If it reaches zero, the pbuf is\r
519  * deallocated.\r
520  *\r
521  * For a pbuf chain, this is repeated for each pbuf in the chain,\r
522  * up to the first pbuf which has a non-zero reference count after\r
523  * decrementing. So, when all reference counts are one, the whole\r
524  * chain is free'd.\r
525  *\r
526  * @param pbuf The pbuf (chain) to be dereferenced.\r
527  *\r
528  * @return the number of pbufs that were de-allocated\r
529  * from the head of the chain.\r
530  *\r
531  * @note MUST NOT be called on a packet queue (Not verified to work yet).\r
532  * @note the reference counter of a pbuf equals the number of pointers\r
533  * that refer to the pbuf (or into the pbuf).\r
534  *\r
535  * @internal examples:\r
536  *\r
537  * Assuming existing chains a->b->c with the following reference\r
538  * counts, calling pbuf_free(a) results in:\r
539  * \r
540  * 1->2->3 becomes ...1->3\r
541  * 3->3->3 becomes 2->3->3\r
542  * 1->1->2 becomes ......1\r
543  * 2->1->1 becomes 1->1->1\r
544  * 1->1->1 becomes .......\r
545  *\r
546  */\r
547 u8_t\r
548 pbuf_free(struct pbuf *p)\r
549 {\r
550   u16_t flags;\r
551   struct pbuf *q;\r
552   u8_t count;\r
553   SYS_ARCH_DECL_PROTECT(old_level);\r
554 \r
555   LWIP_ASSERT("p != NULL", p != NULL);\r
556 \r
557   /* if assertions are disabled, proceed with debug output */\r
558   if (p == NULL) {\r
559     LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));\r
560     return 0;\r
561   }\r
562   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));\r
563 \r
564   PERF_START;\r
565 \r
566   LWIP_ASSERT("pbuf_free: sane flags",\r
567     p->flags == PBUF_FLAG_RAM || p->flags == PBUF_FLAG_ROM ||\r
568     p->flags == PBUF_FLAG_REF || p->flags == PBUF_FLAG_POOL);\r
569 \r
570   count = 0;\r
571   /* Since decrementing ref cannot be guaranteed to be a single machine operation\r
572    * we must protect it. Also, the later test of ref must be protected.\r
573    */\r
574   SYS_ARCH_PROTECT(old_level);\r
575   /* de-allocate all consecutive pbufs from the head of the chain that\r
576    * obtain a zero reference count after decrementing*/\r
577   while (p != NULL) {\r
578     /* all pbufs in a chain are referenced at least once */\r
579     LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);\r
580     /* decrease reference count (number of pointers to pbuf) */\r
581     p->ref--;\r
582     /* this pbuf is no longer referenced to? */\r
583     if (p->ref == 0) {\r
584       /* remember next pbuf in chain for next iteration */\r
585       q = p->next;\r
586       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));\r
587       flags = p->flags;\r
588       /* is this a pbuf from the pool? */\r
589       if (flags == PBUF_FLAG_POOL) {\r
590         p->len = p->tot_len = PBUF_POOL_BUFSIZE;\r
591         p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));\r
592         PBUF_POOL_FREE(p);\r
593       /* is this a ROM or RAM referencing pbuf? */\r
594       } else if (flags == PBUF_FLAG_ROM || flags == PBUF_FLAG_REF) {\r
595         memp_free(MEMP_PBUF, p);\r
596       /* flags == PBUF_FLAG_RAM */\r
597       } else {\r
598         mem_free(p);\r
599       }\r
600       count++;\r
601       /* proceed to next pbuf */\r
602       p = q;\r
603     /* p->ref > 0, this pbuf is still referenced to */\r
604     /* (and so the remaining pbufs in chain as well) */\r
605     } else {\r
606       LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)p->ref));\r
607       /* stop walking through the chain */\r
608       p = NULL;\r
609     }\r
610   }\r
611   SYS_ARCH_UNPROTECT(old_level);\r
612   PERF_STOP("pbuf_free");\r
613   /* return number of de-allocated pbufs */\r
614 \r
615   return count;\r
616 }\r
617 \r
618 /**\r
619  * Count number of pbufs in a chain\r
620  *\r
621  * @param p first pbuf of chain\r
622  * @return the number of pbufs in a chain\r
623  */\r
624 \r
625 u8_t\r
626 pbuf_clen(struct pbuf *p)\r
627 {\r
628   u8_t len;\r
629 \r
630   len = 0;\r
631   while (p != NULL) {\r
632     ++len;\r
633     p = p->next;\r
634   }\r
635   return len;\r
636 }\r
637 \r
638 /**\r
639  * Increment the reference count of the pbuf.\r
640  *\r
641  * @param p pbuf to increase reference counter of\r
642  *\r
643  */\r
644 void\r
645 pbuf_ref(struct pbuf *p)\r
646 {\r
647   SYS_ARCH_DECL_PROTECT(old_level);\r
648   /* pbuf given? */\r
649   if (p != NULL) {\r
650     SYS_ARCH_PROTECT(old_level);\r
651     ++(p->ref);\r
652     SYS_ARCH_UNPROTECT(old_level);\r
653   }\r
654 }\r
655 \r
656 /**\r
657  * Concatenate two pbufs (each may be a pbuf chain) and take over\r
658  * the caller's reference of the tail pbuf.\r
659  * \r
660  * @note The caller MAY NOT reference the tail pbuf afterwards.\r
661  * Use pbuf_chain() for that purpose.\r
662  * \r
663  * @see pbuf_chain()\r
664  */\r
665 \r
666 void\r
667 pbuf_cat(struct pbuf *h, struct pbuf *t)\r
668 {\r
669   struct pbuf *p;\r
670 \r
671   LWIP_ASSERT("h != NULL (programmer violates API)", h != NULL);\r
672   LWIP_ASSERT("t != NULL (programmer violates API)", t != NULL);\r
673   if ((h == NULL) || (t == NULL)) return;\r
674 \r
675   /* proceed to last pbuf of chain */\r
676   for (p = h; p->next != NULL; p = p->next) {\r
677     /* add total length of second chain to all totals of first chain */\r
678     p->tot_len += t->tot_len;\r
679   }\r
680   /* { p is last pbuf of first h chain, p->next == NULL } */\r
681   LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);\r
682   LWIP_ASSERT("p->next == NULL", p->next == NULL);\r
683   /* add total length of second chain to last pbuf total of first chain */\r
684   p->tot_len += t->tot_len;\r
685   /* chain last pbuf of head (p) with first of tail (t) */\r
686   p->next = t;\r
687   /* p->next now references t, but the caller will drop its reference to t,\r
688    * so netto there is no change to the reference count of t.\r
689    */\r
690 }\r
691 \r
692 /**\r
693  * Chain two pbufs (or pbuf chains) together.\r
694  * \r
695  * The caller MUST call pbuf_free(t) once it has stopped\r
696  * using it. Use pbuf_cat() instead if you no longer use t.\r
697  * \r
698  * @param h head pbuf (chain)\r
699  * @param t tail pbuf (chain)\r
700  * @note The pbufs MUST belong to the same packet.\r
701  * @note MAY NOT be called on a packet queue.\r
702  *\r
703  * The ->tot_len fields of all pbufs of the head chain are adjusted.\r
704  * The ->next field of the last pbuf of the head chain is adjusted.\r
705  * The ->ref field of the first pbuf of the tail chain is adjusted.\r
706  *\r
707  */\r
708 void\r
709 pbuf_chain(struct pbuf *h, struct pbuf *t)\r
710 {\r
711   pbuf_cat(h, t);\r
712   /* t is now referenced by h */\r
713   pbuf_ref(t);\r
714   LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));\r
715 }\r
716 \r
717 /* For packet queueing. Note that queued packets MUST be dequeued first\r
718  * using pbuf_dequeue() before calling other pbuf_() functions. */\r
719 #if ARP_QUEUEING\r
720 /**\r
721  * Add a packet to the end of a queue.\r
722  *\r
723  * @param q pointer to first packet on the queue\r
724  * @param n packet to be queued\r
725  *\r
726  * Both packets MUST be given, and must be different.\r
727  */\r
728 void\r
729 pbuf_queue(struct pbuf *p, struct pbuf *n)\r
730 {\r
731 #if PBUF_DEBUG /* remember head of queue */\r
732   struct pbuf *q = p;\r
733 #endif\r
734   /* programmer stupidity checks */\r
735   LWIP_ASSERT("p == NULL in pbuf_queue: this indicates a programmer error\n", p != NULL);\r
736   LWIP_ASSERT("n == NULL in pbuf_queue: this indicates a programmer error\n", n != NULL);\r
737   LWIP_ASSERT("p == n in pbuf_queue: this indicates a programmer error\n", p != n);\r
738   if ((p == NULL) || (n == NULL) || (p == n)){\r
739     LWIP_DEBUGF(PBUF_DEBUG | DBG_HALT | 3, ("pbuf_queue: programmer argument error\n"));\r
740     return;\r
741   }\r
742 \r
743   /* iterate through all packets on queue */\r
744   while (p->next != NULL) {\r
745 /* be very picky about pbuf chain correctness */\r
746 #if PBUF_DEBUG\r
747     /* iterate through all pbufs in packet */\r
748     while (p->tot_len != p->len) {\r
749       /* make sure invariant condition holds */\r
750       LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
751       /* make sure each packet is complete */\r
752       LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
753       p = p->next;\r
754       /* { p->tot_len == p->len => p is last pbuf of a packet } */\r
755     }\r
756     /* { p is last pbuf of a packet } */\r
757     /* proceed to next packet on queue */\r
758 #endif\r
759     /* proceed to next pbuf */\r
760     if (p->next != NULL) p = p->next;\r
761   }\r
762   /* { p->tot_len == p->len and p->next == NULL } ==>\r
763    * { p is last pbuf of last packet on queue } */\r
764   /* chain last pbuf of queue with n */\r
765   p->next = n;\r
766   /* n is now referenced to by the (packet p in the) queue */\r
767   pbuf_ref(n);\r
768 #if PBUF_DEBUG\r
769   LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2,\r
770     ("pbuf_queue: newly queued packet %p sits after packet %p in queue %p\n",\r
771     (void *)n, (void *)p, (void *)q));\r
772 #endif\r
773 }\r
774 \r
775 /**\r
776  * Remove a packet from the head of a queue.\r
777  *\r
778  * The caller MUST reference the remainder of the queue (as returned). The\r
779  * caller MUST NOT call pbuf_ref() as it implicitly takes over the reference\r
780  * from p.\r
781  * \r
782  * @param p pointer to first packet on the queue which will be dequeued.\r
783  * @return first packet on the remaining queue (NULL if no further packets).\r
784  *\r
785  */\r
786 struct pbuf *\r
787 pbuf_dequeue(struct pbuf *p)\r
788 {\r
789   struct pbuf *q;\r
790   LWIP_ASSERT("p != NULL", p != NULL);\r
791 \r
792   /* iterate through all pbufs in packet p */\r
793   while (p->tot_len != p->len) {\r
794     /* make sure invariant condition holds */\r
795     LWIP_ASSERT("p->len < p->tot_len", p->len < p->tot_len);\r
796     /* make sure each packet is complete */\r
797     LWIP_ASSERT("p->next != NULL", p->next != NULL);\r
798     p = p->next;\r
799   }\r
800   /* { p->tot_len == p->len } => p is the last pbuf of the first packet */\r
801   /* remember next packet on queue in q */\r
802   q = p->next;\r
803   /* dequeue packet p from queue */\r
804   p->next = NULL;\r
805   /* any next packet on queue? */\r
806   if (q != NULL) {\r
807     /* although q is no longer referenced by p, it MUST be referenced by\r
808      * the caller, who is maintaining this packet queue. So, we do not call\r
809      * pbuf_free(q) here, resulting in an implicit pbuf_ref(q) for the caller. */\r
810     LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: first remaining packet on queue is %p\n", (void *)q));\r
811   } else {\r
812     LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dequeue: no further packets on queue\n"));\r
813   }\r
814   return q;\r
815 }\r
816 #endif\r
817 \r
818 /**\r
819  *\r
820  * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.\r
821  *\r
822  * Used to queue packets on behalf of the lwIP stack, such as\r
823  * ARP based queueing.\r
824  *\r
825  * Go through a pbuf chain and replace any PBUF_REF buffers\r
826  * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of\r
827  * the referenced data.\r
828  *\r
829  * @note You MUST explicitly use p = pbuf_take(p);\r
830  * The pbuf you give as argument, may have been replaced\r
831  * by a (differently located) copy through pbuf_take()!\r
832  *\r
833  * @note Any replaced pbufs will be freed through pbuf_free().\r
834  * This may deallocate them if they become no longer referenced.\r
835  *\r
836  * @param p Head of pbuf chain to process\r
837  *\r
838  * @return Pointer to head of pbuf chain\r
839  */\r
840 struct pbuf *\r
841 pbuf_take(struct pbuf *p)\r
842 {\r
843   struct pbuf *q , *prev, *head;\r
844   LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);\r
845   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));\r
846 \r
847   prev = NULL;\r
848   head = p;\r
849   /* iterate through pbuf chain */\r
850   do\r
851   {\r
852     /* pbuf is of type PBUF_REF? */\r
853     if (p->flags == PBUF_FLAG_REF) {\r
854       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));\r
855       /* allocate a pbuf (w/ payload) fully in RAM */\r
856       /* PBUF_POOL buffers are faster if we can use them */\r
857       if (p->len <= PBUF_POOL_BUFSIZE) {\r
858         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);\r
859         if (q == NULL) {\r
860           LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));\r
861         }\r
862       } else {\r
863         /* no replacement pbuf yet */\r
864         q = NULL;\r
865         LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));\r
866       }\r
867       /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */\r
868       if (q == NULL) {\r
869         q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);\r
870         if (q == NULL) {\r
871           LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));\r
872         }\r
873       }\r
874       /* replacement pbuf could be allocated? */\r
875       if (q != NULL)\r
876       {\r
877         /* copy p to q */\r
878         /* copy successor */\r
879         q->next = p->next;\r
880         /* remove linkage from original pbuf */\r
881         p->next = NULL;\r
882         /* remove linkage to original pbuf */\r
883         if (prev != NULL) {\r
884           /* prev->next == p at this point */\r
885           LWIP_ASSERT("prev->next == p", prev->next == p);\r
886           /* break chain and insert new pbuf instead */\r
887           prev->next = q;\r
888         /* prev == NULL, so we replaced the head pbuf of the chain */\r
889         } else {\r
890           head = q;\r
891         }\r
892         /* copy pbuf payload */\r
893         memcpy(q->payload, p->payload, p->len);\r
894         q->tot_len = p->tot_len;\r
895         q->len = p->len;\r
896         /* in case p was the first pbuf, it is no longer refered to by\r
897          * our caller, as the caller MUST do p = pbuf_take(p);\r
898          * in case p was not the first pbuf, it is no longer refered to\r
899          * by prev. we can safely free the pbuf here.\r
900          * (note that we have set p->next to NULL already so that\r
901          * we will not free the rest of the chain by accident.)\r
902          */\r
903         pbuf_free(p);\r
904         /* do not copy ref, since someone else might be using the old buffer */\r
905         LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));\r
906         p = q;\r
907       } else {\r
908         /* deallocate chain */\r
909         pbuf_free(head);\r
910         LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));\r
911         return NULL;\r
912       }\r
913     /* p->flags != PBUF_FLAG_REF */\r
914     } else {\r
915       LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));\r
916     }\r
917     /* remember this pbuf */\r
918     prev = p;\r
919     /* proceed to next pbuf in original chain */\r
920     p = p->next;\r
921   } while (p);\r
922   LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));\r
923 \r
924   return head;\r
925 }\r
926 \r
927 /**\r
928  * Dechains the first pbuf from its succeeding pbufs in the chain.\r
929  *\r
930  * Makes p->tot_len field equal to p->len.\r
931  * @param p pbuf to dechain\r
932  * @return remainder of the pbuf chain, or NULL if it was de-allocated.\r
933  * @note May not be called on a packet queue.\r
934  */\r
935 struct pbuf *\r
936 pbuf_dechain(struct pbuf *p)\r
937 {\r
938   struct pbuf *q;\r
939   u8_t tail_gone = 1;\r
940   /* tail */\r
941   q = p->next;\r
942   /* pbuf has successor in chain? */\r
943   if (q != NULL) {\r
944     /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
945     LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);\r
946     /* enforce invariant if assertion is disabled */\r
947     q->tot_len = p->tot_len - p->len;\r
948     /* decouple pbuf from remainder */\r
949     p->next = NULL;\r
950     /* total length of pbuf p is its own length only */\r
951     p->tot_len = p->len;\r
952     /* q is no longer referenced by p, free it */\r
953     LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));\r
954     tail_gone = pbuf_free(q);\r
955     if (tail_gone > 0) {\r
956       LWIP_DEBUGF(PBUF_DEBUG | DBG_STATE,\r
957                   ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));\r
958     }\r
959     /* return remaining tail or NULL if deallocated */\r
960   }\r
961   /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
962   LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);\r
963   return (tail_gone > 0? NULL: q);\r
964 }\r