b327899ea8bb30fc88dbcc94bdf3ed8dedb553d1
[akaros.git] / kern / src / net / pbuf.c
1 #include <ros/common.h>
2 #include <stdio.h>
3
4 #include <string.h>
5 #include <kmalloc.h>
6 #include <slab.h>
7 #include <assert.h>
8 #include <net/pbuf.h>
9 #include <sys/queue.h>
10 #include <net.h>
11 #include <debug.h>
12 #include <net/nic_common.h>
13
14
15 /* TODO: before running
16  * 1. pbuf_free_auto currently decrefs the next one on the chain or queue
17  * 2. copy_out currently copies out the chain following the next pointer
18  *    could be dangerous if it runs on pbufs on a send/recv socket queue
19  * 3. Tot_len could be useless at some point, especially if the max len is only two...
20  * 4. pbuf_chain and pbuf_cat, pbuf_clen has no users yet
21  */
22 #define SIZEOF_STRUCT_PBUF (ROUNDUP(sizeof(struct pbuf), ROS_MEM_ALIGN))
23 #define MTU_PBUF_SIZE SIZEOF_STRUCT_PBUF + MAX_FRAME_SIZE + ETH_PAD_SIZE
24
25 struct kmem_cache *pbuf_kcache;
26 struct kmem_cache *mtupbuf_kcache;
27
28
29 void pbuf_init(void){
30         printk("size of struct pbuf%d, %d \n", SIZEOF_STRUCT_PBUF, sizeof(struct pbuf));
31         printk("alignment %d\n", __alignof__(struct pbuf));
32         pbuf_kcache = kmem_cache_create("pbuf", sizeof(struct pbuf),
33                                                                         __alignof__(struct pbuf), 0, 0, 0);
34   mtupbuf_kcache = kmem_cache_create("mtupbuf_kcache", MTU_PBUF_SIZE, 
35                                                                                 __alignof__(struct pbuf), 0, 0, 0);
36 }
37
38 static void pbuf_free_auto(struct kref *kref){
39     struct pbuf *p = container_of(kref, struct pbuf, bufref);
40                 if (!p) return;
41                 struct pbuf *q = STAILQ_NEXT(p, next);
42                 printd("deleting p %p of type %d\n", p, p->type);
43     switch (p->type){
44         case PBUF_REF:
45             kmem_cache_free(pbuf_kcache, p);
46             break;
47         case PBUF_RAM:
48             kfree(p);
49             break;
50                                 case PBUF_MTU:
51                                                 kmem_cache_free(mtupbuf_kcache,p);
52                                                 break;
53         default:
54             panic("Invalid pbuf type");
55     }
56                 if (q != NULL) 
57                         pbuf_deref(q);
58 }
59
60 /**
61  * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
62  *
63  * The actual memory allocated for the pbuf is determined by the
64  * layer at which the pbuf is allocated and the requested size
65  * (from the size parameter).
66  *
67  * @param layer flag to define header size
68  * @param length size of the pbuf's payload
69  * @param type this parameter decides how and where the pbuf
70  * should be allocated as follows:
71  *
72  * - PBUF_RAM: buffer memory for pbuf is allocated as one large
73  *             chunk. This includes protocol headers as well.
74  * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
75  *             protocol headers. Additional headers must be prepended
76  *             by allocating another pbuf and chain in to the front of
77  *             the ROM pbuf. It is assumed that the memory used is really
78  *             similar to ROM in that it is immutable and will not be
79  *             changed. Memory which is dynamic should generally not
80  *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
81  * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
82  *             protocol headers. It is assumed that the pbuf is only
83  *             being used in a single thread. If the pbuf gets queued,
84  *             then pbuf_take should be called to copy the buffer.
85  * - PBUF_MTU: specific to ROS, additional type that comes out of a 
86  *             slab dedicated for the most common size (MTU sized) pbuf.
87  *
88  * @return the allocated pbuf. If multiple pbufs where allocated, this
89  * is the first pbuf of a pbuf chain.
90  */
91 struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
92 {
93   struct pbuf *p, *q, *r;
94   uint16_t offset;
95         uint16_t buf_size; 
96   int rem_len; /* remaining length */
97
98   /* determine header offset */
99   offset = 0;
100   switch (layer) {
101   case PBUF_TRANSPORT:
102     /* add room for transport (often TCP) layer header */
103     offset += PBUF_TRANSPORT_HLEN;
104     /* FALLTHROUGH */
105   case PBUF_IP:
106     /* add room for IP layer header */
107     offset += PBUF_IP_HLEN;
108     /* FALLTHROUGH */
109   case PBUF_LINK:
110     /* add room for link layer header */
111     offset += PBUF_LINK_HLEN;
112     break;
113   case PBUF_RAW:
114     break;
115   default:
116     warn("pbuf_alloc: bad pbuf layer", 0);
117     return NULL;
118   }
119         
120   switch (type) {
121         case PBUF_MTU:
122                 /* special case PBUFs that are of a common size, notice the length has to be 0 in this case */
123                 assert(length==0); // TODO: reconsider this
124     /* only allocate memory for the pbuf structure */
125     p = (struct pbuf *)kmem_cache_alloc(mtupbuf_kcache, 0);
126     if (p == NULL) {
127       return NULL;
128     }
129     p->payload = (void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset);
130                 STAILQ_NEXT(p, next) = NULL;
131                 p->type = type;
132                 p->alloc_len = MTU_PBUF_SIZE;
133                 p->len = p->tot_len = 0;
134                 break;
135
136         case PBUF_RAM:
137     /* If pbuf is to be allocated in RAM, allocate memory for it. */
138                 buf_size =  (SIZEOF_STRUCT_PBUF + offset) + MEM_ALIGN_SIZE(length);
139     p = (struct pbuf*)kmalloc(buf_size, 0);
140
141     if (p == NULL) {
142       return NULL;
143     }
144     /* Set up internal structure of the pbuf. */
145     p->payload = (void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset);
146     p->alloc_len = p->len = p->tot_len = length;
147                 STAILQ_NEXT(p, next) = NULL;
148     p->type = type;
149     break;
150   case PBUF_REF:
151     /* only allocate memory for the pbuf structure */
152     p = (struct pbuf *)kmem_cache_alloc(pbuf_kcache, 0);
153     if (p == NULL) {
154       return NULL;
155     }
156     p->payload = NULL;
157     p->alloc_len = p->len = p->tot_len = length;
158                 STAILQ_NEXT(p, next) = NULL;
159     p->type = type;
160     break;
161         case PBUF_POOL:
162                 warn("POOL type not supported!");       
163                 return NULL;    
164   default:
165     warn("pbuf_alloc: wrong type", 0);
166     return NULL;
167   }
168   kref_init(&p->bufref, pbuf_free_auto, 1); // TODO: pbuf_free
169   /* set flags */
170   p->flags = 0;
171   return p;
172 }
173
174
175 /**
176  * Shrink a pbuf chain to a desired length.
177  *
178  * @param p pbuf to shrink.
179  * @param new_len desired new length of pbuf chain
180  *
181  * Depending on the desired length, the first few pbufs in a chain might
182  * be skipped and left unchanged. The new last pbuf in the chain will be
183  * resized, and any remaining pbufs will be freed.
184  *
185  * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
186  * @note May not be called on a packet queue.
187  *
188  * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
189  */
190 void
191 pbuf_realloc(struct pbuf *p, uint16_t new_len)
192 {
193   struct pbuf *q;
194   uint16_t rem_len; /* remaining length */
195   int32_t grow;
196
197   /* desired length larger than current length? */
198   if (new_len >= p->tot_len) {
199     /* enlarging not yet supported */
200     return;
201   }
202
203   /* the pbuf chain grows by (new_len - p->tot_len) bytes
204    * (which may be negative in case of shrinking) */
205   grow = new_len - p->tot_len;
206
207   /* first, step over any pbufs that should remain in the chain */
208   rem_len = new_len;
209   q = p;
210   /* should this pbuf be kept? */
211   while (rem_len > q->len) {
212     /* decrease remaining length by pbuf length */
213     rem_len -= q->len;
214     /* decrease total length indicator */
215     LWIP_ASSERT("grow < max_uint16_t", grow < 0xffff);
216     q->tot_len += (uint16_t)grow;
217     /* proceed to next pbuf in chain */
218                 q = STAILQ_NEXT(q, next);
219     LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
220   }
221   /* we have now reached the new last pbuf (in q) */
222   /* rem_len == desired length for pbuf q */
223
224   /* adjust length fields for new last pbuf */
225   q->len = rem_len;
226   q->tot_len = q->len;
227
228   /* any remaining pbufs in chain? */
229   if (STAILQ_NEXT(q, next) != NULL) {
230     /* free remaining pbufs in chain */
231                 pbuf_free(STAILQ_NEXT(q, next));
232   }
233   /* q is last packet in chain */
234         STAILQ_NEXT(q, next) = NULL;
235 }
236
237 void pbuf_ref(struct pbuf *p){
238         kref_get(&p->bufref, 1);
239 }
240
241 /**
242  * true if the pbuf is deallocated as a result of pbuf_deref
243  * false means just a simple deref
244  */
245 bool pbuf_deref(struct pbuf *p){
246         return kref_put(&p->bufref);
247 }
248
249 void attach_pbuf(struct pbuf *p, struct pbuf_head *ph){
250         spin_lock_irqsave(&ph->lock);
251         ph->qlen++;
252         pbuf_ref(p);
253         STAILQ_INSERT_TAIL(&ph->pbuf_fifo, p, next);
254         spin_unlock_irqsave(&ph->lock);
255 }
256
257 struct pbuf* detach_pbuf(struct pbuf_head *ph){
258         struct pbuf* buf = NULL;
259         if (ph->qlen == 0) return NULL;
260         spin_lock_irqsave(&ph->lock);
261         ph->qlen--;
262         buf = STAILQ_FIRST(&ph->pbuf_fifo);
263         STAILQ_REMOVE_HEAD(&ph->pbuf_fifo, next);
264         spin_unlock_irqsave(&ph->lock);
265         return buf;
266 }
267
268 /**
269  * Copy (part of) the contents of a packet buffer
270  * to an application supplied buffer.
271  *
272  * @param buf the pbuf from which to copy data
273  * @param dataptr the application supplied buffer
274  * @param len length of data to copy (dataptr must be big enough). No more 
275  * than buf->tot_len will be copied, irrespective of len
276  * @param offset offset into the packet buffer from where to begin copying len bytes
277  * @return the number of bytes copied, or 0 on failure
278  */
279 int pbuf_copy_out(struct pbuf *buf, void *dataptr, size_t len, uint16_t offset)
280 {
281   struct pbuf *p;
282   uint16_t left;
283   uint16_t buf_copy_len;
284   uint16_t copied_total = 0;
285         
286         if (dataptr == NULL || buf == NULL){
287                 warn("Copying a pbuf_copy to null pointer");
288                 return 0;
289         }
290
291   left = 0;
292   for(p = buf; len != 0 && p != NULL; p = STAILQ_NEXT(p, next)) {
293     if ((offset != 0) && (offset >= p->len)) {
294       /* don't copy from this buffer -> on to the next */
295       offset -= p->len;
296     } else {
297                         /* offset is 0 now, start copying */
298       buf_copy_len = p->len - offset;
299       if (buf_copy_len > len)
300           buf_copy_len = len;
301       /* copy the necessary parts of the buffer */
302       memcpy(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
303       copied_total += buf_copy_len;
304       left += buf_copy_len;
305       len -= buf_copy_len;
306       offset = 0;
307     }
308   }
309   return copied_total;
310 }
311
312 /**
313  * Chain two pbufs (or pbuf chains) together.
314  * 
315  * The caller MUST call pbuf_free(t) once it has stopped
316  * using it. Use pbuf_cat() instead if you no longer use t.
317  * 
318  * @param h head pbuf (chain)
319  * @param t tail pbuf (chain)
320  * @note The pbufs MUST belong to the same packet.
321  * @note MAY NOT be called on a packet queue.
322  *
323  * The ->tot_len fields of all pbufs of the head chain are adjusted.
324  * The ->next field of the last pbuf of the head chain is adjusted.
325  * The ->ref field of the first pbuf of the tail chain is adjusted.
326  *
327  */
328 void
329 pbuf_chain(struct pbuf *h, struct pbuf *t)
330 {
331   pbuf_cat(h, t);
332   /* t is now referenced by h */
333   pbuf_ref(t);
334 }
335
336 void
337 pbuf_cat(struct pbuf *h, struct pbuf *t)
338 {
339   struct pbuf *p;
340   /* proceed to last pbuf of chain */
341   for (p = h; STAILQ_NEXT(p, next) != NULL; p = STAILQ_NEXT(p, next)) {
342     /* add total length of second chain to all totals of first chain */
343     p->tot_len += t->tot_len;
344   }
345   /* add total length of second chain to last pbuf total of first chain */
346   p->tot_len += t->tot_len;
347   /* chain last pbuf of head (p) with first of tail (t) */
348         STAILQ_NEXT(p,next) = t;
349 }
350
351 /**
352  * Adjusts the payload pointer to hide or reveal headers in the payload.
353  *
354  * Adjusts the ->payload pointer so that space for a header
355  * (dis)appears in the pbuf payload.
356  *
357  * The ->payload, ->tot_len and ->len fields are adjusted.
358  *
359  * @param p pbuf to change the header size.
360  * @param header_size_increment Number of bytes to increment header size which
361  * increases the size of the pbuf. New space is on the front.
362  * (Using a negative value decreases the header size.)
363  * If hdr_size_inc is 0, this function does nothing and returns succesful.
364  *
365  * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
366  * the call will fail. A check is made that the increase in header size does
367  * not move the payload pointer in front of the start of the buffer.
368  * @return non-zero on failure, zero on success.
369  *
370  */
371
372 /* TODO: when do we need to lock a pbuf?? */
373 int pbuf_header(struct pbuf *p, int delta){ // increase header size
374         uint8_t type = p->type;
375         void *payload = p->payload;
376         if (p == NULL || delta == 0)
377                 return 0;
378         // This assertion used to apply when len meant allocated space..
379         // assert(-delta < p->len);
380
381   /* pbuf types containing payloads? */
382   if (type == PBUF_RAM || type == PBUF_POOL || type == PBUF_MTU) {
383     /* set new payload pointer */
384     p->payload = (uint8_t *)p->payload - delta;
385     /* boundary check fails? */
386     if ((uint8_t *)p->payload < (uint8_t *)p + SIZEOF_STRUCT_PBUF) {
387       /* restore old payload pointer */
388       p->payload = payload;
389                         warn("boundary failed \n");
390       /* bail out unsuccesfully */
391       return 1;
392     }
393   /* pbuf types refering to external payloads? */
394   } else if (type == PBUF_REF || type == PBUF_ROM) {
395                 /* header was embedded in the payload, we are extracting it */
396     if ((delta < 0) && ((-delta) <= p->len)) {
397       /* increase payload pointer */
398       p->payload = (uint8_t *)p->payload - delta;
399     } else {
400       /* cannot expand payload to front (yet!)
401        * bail out unsuccesfully */
402       return 1;
403     }
404   } else {
405     /* Unknown type */
406     assert("bad pbuf type");
407     return 1;
408   }
409   /* modify pbuf length fields */
410   p->len += delta;
411   p->tot_len += delta;
412
413   return 0;
414 }
415
416 void print_pbuf(struct pbuf *p) {
417         struct pbuf *next = p;
418         //basically while pbuf is not on the socket queue yet, we can't use STAILQ_NEXT 
419
420         /*XXX: this is wrong.. */
421         while (next != NULL) {
422                 printk("pbuf start \n");
423                 dumppacket(next->payload, next->len);
424                 printk("\n");
425                 next = STAILQ_NEXT(next, next);
426         }
427 }
428
429
430 /**
431  * Dereference a pbuf chain or queue and deallocate any no-longer-used
432  * pbufs at the head of this chain or queue.
433  *
434  * Decrements the pbuf reference count. If it reaches zero, the pbuf is
435  * deallocated.
436  *
437  * For a pbuf chain, this is repeated for each pbuf in the chain,
438  * up to the first pbuf which has a non-zero reference count after
439  * decrementing. So, when all reference counts are one, the whole
440  * chain is free'd.
441  *
442  * @param p The pbuf (chain) to be dereferenced.
443  *
444  * @return the number of pbufs that were de-allocated
445  * from the head of the chain.
446  *
447  *
448  */
449 bool pbuf_free(struct pbuf *p) {
450         return pbuf_deref(p);
451 }
452
453 /**
454  * Count number of pbufs in a chain
455  *
456  * @param p first pbuf of chain
457  * @return the number of pbufs in a chain
458  */
459
460 uint8_t pbuf_clen(struct pbuf *p)
461 {
462   uint8_t len;
463
464   len = 0;
465   while (p != NULL) {
466     ++len;
467     p = STAILQ_NEXT(p, next);
468   }
469   return len;
470 }
471
472
473 #if 0
474 #if LWIP_SUPPORT_CUSTOM_PBUF
475 /** Initialize a custom pbuf (already allocated).
476  *
477  * @param layer flag to define header size
478  * @param length size of the pbuf's payload
479  * @param type type of the pbuf (only used to treat the pbuf accordingly, as
480  *        this function allocates no memory)
481  * @param p pointer to the custom pbuf to initialize (already allocated)
482  * @param payload_mem pointer to the buffer that is used for payload and headers,
483  *        must be at least big enough to hold 'length' plus the header size,
484  *        may be NULL if set later
485  * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
486  *        big enough to hold 'length' plus the header size
487  */
488 struct pbuf*
489 pbuf_alloced_custom(pbuf_layer l, uint16_t length, pbuf_type type, struct pbuf_custom *p,
490                     void *payload_mem, uint16_t payload_mem_len)
491 {
492   uint16_t offset;
493   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
494
495   /* determine header offset */
496   offset = 0;
497   switch (l) {
498   case PBUF_TRANSPORT:
499     /* add room for transport (often TCP) layer header */
500     offset += PBUF_TRANSPORT_HLEN;
501     /* FALLTHROUGH */
502   case PBUF_IP:
503     /* add room for IP layer header */
504     offset += PBUF_IP_HLEN;
505     /* FALLTHROUGH */
506   case PBUF_LINK:
507     /* add room for link layer header */
508     offset += PBUF_LINK_HLEN;
509     break;
510   case PBUF_RAW:
511     break;
512   default:
513     LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
514     return NULL;
515   }
516
517   if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
518     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
519     return NULL;
520   }
521
522   p->pbuf.next = NULL;
523   if (payload_mem != NULL) {
524     p->pbuf.payload = LWIP_MEM_ALIGN((void *)((uint8_t *)payload_mem + offset));
525   } else {
526     p->pbuf.payload = NULL;
527   }
528   p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
529   p->pbuf.len = p->pbuf.tot_len = length;
530   p->pbuf.type = type;
531   p->pbuf.ref = 1;
532   return &p->pbuf;
533 }
534 #endif /* LWIP_SUPPORT_CUSTOM_PBUF */
535
536 /**
537  * Shrink a pbuf chain to a desired length.
538  *
539  * @param p pbuf to shrink.
540  * @param new_len desired new length of pbuf chain
541  *
542  * Depending on the desired length, the first few pbufs in a chain might
543  * be skipped and left unchanged. The new last pbuf in the chain will be
544  * resized, and any remaining pbufs will be freed.
545  *
546  * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
547  * @note May not be called on a packet queue.
548  *
549  * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
550  */
551 void
552 pbuf_realloc(struct pbuf *p, uint16_t new_len)
553 {
554   struct pbuf *q;
555   uint16_t rem_len; /* remaining length */
556   int32_t grow;
557
558   LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
559   LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
560               p->type == PBUF_ROM ||
561               p->type == PBUF_RAM ||
562               p->type == PBUF_REF);
563
564   /* desired length larger than current length? */
565   if (new_len >= p->tot_len) {
566     /* enlarging not yet supported */
567     return;
568   }
569
570   /* the pbuf chain grows by (new_len - p->tot_len) bytes
571    * (which may be negative in case of shrinking) */
572   grow = new_len - p->tot_len;
573
574   /* first, step over any pbufs that should remain in the chain */
575   rem_len = new_len;
576   q = p;
577   /* should this pbuf be kept? */
578   while (rem_len > q->len) {
579     /* decrease remaining length by pbuf length */
580     rem_len -= q->len;
581     /* decrease total length indicator */
582     LWIP_ASSERT("grow < max_uint16_t", grow < 0xffff);
583     q->tot_len += (uint16_t)grow;
584     /* proceed to next pbuf in chain */
585     q = q->next;
586     LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
587   }
588   /* we have now reached the new last pbuf (in q) */
589   /* rem_len == desired length for pbuf q */
590
591   /* shrink allocated memory for PBUF_RAM */
592   /* (other types merely adjust their length fields */
593   if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
594     /* reallocate and adjust the length of the pbuf that will be split */
595     q = (struct pbuf *)mem_trim(q, (uint16_t)((uint8_t *)q->payload - (uint8_t *)q) + rem_len);
596     LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
597   }
598   /* adjust length fields for new last pbuf */
599   q->len = rem_len;
600   q->tot_len = q->len;
601
602   /* any remaining pbufs in chain? */
603   if (q->next != NULL) {
604     /* free remaining pbufs in chain */
605     pbuf_free(q->next);
606   }
607   /* q is last packet in chain */
608   q->next = NULL;
609
610 }
611
612
613
614 /**
615  * Increment the reference count of the pbuf.
616  *
617  * @param p pbuf to increase reference counter of
618  *
619  */
620 void
621 pbuf_ref(struct pbuf *p)
622 {
623   SYS_ARCH_DECL_PROTECT(old_level);
624   /* pbuf given? */
625   if (p != NULL) {
626     SYS_ARCH_PROTECT(old_level);
627     ++(p->ref);
628     SYS_ARCH_UNPROTECT(old_level);
629   }
630 }
631
632 /**
633  * Concatenate two pbufs (each may be a pbuf chain) and take over
634  * the caller's reference of the tail pbuf.
635  * 
636  * @note The caller MAY NOT reference the tail pbuf afterwards.
637  * Use pbuf_chain() for that purpose.
638  * 
639  * @see pbuf_chain()
640  */
641
642 void
643 pbuf_cat(struct pbuf *h, struct pbuf *t)
644 {
645   struct pbuf *p;
646
647   LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
648              ((h != NULL) && (t != NULL)), return;);
649
650   /* proceed to last pbuf of chain */
651   for (p = h; p->next != NULL; p = p->next) {
652     /* add total length of second chain to all totals of first chain */
653     p->tot_len += t->tot_len;
654   }
655   /* { p is last pbuf of first h chain, p->next == NULL } */
656   LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
657   LWIP_ASSERT("p->next == NULL", p->next == NULL);
658   /* add total length of second chain to last pbuf total of first chain */
659   p->tot_len += t->tot_len;
660   /* chain last pbuf of head (p) with first of tail (t) */
661   p->next = t;
662   /* p->next now references t, but the caller will drop its reference to t,
663    * so netto there is no change to the reference count of t.
664    */
665 }
666
667 /**
668  * Chain two pbufs (or pbuf chains) together.
669  * 
670  * The caller MUST call pbuf_free(t) once it has stopped
671  * using it. Use pbuf_cat() instead if you no longer use t.
672  * 
673  * @param h head pbuf (chain)
674  * @param t tail pbuf (chain)
675  * @note The pbufs MUST belong to the same packet.
676  * @note MAY NOT be called on a packet queue.
677  *
678  * The ->tot_len fields of all pbufs of the head chain are adjusted.
679  * The ->next field of the last pbuf of the head chain is adjusted.
680  * The ->ref field of the first pbuf of the tail chain is adjusted.
681  *
682  */
683 void
684 pbuf_chain(struct pbuf *h, struct pbuf *t)
685 {
686   pbuf_cat(h, t);
687   /* t is now referenced by h */
688   pbuf_ref(t);
689   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
690 }
691
692 /**
693  * Dechains the first pbuf from its succeeding pbufs in the chain.
694  *
695  * Makes p->tot_len field equal to p->len.
696  * @param p pbuf to dechain
697  * @return remainder of the pbuf chain, or NULL if it was de-allocated.
698  * @note May not be called on a packet queue.
699  */
700 struct pbuf *
701 pbuf_dechain(struct pbuf *p)
702 {
703   struct pbuf *q;
704   uint8_t tail_gone = 1;
705   /* tail */
706   q = p->next;
707   /* pbuf has successor in chain? */
708   if (q != NULL) {
709     /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
710     LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
711     /* enforce invariant if assertion is disabled */
712     q->tot_len = p->tot_len - p->len;
713     /* decouple pbuf from remainder */
714     p->next = NULL;
715     /* total length of pbuf p is its own length only */
716     p->tot_len = p->len;
717     /* q is no longer referenced by p, free it */
718     LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
719     tail_gone = pbuf_free(q);
720     if (tail_gone > 0) {
721       LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
722                   ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
723     }
724     /* return remaining tail or NULL if deallocated */
725   }
726   /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
727   LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
728   return ((tail_gone > 0) ? NULL : q);
729 }
730
731 /**
732  *
733  * Create PBUF_RAM copies of pbufs.
734  *
735  * Used to queue packets on behalf of the lwIP stack, such as
736  * ARP based queueing.
737  *
738  * @note You MUST explicitly use p = pbuf_take(p);
739  *
740  * @note Only one packet is copied, no packet queue!
741  *
742  * @param p_to pbuf destination of the copy
743  * @param p_from pbuf source of the copy
744  *
745  * @return ERR_OK if pbuf was copied
746  *         ERR_ARG if one of the pbufs is NULL or p_to is not big
747  *                 enough to hold p_from
748  */
749 err_t
750 pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
751 {
752   uint16_t offset_to=0, offset_from=0, len;
753
754   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
755     (void*)p_to, (void*)p_from));
756
757   /* is the target big enough to hold the source? */
758   LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
759              (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
760
761   /* iterate through pbuf chain */
762   do
763   {
764     LWIP_ASSERT("p_to != NULL", p_to != NULL);
765     /* copy one part of the original chain */
766     if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
767       /* complete current p_from fits into current p_to */
768       len = p_from->len - offset_from;
769     } else {
770       /* current p_from does not fit into current p_to */
771       len = p_to->len - offset_to;
772     }
773     MEMCPY((uint8_t*)p_to->payload + offset_to, (uint8_t*)p_from->payload + offset_from, len);
774     offset_to += len;
775     offset_from += len;
776     LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
777     if (offset_to == p_to->len) {
778       /* on to next p_to (if any) */
779       offset_to = 0;
780       p_to = p_to->next;
781     }
782     LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
783     if (offset_from >= p_from->len) {
784       /* on to next p_from (if any) */
785       offset_from = 0;
786       p_from = p_from->next;
787     }
788
789     if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
790       /* don't copy more than one packet! */
791       LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
792                  (p_from->next == NULL), return ERR_VAL;);
793     }
794     if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
795       /* don't copy more than one packet! */
796       LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
797                   (p_to->next == NULL), return ERR_VAL;);
798     }
799   } while (p_from);
800   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
801   return ERR_OK;
802 }
803
804
805 /**
806  * Copy application supplied data into a pbuf.
807  * This function can only be used to copy the equivalent of buf->tot_len data.
808  *
809  * @param buf pbuf to fill with data
810  * @param dataptr application supplied data buffer
811  * @param len length of the application supplied data buffer
812  *
813  * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
814  */
815 err_t
816 pbuf_take(struct pbuf *buf, const void *dataptr, uint16_t len)
817 {
818   struct pbuf *p;
819   uint16_t buf_copy_len;
820   uint16_t total_copy_len = len;
821   uint16_t copied_total = 0;
822
823   LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
824   LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
825
826   if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
827     return ERR_ARG;
828   }
829
830   /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
831   for(p = buf; total_copy_len != 0; p = p->next) {
832     LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
833     buf_copy_len = total_copy_len;
834     if (buf_copy_len > p->len) {
835       /* this pbuf cannot hold all remaining data */
836       buf_copy_len = p->len;
837     }
838     /* copy the necessary parts of the buffer */
839     MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
840     total_copy_len -= buf_copy_len;
841     copied_total += buf_copy_len;
842   }
843   LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
844   return ERR_OK;
845 }
846
847 /**
848  * Creates a single pbuf out of a queue of pbufs.
849  *
850  * @remark: Either the source pbuf 'p' is freed by this function or the original
851  *          pbuf 'p' is returned, therefore the caller has to check the result!
852  *
853  * @param p the source pbuf
854  * @param layer pbuf_layer of the new pbuf
855  *
856  * @return a new, single pbuf (p->next is NULL)
857  *         or the old pbuf if allocation fails
858  */
859 struct pbuf*
860 pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
861 {
862   struct pbuf *q;
863   err_t err;
864   if (p->next == NULL) {
865     return p;
866   }
867   q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
868   if (q == NULL) {
869     /* @todo: what do we do now? */
870     return p;
871   }
872   err = pbuf_copy(q, p);
873   LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
874   pbuf_free(p);
875   return q;
876 }
877
878 #if LWIP_CHECKSUM_ON_COPY
879 /**
880  * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
881  * the checksum while copying
882  *
883  * @param p the pbuf to copy data into
884  * @param start_offset offset of p->payload where to copy the data to
885  * @param dataptr data to copy into the pbuf
886  * @param len length of data to copy into the pbuf
887  * @param chksum pointer to the checksum which is updated
888  * @return ERR_OK if successful, another error if the data does not fit
889  *         within the (first) pbuf (no pbuf queues!)
890  */
891 err_t
892 pbuf_fill_chksum(struct pbuf *p, uint16_t start_offset, const void *dataptr,
893                  uint16_t len, uint16_t *chksum)
894 {
895   u32_t acc;
896   uint16_t copy_chksum;
897   char *dst_ptr;
898   LWIP_ASSERT("p != NULL", p != NULL);
899   LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
900   LWIP_ASSERT("chksum != NULL", chksum != NULL);
901   LWIP_ASSERT("len != 0", len != 0);
902
903   if ((start_offset >= p->len) || (start_offset + len > p->len)) {
904     return ERR_ARG;
905   }
906
907   dst_ptr = ((char*)p->payload) + start_offset;
908   copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
909   if ((start_offset & 1) != 0) {
910     copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
911   }
912   acc = *chksum;
913   acc += copy_chksum;
914   *chksum = FOLD_U32T(acc);
915   return ERR_OK;
916 }
917 #endif /* LWIP_CHECKSUM_ON_COPY */
918
919  /** Get one byte from the specified position in a pbuf
920  * WARNING: returns zero for offset >= p->tot_len
921  *
922  * @param p pbuf to parse
923  * @param offset offset into p of the byte to return
924  * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
925  */
926 uint8_t
927 pbuf_get_at(struct pbuf* p, uint16_t offset)
928 {
929   uint16_t copy_from = offset;
930   struct pbuf* q = p;
931
932   /* get the correct pbuf */
933   while ((q != NULL) && (q->len <= copy_from)) {
934     copy_from -= q->len;
935     q = q->next;
936   }
937   /* return requested data if pbuf is OK */
938   if ((q != NULL) && (q->len > copy_from)) {
939     return ((uint8_t*)q->payload)[copy_from];
940   }
941   return 0;
942 }
943
944 /** Compare pbuf contents at specified offset with memory s2, both of length n
945  *
946  * @param p pbuf to compare
947  * @param offset offset into p at wich to start comparing
948  * @param s2 buffer to compare
949  * @param n length of buffer to compare
950  * @return zero if equal, nonzero otherwise
951  *         (0xffff if p is too short, diffoffset+1 otherwise)
952  */
953 uint16_t
954 pbuf_memcmp(struct pbuf* p, uint16_t offset, const void* s2, uint16_t n)
955 {
956   uint16_t start = offset;
957   struct pbuf* q = p;
958
959   /* get the correct pbuf */
960   while ((q != NULL) && (q->len <= start)) {
961     start -= q->len;
962     q = q->next;
963   }
964   /* return requested data if pbuf is OK */
965   if ((q != NULL) && (q->len > start)) {
966     uint16_t i;
967     for(i = 0; i < n; i++) {
968       uint8_t a = pbuf_get_at(q, start + i);
969       uint8_t b = ((uint8_t*)s2)[i];
970       if (a != b) {
971         return i+1;
972       }
973     }
974     return 0;
975   }
976   return 0xffff;
977 }
978
979 /** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
980  * start_offset.
981  *
982  * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
983  *        return value 'not found'
984  * @param mem search for the contents of this buffer
985  * @param mem_len length of 'mem'
986  * @param start_offset offset into p at which to start searching
987  * @return 0xFFFF if substr was not found in p or the index where it was found
988  */
989 uint16_t
990 pbuf_memfind(struct pbuf* p, const void* mem, uint16_t mem_len, uint16_t start_offset)
991 {
992   uint16_t i;
993   uint16_t max = p->tot_len - mem_len;
994   if (p->tot_len >= mem_len + start_offset) {
995     for(i = start_offset; i <= max; ) {
996       uint16_t plus = pbuf_memcmp(p, i, mem, mem_len);
997       if (plus == 0) {
998         return i;
999       } else {
1000         i += plus;
1001       }
1002     }
1003   }
1004   return 0xFFFF;
1005 }
1006
1007 /** Find occurrence of substr with length substr_len in pbuf p, start at offset
1008  * start_offset
1009  * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
1010  * the pbuf/source string!
1011  *
1012  * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
1013  *        return value 'not found'
1014  * @param substr string to search for in p, maximum length is 0xFFFE
1015  * @return 0xFFFF if substr was not found in p or the index where it was found
1016  */
1017 uint16_t
1018 pbuf_strstr(struct pbuf* p, const char* substr)
1019 {
1020   size_t substr_len;
1021   if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
1022     return 0xFFFF;
1023   }
1024   substr_len = strlen(substr);
1025   if (substr_len >= 0xFFFF) {
1026     return 0xFFFF;
1027   }
1028   return pbuf_memfind(p, substr, (uint16_t)substr_len, 0);
1029 }
1030
1031 #endif /*EVERYTHING*/