• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Software in this file is based heavily on code written in the FreeBSD source
3  * code repostiory.  While the code is written from scratch, it contains
4  * many of the ideas and logic flow in the original source, this is a
5  * derivative work, and the following license applies as well:
6  *
7  * Copyright (c) 1982, 1986, 1988, 1991, 1993
8  *  The Regents of the University of California.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <assert.h>
37 #include <stddef.h>
38 #include <string.h>
39 #include <limits.h>
40 #include "os/os.h"
41 #include "securec.h"
42 
43 /**
44  * @addtogroup OSKernel
45  * @{
46  *   @defgroup OSMqueue Queue of Mbufs
47  *   @{
48  */
49 
50 STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list = STAILQ_HEAD_INITIALIZER(g_msys_pool_list);
51 
os_mqueue_init(struct os_mqueue * mq,ble_npl_event_fn * ev_cb,void * arg)52 int os_mqueue_init(struct os_mqueue *mq, ble_npl_event_fn *ev_cb, void *arg)
53 {
54     struct ble_npl_event *ev;
55     STAILQ_INIT(&mq->mq_head);
56     ev = &mq->mq_ev;
57     ble_npl_event_init(ev, ev_cb, arg);
58     return (0);
59 }
60 
os_mqueue_get(struct os_mqueue * mq)61 struct os_mbuf *os_mqueue_get(struct os_mqueue *mq)
62 {
63     struct os_mbuf_pkthdr *mp;
64     struct os_mbuf *m;
65     os_sr_t sr;
66     OS_ENTER_CRITICAL(sr);
67     mp = STAILQ_FIRST(&mq->mq_head);
68     if (mp) {
69         STAILQ_REMOVE_HEAD(&mq->mq_head, omp_next);
70     }
71 
72     OS_EXIT_CRITICAL(sr);
73 
74     if (mp) {
75         m = OS_MBUF_PKTHDR_TO_MBUF(mp);
76     } else {
77         m = NULL;
78     }
79 
80     return (m);
81 }
82 
os_mqueue_put(struct os_mqueue * mq,struct ble_npl_eventq * evq,struct os_mbuf * m)83 int os_mqueue_put(struct os_mqueue *mq, struct ble_npl_eventq *evq, struct os_mbuf *m)
84 {
85     struct os_mbuf_pkthdr *mp;
86     os_sr_t sr;
87     int rc;
88 
89     /* Can only place the head of a chained mbuf on the queue. */
90     if (!OS_MBUF_IS_PKTHDR(m)) {
91         rc = OS_EINVAL;
92         goto err;
93     }
94 
95     mp = OS_MBUF_PKTHDR(m);
96     OS_ENTER_CRITICAL(sr);
97     STAILQ_INSERT_TAIL(&mq->mq_head, mp, omp_next);
98     OS_EXIT_CRITICAL(sr);
99 
100     /* Only post an event to the queue if its specified */
101     if (evq) {
102         ble_npl_eventq_put(evq, &mq->mq_ev);
103     }
104 
105     return (0);
106 err:
107     return (rc);
108 }
109 
os_msys_register(struct os_mbuf_pool * new_pool)110 int os_msys_register(struct os_mbuf_pool *new_pool)
111 {
112     struct os_mbuf_pool *pool;
113     pool = NULL;
114     STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) {
115         if (new_pool->omp_databuf_len > pool->omp_databuf_len) {
116             break;
117         }
118     }
119 
120     if (pool) {
121         STAILQ_INSERT_AFTER(&g_msys_pool_list, pool, new_pool, omp_next);
122     } else {
123         STAILQ_INSERT_TAIL(&g_msys_pool_list, new_pool, omp_next);
124     }
125 
126     return (0);
127 }
128 
os_msys_reset(void)129 void os_msys_reset(void)
130 {
131     STAILQ_INIT(&g_msys_pool_list);
132 }
133 
_os_msys_find_pool(uint16_t dsize)134 static struct os_mbuf_pool *_os_msys_find_pool(uint16_t dsize)
135 {
136     struct os_mbuf_pool *pool;
137     pool = NULL;
138     STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) {
139         if (dsize <= pool->omp_databuf_len) {
140             break;
141         }
142     }
143 
144     if (!pool) {
145         pool = STAILQ_LAST(&g_msys_pool_list, os_mbuf_pool, omp_next);
146     }
147 
148     return (pool);
149 }
150 
os_msys_get(uint16_t dsize,uint16_t leadingspace)151 struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace)
152 {
153     struct os_mbuf *m;
154     struct os_mbuf_pool *pool;
155     pool = _os_msys_find_pool(dsize);
156     if (!pool) {
157         goto err;
158     }
159 
160     m = os_mbuf_get(pool, leadingspace);
161     return (m);
162 err:
163     return (NULL);
164 }
165 
os_msys_get_pkthdr(uint16_t dsize,uint16_t user_hdr_len)166 struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len)
167 {
168     uint16_t total_pkthdr_len;
169     struct os_mbuf *m;
170     struct os_mbuf_pool *pool;
171     total_pkthdr_len =  user_hdr_len + sizeof(struct os_mbuf_pkthdr);
172     pool = _os_msys_find_pool(dsize + total_pkthdr_len);
173     if (!pool) {
174         goto err;
175     }
176 
177     m = os_mbuf_get_pkthdr(pool, user_hdr_len);
178     return (m);
179 err:
180     return (NULL);
181 }
182 
os_msys_count(void)183 int os_msys_count(void)
184 {
185     struct os_mbuf_pool *omp;
186     int total;
187     total = 0;
188     STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) {
189         total += omp->omp_pool->mp_num_blocks;
190     }
191     return total;
192 }
193 
os_msys_num_free(void)194 int os_msys_num_free(void)
195 {
196     struct os_mbuf_pool *omp;
197     int total;
198     total = 0;
199     STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) {
200         total += omp->omp_pool->mp_num_free;
201     }
202     return total;
203 }
204 
os_mbuf_pool_init(struct os_mbuf_pool * omp,struct os_mempool * mp,uint16_t buf_len,uint16_t nbufs)205 int os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp,
206                       uint16_t buf_len, uint16_t nbufs)
207 {
208     omp->omp_databuf_len = buf_len - sizeof(struct os_mbuf);
209     omp->omp_pool = mp;
210     return (0);
211 }
212 
os_mbuf_get(struct os_mbuf_pool * omp,uint16_t leadingspace)213 struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace)
214 {
215     struct os_mbuf *om;
216 
217     if (leadingspace > omp->omp_databuf_len) {
218         goto err;
219     }
220 
221     om = os_memblock_get(omp->omp_pool);
222     if (!om) {
223         goto err;
224     }
225 
226     SLIST_NEXT(om, om_next) = NULL;
227     om->om_flags = 0;
228     om->om_pkthdr_len = 0;
229     om->om_len = 0;
230     om->om_data = (&om->om_databuf[0] + leadingspace);
231     om->om_omp = omp;
232     return (om);
233 err:
234     return (NULL);
235 }
236 
os_mbuf_get_pkthdr(struct os_mbuf_pool * omp,uint8_t user_pkthdr_len)237 struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len)
238 {
239     uint16_t pkthdr_len;
240 
241     struct os_mbuf *om;
242     /* User packet header must fit inside mbuf */
243     pkthdr_len = user_pkthdr_len + sizeof(struct os_mbuf_pkthdr);
244     if ((pkthdr_len > omp->omp_databuf_len) || (pkthdr_len > 255)) { // 255:Analyzing conditions
245         return NULL;
246     }
247 
248     om = os_mbuf_get(omp, 0);
249     if (om) {
250         om->om_pkthdr_len = pkthdr_len;
251         om->om_data += pkthdr_len;
252         struct os_mbuf_pkthdr *pkthdr = OS_MBUF_PKTHDR(om);
253         pkthdr->omp_len = 0;
254         pkthdr->omp_flags = 0;
255         STAILQ_NEXT(pkthdr, omp_next) = NULL;
256     }
257 
258     return om;
259 }
260 
os_mbuf_free(struct os_mbuf * om)261 int os_mbuf_free(struct os_mbuf *om)
262 {
263     int rc;
264 
265     if (om->om_omp != NULL) {
266         rc = os_memblock_put(om->om_omp->omp_pool, om);
267         if (rc != 0) {
268             goto err;
269         }
270     }
271 
272     return (0);
273 err:
274     return (rc);
275 }
276 
os_mbuf_free_chain(struct os_mbuf * om)277 int os_mbuf_free_chain(struct os_mbuf *om)
278 {
279     struct os_mbuf *om_tmp = om;
280     struct os_mbuf *next;
281     int rc;
282 
283     while (om_tmp != NULL) {
284         next = SLIST_NEXT(om_tmp, om_next);
285         rc = os_mbuf_free(om_tmp);
286         if (rc != 0) {
287             goto err;
288         }
289 
290         om_tmp = next;
291     }
292 
293     return (0);
294 err:
295     return (rc);
296 }
297 
298 /**
299  * Copy a packet header from one mbuf to another.
300  *
301  * @param omp The mbuf pool associated with these buffers
302  * @param new_buf The new buffer to copy the packet header into
303  * @param old_buf The old buffer to copy the packet header from
304  */
_os_mbuf_copypkthdr(struct os_mbuf * new_buf,struct os_mbuf * old_buf)305 static inline void _os_mbuf_copypkthdr(struct os_mbuf *new_buf, struct os_mbuf *old_buf)
306 {
307     assert(new_buf->om_len == 0);
308     memcpy_s(&new_buf->om_databuf[0], sizeof(new_buf->om_databuf[0]), &old_buf->om_databuf[0],
309         old_buf->om_pkthdr_len);
310     new_buf->om_pkthdr_len = old_buf->om_pkthdr_len;
311     new_buf->om_data = new_buf->om_databuf + old_buf->om_pkthdr_len;
312 }
313 
os_mbuf_append(struct os_mbuf * om,const void * data,uint16_t len)314 int os_mbuf_append(struct os_mbuf *om, const void *data,  uint16_t len)
315 {
316     struct os_mbuf_pool *omp;
317     struct os_mbuf *last;
318     struct os_mbuf *new;
319     int remainder;
320     int space;
321     int rc;
322     uint8_t *pdata = (uint8_t *)data;
323 
324     if (om == NULL) {
325         rc = OS_EINVAL;
326         goto err;
327     }
328 
329     omp = om->om_omp;
330     /* Scroll to last mbuf in the chain */
331     last = om;
332 
333     while (SLIST_NEXT(last, om_next) != NULL) {
334         last = SLIST_NEXT(last, om_next);
335     }
336 
337     remainder = len;
338     space = OS_MBUF_TRAILINGSPACE(last);
339     /* If room in current mbuf, copy the first part of the data into the
340      * remaining space in that mbuf.
341      */
342     if (space > 0) {
343         if (space > remainder) {
344             space = remainder;
345         }
346 
347         memcpy_s(OS_MBUF_DATA(last, uint8_t *) + last->om_len,
348             sizeof(OS_MBUF_DATA(last, uint8_t *) + last->om_len), pdata, space);
349         last->om_len += space;
350         pdata += space;
351         remainder -= space;
352     }
353 
354     /* Take the remaining data, and keep allocating new mbufs and copying
355      * data into it, until data is exhausted.
356      */
357     while (remainder > 0) {
358         new = os_mbuf_get(omp, 0);
359         if (!new) {
360             break;
361         }
362 
363         new->om_len = min(omp->omp_databuf_len, remainder);
364         memcpy_s(OS_MBUF_DATA(new, void *), sizeof(OS_MBUF_DATA(new, void *)), pdata, new->om_len);
365         pdata += new->om_len;
366         remainder -= new->om_len;
367         SLIST_NEXT(last, om_next) = new;
368         last = new;
369     }
370 
371     /* Adjust the packet header length in the buffer */
372     if (OS_MBUF_IS_PKTHDR(om)) {
373         OS_MBUF_PKTHDR(om)->omp_len += len - remainder;
374     }
375 
376     if (remainder != 0) {
377         rc = OS_ENOMEM;
378         goto err;
379     }
380 
381     return (0);
382 err:
383     return (rc);
384 }
385 
os_mbuf_appendfrom(struct os_mbuf * dst,const struct os_mbuf * src,uint16_t src_off,uint16_t len)386 int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src,
387                        uint16_t src_off, uint16_t len)
388 {
389     const struct os_mbuf *src_cur_om;
390     uint16_t src_cur_off;
391 
392     src_cur_om = os_mbuf_off(src, src_off, &src_cur_off);
393 
394     while (len > 0) {
395         if (src_cur_om == NULL) {
396             return OS_EINVAL;
397         }
398 
399         uint16_t chunk_sz = min(len, src_cur_om->om_len - src_cur_off);
400         int rc = os_mbuf_append(dst, src_cur_om->om_data + src_cur_off, chunk_sz);
401         if (rc != 0) {
402             return rc;
403         }
404 
405         len -= chunk_sz;
406         src_cur_om = SLIST_NEXT(src_cur_om, om_next);
407         src_cur_off = 0;
408     }
409 
410     return 0;
411 }
412 
os_mbuf_dup(struct os_mbuf * om)413 struct os_mbuf *os_mbuf_dup(struct os_mbuf *om)
414 {
415     struct os_mbuf_pool *omp;
416     struct os_mbuf *head;
417     struct os_mbuf *copy;
418     omp = om->om_omp;
419     head = NULL;
420     copy = NULL;
421 
422     for (; om != NULL; om = SLIST_NEXT(om, om_next)) {
423         if (head) {
424             SLIST_NEXT(copy, om_next) = os_mbuf_get(omp,
425                                                     OS_MBUF_LEADINGSPACE(om));
426             if (!SLIST_NEXT(copy, om_next)) {
427                 os_mbuf_free_chain(head);
428                 goto err;
429             }
430 
431             copy = SLIST_NEXT(copy, om_next);
432         } else {
433             head = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(om));
434             if (!head) {
435                 goto err;
436             }
437 
438             if (OS_MBUF_IS_PKTHDR(om)) {
439                 _os_mbuf_copypkthdr(head, om);
440             }
441 
442             copy = head;
443         }
444 
445         copy->om_flags = om->om_flags;
446         copy->om_len = om->om_len;
447         memcpy_s(OS_MBUF_DATA(copy, uint8_t *), sizeof(OS_MBUF_DATA(copy, uint8_t *)), OS_MBUF_DATA(om, uint8_t *),
448                om->om_len);
449     }
450 
451     return (head);
452 err:
453     return (NULL);
454 }
455 
os_mbuf_off(const struct os_mbuf * om,int off,uint16_t * out_off)456 struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off)
457 {
458     struct os_mbuf *next;
459     struct os_mbuf *cur;
460     /* Cast away const. */
461     cur = (struct os_mbuf *)om;
462 
463     while (1) {
464         if (cur == NULL) {
465             return NULL;
466         }
467 
468         next = SLIST_NEXT(cur, om_next);
469         if (cur->om_len > off ||
470                 (cur->om_len == off && next == NULL)) {
471             *out_off = off;
472             return cur;
473         }
474 
475         off -= cur->om_len;
476         cur = next;
477     }
478 }
479 
os_mbuf_copydata(const struct os_mbuf * m,int off,int len,void * dst)480 int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst)
481 {
482     int off_tmp = off;
483     int len_tmp = len;
484     uint8_t *udst;
485 
486     if (!len_tmp) {
487         return 0;
488     }
489 
490     udst = dst;
491 
492     while (off_tmp > 0) {
493         if (!m) {
494             return (-1);
495         }
496 
497         if (off_tmp < m->om_len) {
498             break;
499         }
500 
501         off_tmp -= m->om_len;
502         m = SLIST_NEXT(m, om_next);
503     }
504 
505     while (len_tmp > 0 && m != NULL) {
506         unsigned int count = min(m->om_len - off_tmp, len_tmp);
507         memcpy_s(udst, sizeof(*udst), m->om_data + off_tmp, count);
508         len_tmp -= count;
509         udst += count;
510         off_tmp = 0;
511         m = SLIST_NEXT(m, om_next);
512     }
513 
514     return (len_tmp > 0 ? -1 : 0);
515 }
516 
os_mbuf_adj(struct os_mbuf * mp,int req_len)517 void os_mbuf_adj(struct os_mbuf *mp, int req_len)
518 {
519     int len = req_len;
520     struct os_mbuf *m;
521 
522     if ((m = mp) == NULL) {
523         return;
524     }
525 
526     if (len >= 0) {
527         /*
528          * Trim from head.
529          */
530         while (m != NULL && len > 0) {
531             if (m->om_len <= len) {
532                 len -= m->om_len;
533                 m->om_len = 0;
534                 m = SLIST_NEXT(m, om_next);
535             } else {
536                 m->om_len -= len;
537                 m->om_data += len;
538                 len = 0;
539             }
540         }
541 
542         if (OS_MBUF_IS_PKTHDR(mp)) {
543             OS_MBUF_PKTHDR(mp)->omp_len -= (req_len - len);
544         }
545     } else {
546         /*
547          * Trim from tail.  Scan the mbuf chain,
548          * calculating its length and finding the last mbuf.
549          * If the adjustment only affects this mbuf, then just
550          * adjust and return.  Otherwise, rescan and truncate
551          * after the remaining size.
552          */
553         len = -len;
554         int count = 0;
555 
556         for (;;) {
557             count += m->om_len;
558 
559             if (SLIST_NEXT(m, om_next) == (struct os_mbuf *)0) {
560                 break;
561             }
562 
563             m = SLIST_NEXT(m, om_next);
564         }
565 
566         if (m->om_len >= len) {
567             m->om_len -= len;
568 
569             if (OS_MBUF_IS_PKTHDR(mp)) {
570                 OS_MBUF_PKTHDR(mp)->omp_len -= len;
571             }
572 
573             return;
574         }
575 
576         count -= len;
577         if (count < 0) {
578             count = 0;
579         }
580 
581         /*
582          * Correct length for chain is "count".
583          * Find the mbuf with last data, adjust its length,
584          * and toss data from remaining mbufs on chain.
585          */
586         m = mp;
587 
588         if (OS_MBUF_IS_PKTHDR(m)) {
589             OS_MBUF_PKTHDR(m)->omp_len = count;
590         }
591 
592         for (; m; m = SLIST_NEXT(m, om_next)) {
593             if (m->om_len >= count) {
594                 m->om_len = count;
595 
596                 if (SLIST_NEXT(m, om_next) != NULL) {
597                     os_mbuf_free_chain(SLIST_NEXT(m, om_next));
598                     SLIST_NEXT(m, om_next) = NULL;
599                 }
600 
601                 break;
602             }
603 
604             count -= m->om_len;
605         }
606     }
607 }
608 
os_mbuf_cmpf(const struct os_mbuf * om,int off,const void * data,int len)609 int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len)
610 {
611     uint16_t data_off;
612     uint16_t om_off;
613     int rc;
614 
615     if (len <= 0) {
616         return 0;
617     }
618 
619     data_off = 0;
620     om = os_mbuf_off(om, off, &om_off);
621 
622     while (1) {
623         if (om == NULL) {
624             return INT_MAX;
625         }
626 
627         uint16_t chunk_sz = min(om->om_len - om_off, len - data_off);
628         if (chunk_sz > 0) {
629             rc = memcmp(om->om_data + om_off, (uint8_t *)data + data_off, chunk_sz);
630             if (rc != 0) {
631                 return rc;
632             }
633         }
634 
635         data_off += chunk_sz;
636         if (data_off == len) {
637             return 0;
638         }
639 
640         om = SLIST_NEXT(om, om_next);
641         om_off = 0;
642 
643         if (om == NULL) {
644             return INT_MAX;
645         }
646     }
647 }
648 
os_mbuf_cmpm(const struct os_mbuf * om1,uint16_t offset1,const struct os_mbuf * om2,uint16_t offset2,uint16_t len)649 int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
650                  const struct os_mbuf *om2, uint16_t offset2,
651                  uint16_t len)
652 {
653     const struct os_mbuf *cur1;
654     const struct os_mbuf *cur2;
655     uint16_t bytes_remaining;
656     uint16_t om1_off;
657     uint16_t om2_off;
658 
659     om1_off = 0;
660     om2_off = 0;
661     cur1 = os_mbuf_off(om1, offset1, &om1_off);
662     cur2 = os_mbuf_off(om2, offset2, &om2_off);
663     bytes_remaining = len;
664 
665     while (1) {
666         if (bytes_remaining == 0) {
667             return 0;
668         }
669 
670         while (cur1 != NULL && om1_off >= cur1->om_len) {
671             cur1 = SLIST_NEXT(cur1, om_next);
672             om1_off = 0;
673         }
674 
675         while (cur2 != NULL && om2_off >= cur2->om_len) {
676             cur2 = SLIST_NEXT(cur2, om_next);
677             om2_off = 0;
678         }
679 
680         if (cur1 == NULL || cur2 == NULL) {
681             return INT_MAX;
682         }
683 
684         uint16_t om1_left = cur1->om_len - om1_off;
685         uint16_t om2_left = cur2->om_len - om2_off;
686         uint16_t chunk_sz = min(min(om1_left, om2_left), bytes_remaining);
687         int rc = memcmp(cur1->om_data + om1_off, cur2->om_data + om2_off, chunk_sz);
688         if (rc != 0) {
689             return rc;
690         }
691 
692         om1_off += chunk_sz;
693         om2_off += chunk_sz;
694         bytes_remaining -= chunk_sz;
695     }
696 }
697 
os_mbuf_prepend(struct os_mbuf * om,int len)698 struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len)
699 {
700     struct os_mbuf *om_tmp = om;
701     int len_tmp = len;
702     struct os_mbuf *p;
703 
704     while (1) {
705         /* Fill the available space at the front of the head of the chain, as
706          * needed.
707          */
708         int leading = min(len_tmp, OS_MBUF_LEADINGSPACE(om_tmp));
709         om_tmp->om_data -= leading;
710         om_tmp->om_len += leading;
711 
712         if (OS_MBUF_IS_PKTHDR(om_tmp)) {
713             OS_MBUF_PKTHDR(om_tmp)->omp_len += leading;
714         }
715 
716         len_tmp -= leading;
717         if (len_tmp == 0) {
718             break;
719         }
720 
721         /* The current head didn't have enough space; allocate a new head. */
722         if (OS_MBUF_IS_PKTHDR(om_tmp)) {
723             p = os_mbuf_get_pkthdr(om_tmp->om_omp,
724                                    om_tmp->om_pkthdr_len - sizeof(struct os_mbuf_pkthdr));
725         } else {
726             p = os_mbuf_get(om_tmp->om_omp, 0);
727         }
728 
729         if (p == NULL) {
730             os_mbuf_free_chain(om_tmp);
731             om_tmp = NULL;
732             break;
733         }
734 
735         if (OS_MBUF_IS_PKTHDR(om_tmp)) {
736             _os_mbuf_copypkthdr(p, om_tmp);
737             om_tmp->om_pkthdr_len = 0;
738         }
739 
740         /* Move the new head's data pointer to the end so that data can be
741          * prepended.
742          */
743         p->om_data += OS_MBUF_TRAILINGSPACE(p);
744         SLIST_NEXT(p, om_next) = om_tmp;
745         om_tmp = p;
746     }
747 
748     return om_tmp;
749 }
750 
os_mbuf_prepend_pullup(struct os_mbuf * om,uint16_t len)751 struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len)
752 {
753     om = os_mbuf_prepend(om, len);
754     if (om == NULL) {
755         return NULL;
756     }
757 
758     om = os_mbuf_pullup(om, len);
759     if (om == NULL) {
760         return NULL;
761     }
762 
763     return om;
764 }
765 
os_mbuf_copyinto(struct os_mbuf * om,int off,const void * src,int len)766 int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len)
767 {
768     int len_tmp = len;
769     struct os_mbuf *next;
770     struct os_mbuf *cur;
771     const uint8_t *sptr;
772     uint16_t cur_off;
773     int rc;
774     /* Find the mbuf,offset pair for the start of the destination. */
775     cur = os_mbuf_off(om, off, &cur_off);
776     if (cur == NULL) {
777         return -1;
778     }
779 
780     /* Overwrite existing data until we reach the end of the chain. */
781     sptr = src;
782 
783     while (1) {
784         int copylen = min(cur->om_len - cur_off, len_tmp);
785         if (copylen > 0) {
786             memcpy_s(cur->om_data + cur_off, sizeof(cur->om_data + cur_off), sptr, copylen);
787             sptr += copylen;
788             len_tmp -= copylen;
789             copylen = 0;
790         }
791 
792         if (len_tmp == 0) {
793             /* All the source data fit in the existing mbuf chain. */
794             return 0;
795         }
796 
797         next = SLIST_NEXT(cur, om_next);
798         if (next == NULL) {
799             break;
800         }
801 
802         cur = next;
803         cur_off = 0;
804     }
805 
806     /* Append the remaining data to the end of the chain. */
807     rc = os_mbuf_append(cur, sptr, len_tmp);
808     if (rc != 0) {
809         return rc;
810     }
811 
812     /* Fix up the packet header, if one is present. */
813     if (OS_MBUF_IS_PKTHDR(om)) {
814         OS_MBUF_PKTHDR(om)->omp_len =
815                         max(OS_MBUF_PKTHDR(om)->omp_len, off + len_tmp);
816     }
817 
818     return 0;
819 }
820 
os_mbuf_concat(struct os_mbuf * first,struct os_mbuf * second)821 void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second)
822 {
823     struct os_mbuf *next;
824     struct os_mbuf *cur;
825     /* Point 'cur' to the last buffer in the first chain. */
826     cur = first;
827 
828     while (1) {
829         next = SLIST_NEXT(cur, om_next);
830         if (next == NULL) {
831             break;
832         }
833 
834         cur = next;
835     }
836 
837     /* Attach the second chain to the end of the first. */
838     SLIST_NEXT(cur, om_next) = second;
839 
840     /* If the first chain has a packet header, calculate the length of the
841      * second chain and add it to the header length.
842      */
843     if (OS_MBUF_IS_PKTHDR(first)) {
844         if (OS_MBUF_IS_PKTHDR(second)) {
845             OS_MBUF_PKTHDR(first)->omp_len += OS_MBUF_PKTHDR(second)->omp_len;
846         } else {
847             for (cur = second; cur != NULL; cur = SLIST_NEXT(cur, om_next)) {
848                 OS_MBUF_PKTHDR(first)->omp_len += cur->om_len;
849             }
850         }
851     }
852 
853     second->om_pkthdr_len = 0;
854 }
855 
os_mbuf_extend(struct os_mbuf * om,uint16_t len)856 void *os_mbuf_extend(struct os_mbuf *om, uint16_t len)
857 {
858     struct os_mbuf *newm;
859     struct os_mbuf *last;
860     void *data;
861 
862     if (len > om->om_omp->omp_databuf_len) {
863         return NULL;
864     }
865 
866     /* Scroll to last mbuf in the chain */
867     last = om;
868 
869     while (SLIST_NEXT(last, om_next) != NULL) {
870         last = SLIST_NEXT(last, om_next);
871     }
872 
873     if (OS_MBUF_TRAILINGSPACE(last) < len) {
874         newm = os_mbuf_get(om->om_omp, 0);
875         if (newm == NULL) {
876             return NULL;
877         }
878 
879         SLIST_NEXT(last, om_next) = newm;
880         last = newm;
881     }
882 
883     data = last->om_data + last->om_len;
884     last->om_len += len;
885 
886     if (OS_MBUF_IS_PKTHDR(om)) {
887         OS_MBUF_PKTHDR(om)->omp_len += len;
888     }
889 
890     return data;
891 }
892 
os_mbuf_pullup(struct os_mbuf * om,uint16_t len)893 struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len)
894 {
895     struct os_mbuf_pool *omp;
896     struct os_mbuf *next;
897     struct os_mbuf *om2;
898     int count;
899     int space;
900     omp = om->om_omp;
901 
902     /*
903      * If first mbuf has no cluster, and has room for len bytes
904      * without shifting current data, pullup into it,
905      * otherwise allocate a new mbuf to prepend to the chain.
906      */
907     if (om->om_len >= len) {
908         return (om);
909     }
910 
911     if (om->om_len + OS_MBUF_TRAILINGSPACE(om) >= len &&
912             SLIST_NEXT(om, om_next)) {
913         om2 = om;
914         om = SLIST_NEXT(om, om_next);
915         len -= om2->om_len;
916     } else {
917         if (len > omp->omp_databuf_len - om->om_pkthdr_len) {
918             goto bad;
919         }
920 
921         om2 = os_mbuf_get(omp, 0);
922         if (om2 == NULL) {
923             goto bad;
924         }
925 
926         if (OS_MBUF_IS_PKTHDR(om)) {
927             _os_mbuf_copypkthdr(om2, om);
928         }
929     }
930 
931     space = OS_MBUF_TRAILINGSPACE(om2);
932 
933     do {
934         count = min(min(len, space), om->om_len);
935         memcpy_s(om2->om_data + om2->om_len, sizeof(om2->om_data + om2->om_len), om->om_data, count);
936         len -= count;
937         om2->om_len += count;
938         om->om_len -= count;
939         space -= count;
940 
941         if (om->om_len) {
942             om->om_data += count;
943         } else {
944             next = SLIST_NEXT(om, om_next);
945             os_mbuf_free(om);
946             om = next;
947         }
948     } while (len > 0 && om);
949 
950     if (len > 0) {
951         os_mbuf_free(om2);
952         goto bad;
953     }
954 
955     SLIST_NEXT(om2, om_next) = om;
956     return (om2);
957 bad:
958     os_mbuf_free_chain(om);
959     return (NULL);
960 }
961 
os_mbuf_trim_front(struct os_mbuf * om)962 struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *om)
963 {
964     struct os_mbuf *next;
965     struct os_mbuf *cur;
966     struct os_mbuf *om_tmp = om;
967 
968     /* Abort early if there is nothing to trim. */
969     if (om_tmp->om_len != 0) {
970         return om_tmp;
971     }
972 
973     /* Starting with the second mbuf in the chain, continue removing and
974      * freeing mbufs until an non-empty one is encountered.
975      */
976     cur = SLIST_NEXT(om_tmp, om_next);
977     while (cur != NULL && cur->om_len == 0) {
978         next = SLIST_NEXT(cur, om_next);
979         SLIST_NEXT(om_tmp, om_next) = next;
980         os_mbuf_free(cur);
981         cur = next;
982     }
983 
984     if (cur == NULL) {
985         /* All buffers after the first have been freed. */
986         return om_tmp;
987     }
988 
989     /* Try to remove the first mbuf in the chain.  If this buffer contains a
990      * packet header, make sure the second buffer can accommodate it.
991      */
992     if (OS_MBUF_LEADINGSPACE(cur) >= om_tmp->om_pkthdr_len) {
993         /* Second buffer has room; copy packet header. */
994         cur->om_pkthdr_len = om_tmp->om_pkthdr_len;
995         memcpy_s(OS_MBUF_PKTHDR(cur), sizeof(OS_MBUF_PKTHDR(cur)), OS_MBUF_PKTHDR(om_tmp), om_tmp->om_pkthdr_len);
996         /* Free first buffer. */
997         os_mbuf_free(om_tmp);
998         om_tmp = cur;
999     }
1000 
1001     return om_tmp;
1002 }
1003 
os_mbuf_pack_chains(struct os_mbuf * m1,struct os_mbuf * m2)1004 struct os_mbuf *os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2)
1005 {
1006     uint16_t copylen;
1007     uint8_t *dptr;
1008     struct os_mbuf *cur;
1009     struct os_mbuf *next;
1010 
1011     /* If m1 is NULL, return NULL */
1012     if (m1 == NULL) {
1013         return NULL;
1014     }
1015 
1016     /*
1017      * Concatenate the two chains to start. This will discard packet header in
1018      * m2 and adjust packet length in m1 if m1 has a packet header.
1019      */
1020     if (m2 != NULL) {
1021         os_mbuf_concat(m1, m2);
1022     }
1023 
1024     cur = m1;
1025 
1026     while (1) {
1027         /* If there is leading space in the mbuf, move data up */
1028         if (OS_MBUF_LEADINGSPACE(cur)) {
1029             dptr = &cur->om_databuf[0];
1030 
1031             if (OS_MBUF_IS_PKTHDR(cur)) {
1032                 dptr += cur->om_pkthdr_len;
1033             }
1034 
1035             memmove_s(dptr, sizeof(*dptr), cur->om_data, cur->om_len);
1036             cur->om_data = dptr;
1037         }
1038 
1039         /* Set pointer to where we will begin copying data in current mbuf */
1040         dptr = cur->om_data + cur->om_len;
1041         /* Get a pointer to the next buf we want to absorb */
1042         next = SLIST_NEXT(cur, om_next);
1043         /*
1044          * Is there trailing space in the mbuf? If so, copy data from
1045          * following mbufs into the current mbuf
1046          */
1047         uint16_t rem_len = OS_MBUF_TRAILINGSPACE(cur);
1048 
1049         while (rem_len && next) {
1050             copylen = min(rem_len, next->om_len);
1051             memcpy_s(dptr, sizeof(*dptr), next->om_data, copylen);
1052             cur->om_len += copylen;
1053             dptr += copylen;
1054             rem_len -= copylen;
1055             /*
1056              * We copied bytes from the next mbuf. Move the data pointer
1057              * and subtract from its length
1058              */
1059             next->om_data += copylen;
1060             next->om_len -= copylen;
1061 
1062             /*
1063              * Keep removing and freeing consecutive zero length mbufs,
1064              * stopping when we find one with data in it or we have
1065              * reached the end. This will prevent any zero length mbufs
1066              * from remaining in the chain.
1067              */
1068             while (next->om_len == 0) {
1069                 SLIST_NEXT(cur, om_next) = SLIST_NEXT(next, om_next);
1070                 os_mbuf_free(next);
1071                 next = SLIST_NEXT(cur, om_next);
1072                 if (next == NULL) {
1073                     break;
1074                 }
1075             }
1076         }
1077 
1078         /* If no mbufs are left, we are done */
1079         if (next == NULL) {
1080             break;
1081         }
1082 
1083         /* Move cur to next as we filled up current */
1084         cur = next;
1085     }
1086 
1087     return m1;
1088 }