1/*	$OpenBSD: uipc_mbuf.c,v 1.283 2022/02/22 01:15:01 guenther Exp $	*/
2/*	$NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1982, 1986, 1988, 1991, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
33 */
34
35/*
36 *	@(#)COPYRIGHT	1.1 (NRL) 17 January 1995
37 *
38 * NRL grants permission for redistribution and use in source and binary
39 * forms, with or without modification, of the software and documentation
40 * created at NRL provided that the following conditions are met:
41 *
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 *    must display the following acknowledgements:
49 *	This product includes software developed by the University of
50 *	California, Berkeley and its contributors.
51 *	This product includes software developed at the Information
52 *	Technology Division, US Naval Research Laboratory.
53 * 4. Neither the name of the NRL nor the names of its contributors
54 *    may be used to endorse or promote products derived from this software
55 *    without specific prior written permission.
56 *
57 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
58 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
60 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
61 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
62 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
63 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
64 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
65 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
66 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
67 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68 *
69 * The views and conclusions contained in the software and documentation
70 * are those of the authors and should not be interpreted as representing
71 * official policies, either expressed or implied, of the US Naval
72 * Research Laboratory (NRL).
73 */
74
75struct mbuf_list {
76	struct mbuf		*ml_head;
77	struct mbuf		*ml_tail;
78	u_int			ml_len;
79};
80
81struct mbuf_queue {
82	struct mutex		mq_mtx;
83	struct mbuf_list	mq_list;
84	u_int			mq_maxlen;
85	u_int			mq_drops;
86};
87
88
89static struct mbuf *
90m_dup_pkt(struct mbuf *m0, unsigned int adj, int wait)
91{
92	struct mbuf *m;
93	int len;
94
95	KASSERT(m0->m_flags & M_PKTHDR);
96
97	len = m0->m_pkthdr.len + adj;
98	if (len > MAXMCLBYTES) /* XXX */
99		return (NULL);
100
101	m = m_get(wait, m0->m_type);
102	if (m == NULL)
103		return (NULL);
104
105	if (m_dup_pkthdr(m, m0, wait) != 0)
106		goto fail;
107
108	if (len > MHLEN) {
109		MCLGETL(m, wait, len);
110		if (!ISSET(m->m_flags, M_EXT))
111			goto fail;
112	}
113
114	m->m_len = m->m_pkthdr.len = len;
115	m_adj(m, adj);
116	m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
117
118	return (m);
119
120fail:
121	m_freem(m);
122	return (NULL);
123}
124
125
126/*
127 * Compute the amount of space available after the end of data in an mbuf.
128 * Read-only clusters never have space available.
129 */
130static int
131m_trailingspace(struct mbuf *m)
132{
133	if (M_READONLY(m))
134		return 0;
135	KASSERT(M_DATABUF(m) + M_SIZE(m) >= (m->m_data + m->m_len));
136	return M_DATABUF(m) + M_SIZE(m) - (m->m_data + m->m_len);
137}
138
139
140/*
141 * mbuf lists
142 */
143
144#define MBUF_LIST_INITIALIZER() { NULL, NULL, 0 }
145
146#define	ml_len(_ml)		((_ml)->ml_len)
147#define	ml_empty(_ml)		((_ml)->ml_len == 0)
148
149#define MBUF_LIST_FIRST(_ml)	((_ml)->ml_head)
150#define MBUF_LIST_NEXT(_m)	((_m)->m_nextpkt)
151
152#define MBUF_LIST_FOREACH(_ml, _m)					\
153	for ((_m) = MBUF_LIST_FIRST(_ml);				\
154		(_m) != NULL;						\
155		(_m) = MBUF_LIST_NEXT(_m))
156
157static void
158ml_init(struct mbuf_list *ml)
159{
160	ml->ml_head = ml->ml_tail = NULL;
161	ml->ml_len = 0;
162}
163
164static void
165ml_enqueue(struct mbuf_list *ml, struct mbuf *m)
166{
167	if (ml->ml_tail == NULL)
168		ml->ml_head = ml->ml_tail = m;
169	else {
170		ml->ml_tail->m_nextpkt = m;
171		ml->ml_tail = m;
172	}
173
174	m->m_nextpkt = NULL;
175	ml->ml_len++;
176}
177
178static void
179ml_enlist(struct mbuf_list *mla, struct mbuf_list *mlb)
180{
181	if (!ml_empty(mlb)) {
182		if (ml_empty(mla))
183			mla->ml_head = mlb->ml_head;
184		else
185			mla->ml_tail->m_nextpkt = mlb->ml_head;
186		mla->ml_tail = mlb->ml_tail;
187		mla->ml_len += mlb->ml_len;
188
189		ml_init(mlb);
190	}
191}
192
193static struct mbuf *
194ml_dequeue(struct mbuf_list *ml)
195{
196	struct mbuf *m;
197
198	m = ml->ml_head;
199	if (m != NULL) {
200		ml->ml_head = m->m_nextpkt;
201		if (ml->ml_head == NULL)
202			ml->ml_tail = NULL;
203
204		m->m_nextpkt = NULL;
205		ml->ml_len--;
206	}
207
208	return (m);
209}
210
211static struct mbuf *
212ml_dechain(struct mbuf_list *ml)
213{
214	struct mbuf *m0;
215
216	m0 = ml->ml_head;
217
218	ml_init(ml);
219
220	return (m0);
221}
222
223static unsigned int
224ml_purge(struct mbuf_list *ml)
225{
226	struct mbuf *m, *n;
227	unsigned int len;
228
229	for (m = ml->ml_head; m != NULL; m = n) {
230		n = m->m_nextpkt;
231		m_freem(m);
232	}
233
234	len = ml->ml_len;
235	ml_init(ml);
236
237	return (len);
238}
239
240static unsigned int
241ml_hdatalen(struct mbuf_list *ml)
242{
243	struct mbuf *m;
244
245	m = ml->ml_head;
246	if (m == NULL)
247		return (0);
248
249	KASSERT(ISSET(m->m_flags, M_PKTHDR));
250	return (m->m_pkthdr.len);
251}
252
253
254/*
255 * mbuf queues
256 */
257
258#define MBUF_QUEUE_INITIALIZER(_maxlen, _ipl) \
259	{ MUTEX_INITIALIZER(_ipl), MBUF_LIST_INITIALIZER(), (_maxlen), 0 }
260
261#define	mq_len(_mq)		ml_len(&(_mq)->mq_list)
262#define	mq_empty(_mq)		ml_empty(&(_mq)->mq_list)
263#define	mq_full(_mq)		(mq_len((_mq)) >= (_mq)->mq_maxlen)
264#define	mq_drops(_mq)		((_mq)->mq_drops)
265#define	mq_set_maxlen(_mq, _l)	((_mq)->mq_maxlen = (_l))
266
267static void
268mq_init(struct mbuf_queue *mq, u_int maxlen, int ipl)
269{
270	mtx_init(&mq->mq_mtx, ipl);
271	ml_init(&mq->mq_list);
272	mq->mq_maxlen = maxlen;
273}
274
275static int
276mq_push(struct mbuf_queue *mq, struct mbuf *m)
277{
278	struct mbuf *dropped = NULL;
279
280	mtx_enter(&mq->mq_mtx);
281	if (mq_len(mq) >= mq->mq_maxlen) {
282		mq->mq_drops++;
283		dropped = ml_dequeue(&mq->mq_list);
284	}
285	ml_enqueue(&mq->mq_list, m);
286	mtx_leave(&mq->mq_mtx);
287
288	if (dropped)
289		m_freem(dropped);
290
291	return (dropped != NULL);
292}
293
294static int
295mq_enqueue(struct mbuf_queue *mq, struct mbuf *m)
296{
297	int dropped = 0;
298
299	mtx_enter(&mq->mq_mtx);
300	if (mq_len(mq) < mq->mq_maxlen)
301		ml_enqueue(&mq->mq_list, m);
302	else {
303		mq->mq_drops++;
304		dropped = 1;
305	}
306	mtx_leave(&mq->mq_mtx);
307
308	if (dropped)
309		m_freem(m);
310
311	return (dropped);
312}
313
314static struct mbuf *
315mq_dequeue(struct mbuf_queue *mq)
316{
317	struct mbuf *m;
318
319	mtx_enter(&mq->mq_mtx);
320	m = ml_dequeue(&mq->mq_list);
321	mtx_leave(&mq->mq_mtx);
322
323	return (m);
324}
325
326static int
327mq_enlist(struct mbuf_queue *mq, struct mbuf_list *ml)
328{
329	struct mbuf *m;
330	int dropped = 0;
331
332	mtx_enter(&mq->mq_mtx);
333	if (mq_len(mq) < mq->mq_maxlen)
334		ml_enlist(&mq->mq_list, ml);
335	else {
336		dropped = ml_len(ml);
337		mq->mq_drops += dropped;
338	}
339	mtx_leave(&mq->mq_mtx);
340
341	if (dropped) {
342		while ((m = ml_dequeue(ml)) != NULL)
343			m_freem(m);
344	}
345
346	return (dropped);
347}
348
349static void
350mq_delist(struct mbuf_queue *mq, struct mbuf_list *ml)
351{
352	mtx_enter(&mq->mq_mtx);
353	*ml = mq->mq_list;
354	ml_init(&mq->mq_list);
355	mtx_leave(&mq->mq_mtx);
356}
357
358static struct mbuf *
359mq_dechain(struct mbuf_queue *mq)
360{
361	struct mbuf *m0;
362
363	mtx_enter(&mq->mq_mtx);
364	m0 = ml_dechain(&mq->mq_list);
365	mtx_leave(&mq->mq_mtx);
366
367	return (m0);
368}
369
370static unsigned int
371mq_purge(struct mbuf_queue *mq)
372{
373	struct mbuf_list ml;
374
375	mq_delist(mq, &ml);
376
377	return (ml_purge(&ml));
378}
379
380static unsigned int
381mq_hdatalen(struct mbuf_queue *mq)
382{
383	unsigned int hdatalen;
384
385	mtx_enter(&mq->mq_mtx);
386	hdatalen = ml_hdatalen(&mq->mq_list);
387	mtx_leave(&mq->mq_mtx);
388
389	return (hdatalen);
390}
391