1 1.30 maxv /* $NetBSD: ipsec_mbuf.c,v 1.30 2018/12/22 13:11:38 maxv Exp $ */ 2 1.20 maxv 3 1.20 maxv /* 4 1.4 thorpej * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 5 1.4 thorpej * All rights reserved. 6 1.4 thorpej * 7 1.4 thorpej * Redistribution and use in source and binary forms, with or without 8 1.4 thorpej * modification, are permitted provided that the following conditions 9 1.4 thorpej * are met: 10 1.4 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.4 thorpej * notice, this list of conditions and the following disclaimer. 12 1.4 thorpej * 2. Redistributions in binary form must reproduce the above copyright 13 1.4 thorpej * notice, this list of conditions and the following disclaimer in the 14 1.4 thorpej * documentation and/or other materials provided with the distribution. 15 1.4 thorpej * 16 1.4 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.4 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.4 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.4 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.4 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.4 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.4 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.4 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.4 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.4 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.4 thorpej * SUCH DAMAGE. 27 1.4 thorpej * 28 1.26 maxv * $FreeBSD: sys/netipsec/ipsec_mbuf.c,v 1.5.2.2 2003/03/28 20:32:53 sam Exp $ 29 1.4 thorpej */ 30 1.1 jonathan 31 1.1 jonathan #include <sys/cdefs.h> 32 1.30 maxv __KERNEL_RCSID(0, "$NetBSD: ipsec_mbuf.c,v 1.30 2018/12/22 13:11:38 maxv Exp $"); 33 1.1 jonathan 34 1.1 jonathan /* 35 1.1 jonathan * IPsec-specific mbuf routines. 36 1.1 jonathan */ 37 1.1 jonathan 38 1.1 jonathan #include <sys/param.h> 39 1.1 jonathan #include <sys/systm.h> 40 1.1 jonathan #include <sys/mbuf.h> 41 1.1 jonathan 42 1.1 jonathan #include <netipsec/ipsec.h> 43 1.5 jonathan #include <netipsec/ipsec_var.h> 44 1.11 thorpej #include <netipsec/ipsec_private.h> 45 1.1 jonathan 46 1.1 jonathan /* 47 1.1 jonathan * Create a writable copy of the mbuf chain. While doing this 48 1.1 jonathan * we compact the chain with a goal of producing a chain with 49 1.1 jonathan * at most two mbufs. The second mbuf in this chain is likely 50 1.1 jonathan * to be a cluster. The primary purpose of this work is to create 51 1.1 jonathan * a writable packet for encryption, compression, etc. The 52 1.1 jonathan * secondary goal is to linearize the data so the data can be 53 1.1 jonathan * passed to crypto hardware in the most efficient manner possible. 54 1.1 jonathan */ 55 1.1 jonathan struct mbuf * 56 1.1 jonathan m_clone(struct mbuf *m0) 57 1.1 jonathan { 58 1.1 jonathan struct mbuf *m, *mprev; 59 1.1 jonathan struct mbuf *n, *mfirst, *mlast; 60 1.1 jonathan int len, off; 61 1.1 jonathan 62 1.14 ozaki KASSERT(m0 != NULL); 63 1.1 jonathan 64 1.1 jonathan mprev = NULL; 65 1.1 jonathan for (m = m0; m != NULL; m = mprev->m_next) { 66 1.1 jonathan /* 67 1.1 jonathan * Regular mbufs are ignored unless there's a cluster 68 1.28 maxv * in front of it that we can use to coalesce. 69 1.1 jonathan */ 70 1.1 jonathan if ((m->m_flags & M_EXT) == 0) { 71 1.1 jonathan if (mprev && (mprev->m_flags & M_EXT) && 72 1.1 jonathan m->m_len <= M_TRAILINGSPACE(mprev)) { 73 1.9 degroote memcpy(mtod(mprev, char *) + mprev->m_len, 74 1.28 maxv mtod(m, char *), m->m_len); 75 1.1 jonathan mprev->m_len += m->m_len; 76 1.28 maxv mprev->m_next = m_free(m); 77 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_MBCOALESCED); 78 1.1 jonathan } else { 79 1.1 jonathan mprev = m; 80 1.1 jonathan } 81 1.1 jonathan continue; 82 1.1 jonathan } 83 1.25 maxv 84 1.1 jonathan /* 85 1.28 maxv * Writable mbufs are left alone. 86 1.1 jonathan */ 87 1.27 maxv if (!M_READONLY(m)) { 88 1.1 jonathan mprev = m; 89 1.1 jonathan continue; 90 1.1 jonathan } 91 1.1 jonathan 92 1.1 jonathan /* 93 1.1 jonathan * Not writable, replace with a copy or coalesce with 94 1.1 jonathan * the previous mbuf if possible (since we have to copy 95 1.1 jonathan * it anyway, we try to reduce the number of mbufs and 96 1.1 jonathan * clusters so that future work is easier). 97 1.1 jonathan */ 98 1.28 maxv 99 1.28 maxv /* We only coalesce into a cluster. */ 100 1.1 jonathan if (mprev != NULL && (mprev->m_flags & M_EXT) && 101 1.1 jonathan m->m_len <= M_TRAILINGSPACE(mprev)) { 102 1.9 degroote memcpy(mtod(mprev, char *) + mprev->m_len, 103 1.28 maxv mtod(m, char *), m->m_len); 104 1.1 jonathan mprev->m_len += m->m_len; 105 1.28 maxv mprev->m_next = m_free(m); 106 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_CLCOALESCED); 107 1.1 jonathan continue; 108 1.1 jonathan } 109 1.1 jonathan 110 1.1 jonathan /* 111 1.1 jonathan * Allocate new space to hold the copy... 112 1.1 jonathan */ 113 1.1 jonathan if (mprev == NULL && (m->m_flags & M_PKTHDR)) { 114 1.1 jonathan MGETHDR(n, M_DONTWAIT, m->m_type); 115 1.1 jonathan if (n == NULL) { 116 1.1 jonathan m_freem(m0); 117 1.25 maxv return NULL; 118 1.1 jonathan } 119 1.30 maxv m_move_pkthdr(n, m); 120 1.1 jonathan MCLGET(n, M_DONTWAIT); 121 1.1 jonathan if ((n->m_flags & M_EXT) == 0) { 122 1.1 jonathan m_free(n); 123 1.1 jonathan m_freem(m0); 124 1.25 maxv return NULL; 125 1.1 jonathan } 126 1.1 jonathan } else { 127 1.1 jonathan n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags); 128 1.1 jonathan if (n == NULL) { 129 1.1 jonathan m_freem(m0); 130 1.25 maxv return NULL; 131 1.1 jonathan } 132 1.1 jonathan } 133 1.25 maxv 134 1.1 jonathan /* 135 1.1 jonathan * ... and copy the data. We deal with jumbo mbufs 136 1.1 jonathan * (i.e. m_len > MCLBYTES) by splitting them into 137 1.1 jonathan * clusters. We could just malloc a buffer and make 138 1.1 jonathan * it external but too many device drivers don't know 139 1.1 jonathan * how to break up the non-contiguous memory when 140 1.1 jonathan * doing DMA. 141 1.1 jonathan */ 142 1.1 jonathan len = m->m_len; 143 1.1 jonathan off = 0; 144 1.1 jonathan mfirst = n; 145 1.1 jonathan mlast = NULL; 146 1.1 jonathan for (;;) { 147 1.29 riastrad const int cc = uimin(len, MCLBYTES); 148 1.9 degroote memcpy(mtod(n, char *), mtod(m, char *) + off, cc); 149 1.1 jonathan n->m_len = cc; 150 1.1 jonathan if (mlast != NULL) 151 1.1 jonathan mlast->m_next = n; 152 1.6 perry mlast = n; 153 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_CLCOPIED); 154 1.1 jonathan 155 1.1 jonathan len -= cc; 156 1.1 jonathan if (len <= 0) 157 1.1 jonathan break; 158 1.1 jonathan off += cc; 159 1.1 jonathan 160 1.1 jonathan n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags); 161 1.1 jonathan if (n == NULL) { 162 1.1 jonathan m_freem(mfirst); 163 1.1 jonathan m_freem(m0); 164 1.25 maxv return NULL; 165 1.1 jonathan } 166 1.1 jonathan } 167 1.6 perry n->m_next = m->m_next; 168 1.1 jonathan if (mprev == NULL) 169 1.1 jonathan m0 = mfirst; /* new head of chain */ 170 1.1 jonathan else 171 1.1 jonathan mprev->m_next = mfirst; /* replace old mbuf */ 172 1.1 jonathan m_free(m); /* release old mbuf */ 173 1.1 jonathan mprev = mfirst; 174 1.1 jonathan } 175 1.25 maxv 176 1.25 maxv return m0; 177 1.1 jonathan } 178 1.1 jonathan 179 1.1 jonathan /* 180 1.1 jonathan * Make space for a new header of length hlen at skip bytes 181 1.1 jonathan * into the packet. When doing this we allocate new mbufs only 182 1.1 jonathan * when absolutely necessary. The mbuf where the new header 183 1.1 jonathan * is to go is returned together with an offset into the mbuf. 184 1.1 jonathan * If NULL is returned then the mbuf chain may have been modified; 185 1.1 jonathan * the caller is assumed to always free the chain. 186 1.1 jonathan */ 187 1.1 jonathan struct mbuf * 188 1.1 jonathan m_makespace(struct mbuf *m0, int skip, int hlen, int *off) 189 1.1 jonathan { 190 1.1 jonathan struct mbuf *m; 191 1.1 jonathan unsigned remain; 192 1.1 jonathan 193 1.14 ozaki KASSERT(m0 != NULL); 194 1.22 maxv KASSERT(m0->m_flags & M_PKTHDR); 195 1.14 ozaki KASSERTMSG(hlen < MHLEN, "hlen too big: %u", hlen); 196 1.1 jonathan 197 1.1 jonathan for (m = m0; m && skip > m->m_len; m = m->m_next) 198 1.1 jonathan skip -= m->m_len; 199 1.1 jonathan if (m == NULL) 200 1.25 maxv return NULL; 201 1.25 maxv 202 1.1 jonathan /* 203 1.1 jonathan * At this point skip is the offset into the mbuf m 204 1.1 jonathan * where the new header should be placed. Figure out 205 1.1 jonathan * if there's space to insert the new header. If so, 206 1.20 maxv * and copying the remainder makes sense then do so. 207 1.1 jonathan * Otherwise insert a new mbuf in the chain, splitting 208 1.1 jonathan * the contents of m as needed. 209 1.1 jonathan */ 210 1.1 jonathan remain = m->m_len - skip; /* data to move */ 211 1.1 jonathan if (hlen > M_TRAILINGSPACE(m)) { 212 1.10 seanb struct mbuf *n0, *n, **np; 213 1.10 seanb int todo, len, done, alloc; 214 1.10 seanb 215 1.10 seanb n0 = NULL; 216 1.10 seanb np = &n0; 217 1.10 seanb alloc = 0; 218 1.10 seanb done = 0; 219 1.10 seanb todo = remain; 220 1.10 seanb while (todo > 0) { 221 1.10 seanb if (todo > MHLEN) { 222 1.10 seanb n = m_getcl(M_DONTWAIT, m->m_type, 0); 223 1.10 seanb len = MCLBYTES; 224 1.20 maxv } else { 225 1.10 seanb n = m_get(M_DONTWAIT, m->m_type); 226 1.10 seanb len = MHLEN; 227 1.10 seanb } 228 1.10 seanb if (n == NULL) { 229 1.10 seanb m_freem(n0); 230 1.10 seanb return NULL; 231 1.10 seanb } 232 1.10 seanb *np = n; 233 1.10 seanb np = &n->m_next; 234 1.10 seanb alloc++; 235 1.29 riastrad len = uimin(todo, len); 236 1.10 seanb memcpy(n->m_data, mtod(m, char *) + skip + done, len); 237 1.10 seanb n->m_len = len; 238 1.10 seanb done += len; 239 1.10 seanb todo -= len; 240 1.10 seanb } 241 1.1 jonathan 242 1.1 jonathan if (hlen <= M_TRAILINGSPACE(m) + remain) { 243 1.1 jonathan m->m_len = skip + hlen; 244 1.1 jonathan *off = skip; 245 1.10 seanb if (n0 != NULL) { 246 1.10 seanb *np = m->m_next; 247 1.10 seanb m->m_next = n0; 248 1.10 seanb } 249 1.20 maxv } else { 250 1.10 seanb n = m_get(M_DONTWAIT, m->m_type); 251 1.10 seanb if (n == NULL) { 252 1.10 seanb m_freem(n0); 253 1.10 seanb return NULL; 254 1.1 jonathan } 255 1.10 seanb alloc++; 256 1.10 seanb 257 1.10 seanb if ((n->m_next = n0) == NULL) 258 1.10 seanb np = &n->m_next; 259 1.10 seanb n0 = n; 260 1.10 seanb 261 1.10 seanb *np = m->m_next; 262 1.10 seanb m->m_next = n0; 263 1.10 seanb 264 1.10 seanb n->m_len = hlen; 265 1.10 seanb m->m_len = skip; 266 1.10 seanb 267 1.1 jonathan m = n; /* header is at front ... */ 268 1.1 jonathan *off = 0; /* ... of new mbuf */ 269 1.1 jonathan } 270 1.10 seanb 271 1.11 thorpej IPSEC_STATADD(IPSEC_STAT_MBINSERTED, alloc); 272 1.1 jonathan } else { 273 1.1 jonathan /* 274 1.1 jonathan * Copy the remainder to the back of the mbuf 275 1.1 jonathan * so there's space to write the new header. 276 1.1 jonathan */ 277 1.1 jonathan /* XXX can this be memcpy? does it handle overlap? */ 278 1.17 maxv memmove(mtod(m, char *) + skip + hlen, 279 1.17 maxv mtod(m, char *) + skip, remain); 280 1.1 jonathan m->m_len += hlen; 281 1.1 jonathan *off = skip; 282 1.1 jonathan } 283 1.25 maxv 284 1.1 jonathan m0->m_pkthdr.len += hlen; /* adjust packet length */ 285 1.1 jonathan return m; 286 1.1 jonathan } 287 1.1 jonathan 288 1.1 jonathan /* 289 1.1 jonathan * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header 290 1.1 jonathan * length is updated, and a pointer to the first byte of the padding 291 1.1 jonathan * (which is guaranteed to be all in one mbuf) is returned. 292 1.1 jonathan */ 293 1.8 christos void * 294 1.1 jonathan m_pad(struct mbuf *m, int n) 295 1.1 jonathan { 296 1.1 jonathan register struct mbuf *m0, *m1; 297 1.1 jonathan register int len, pad; 298 1.8 christos void *retval; 299 1.1 jonathan 300 1.21 maxv if (__predict_false(n > MLEN)) { 301 1.21 maxv panic("%s: %d > MLEN", __func__, n); 302 1.1 jonathan } 303 1.22 maxv KASSERT(m->m_flags & M_PKTHDR); 304 1.1 jonathan 305 1.1 jonathan len = m->m_pkthdr.len; 306 1.1 jonathan pad = n; 307 1.1 jonathan m0 = m; 308 1.1 jonathan 309 1.1 jonathan while (m0->m_len < len) { 310 1.14 ozaki KASSERTMSG(m0->m_next != NULL, 311 1.21 maxv "m0 null, len %u m_len %u", len, m0->m_len); 312 1.1 jonathan len -= m0->m_len; 313 1.1 jonathan m0 = m0->m_next; 314 1.1 jonathan } 315 1.1 jonathan 316 1.1 jonathan if (m0->m_len != len) { 317 1.16 ozaki IPSECLOG(LOG_DEBUG, 318 1.16 ozaki "length mismatch (should be %d instead of %d)\n", 319 1.16 ozaki m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len); 320 1.1 jonathan m_freem(m); 321 1.1 jonathan return NULL; 322 1.1 jonathan } 323 1.1 jonathan 324 1.1 jonathan /* Check for zero-length trailing mbufs, and find the last one. */ 325 1.1 jonathan for (m1 = m0; m1->m_next; m1 = m1->m_next) { 326 1.1 jonathan if (m1->m_next->m_len != 0) { 327 1.16 ozaki IPSECLOG(LOG_DEBUG, 328 1.16 ozaki "length mismatch (should be %d instead of %d)\n", 329 1.1 jonathan m->m_pkthdr.len, 330 1.16 ozaki m->m_pkthdr.len + m1->m_next->m_len); 331 1.1 jonathan m_freem(m); 332 1.1 jonathan return NULL; 333 1.1 jonathan } 334 1.1 jonathan 335 1.1 jonathan m0 = m1->m_next; 336 1.1 jonathan } 337 1.1 jonathan 338 1.1 jonathan if (pad > M_TRAILINGSPACE(m0)) { 339 1.1 jonathan /* Add an mbuf to the chain. */ 340 1.1 jonathan MGET(m1, M_DONTWAIT, MT_DATA); 341 1.21 maxv if (m1 == NULL) { 342 1.21 maxv m_freem(m); 343 1.16 ozaki IPSECLOG(LOG_DEBUG, "unable to get extra mbuf\n"); 344 1.1 jonathan return NULL; 345 1.1 jonathan } 346 1.1 jonathan 347 1.1 jonathan m0->m_next = m1; 348 1.1 jonathan m0 = m1; 349 1.1 jonathan m0->m_len = 0; 350 1.1 jonathan } 351 1.1 jonathan 352 1.1 jonathan retval = m0->m_data + m0->m_len; 353 1.1 jonathan m0->m_len += pad; 354 1.1 jonathan m->m_pkthdr.len += pad; 355 1.1 jonathan 356 1.1 jonathan return retval; 357 1.1 jonathan } 358 1.1 jonathan 359 1.1 jonathan /* 360 1.1 jonathan * Remove hlen data at offset skip in the packet. This is used by 361 1.1 jonathan * the protocols strip protocol headers and associated data (e.g. IV, 362 1.1 jonathan * authenticator) on input. 363 1.1 jonathan */ 364 1.1 jonathan int 365 1.1 jonathan m_striphdr(struct mbuf *m, int skip, int hlen) 366 1.1 jonathan { 367 1.1 jonathan struct mbuf *m1; 368 1.1 jonathan int roff; 369 1.1 jonathan 370 1.22 maxv KASSERT(m->m_flags & M_PKTHDR); 371 1.22 maxv 372 1.1 jonathan /* Find beginning of header */ 373 1.1 jonathan m1 = m_getptr(m, skip, &roff); 374 1.1 jonathan if (m1 == NULL) 375 1.25 maxv return EINVAL; 376 1.1 jonathan 377 1.1 jonathan /* Remove the header and associated data from the mbuf. */ 378 1.1 jonathan if (roff == 0) { 379 1.1 jonathan /* The header was at the beginning of the mbuf */ 380 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_INPUT_FRONT); 381 1.1 jonathan m_adj(m1, hlen); 382 1.23 maxv if (m1 != m) 383 1.1 jonathan m->m_pkthdr.len -= hlen; 384 1.1 jonathan } else if (roff + hlen >= m1->m_len) { 385 1.1 jonathan struct mbuf *mo; 386 1.24 maxv int adjlen; 387 1.1 jonathan 388 1.1 jonathan /* 389 1.1 jonathan * Part or all of the header is at the end of this mbuf, 390 1.1 jonathan * so first let's remove the remainder of the header from 391 1.1 jonathan * the beginning of the remainder of the mbuf chain, if any. 392 1.1 jonathan */ 393 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_INPUT_END); 394 1.1 jonathan if (roff + hlen > m1->m_len) { 395 1.24 maxv adjlen = roff + hlen - m1->m_len; 396 1.24 maxv 397 1.1 jonathan /* Adjust the next mbuf by the remainder */ 398 1.24 maxv m_adj(m1->m_next, adjlen); 399 1.1 jonathan 400 1.1 jonathan /* The second mbuf is guaranteed not to have a pkthdr... */ 401 1.24 maxv m->m_pkthdr.len -= adjlen; 402 1.1 jonathan } 403 1.1 jonathan 404 1.1 jonathan /* Now, let's unlink the mbuf chain for a second...*/ 405 1.1 jonathan mo = m1->m_next; 406 1.1 jonathan m1->m_next = NULL; 407 1.1 jonathan 408 1.1 jonathan /* ...and trim the end of the first part of the chain...sick */ 409 1.24 maxv adjlen = m1->m_len - roff; 410 1.24 maxv m_adj(m1, -adjlen); 411 1.23 maxv if (m1 != m) 412 1.24 maxv m->m_pkthdr.len -= adjlen; 413 1.1 jonathan 414 1.1 jonathan /* Finally, let's relink */ 415 1.1 jonathan m1->m_next = mo; 416 1.1 jonathan } else { 417 1.1 jonathan /* 418 1.1 jonathan * The header lies in the "middle" of the mbuf; copy 419 1.1 jonathan * the remainder of the mbuf down over the header. 420 1.1 jonathan */ 421 1.11 thorpej IPSEC_STATINC(IPSEC_STAT_INPUT_MIDDLE); 422 1.17 maxv memmove(mtod(m1, u_char *) + roff, 423 1.17 maxv mtod(m1, u_char *) + roff + hlen, 424 1.1 jonathan m1->m_len - (roff + hlen)); 425 1.1 jonathan m1->m_len -= hlen; 426 1.1 jonathan m->m_pkthdr.len -= hlen; 427 1.1 jonathan } 428 1.25 maxv 429 1.25 maxv return 0; 430 1.1 jonathan } 431