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