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