1aaea26efSSam Leffler /*- 2aaea26efSSam Leffler * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3aaea26efSSam Leffler * All rights reserved. 4aaea26efSSam Leffler * 5aaea26efSSam Leffler * Redistribution and use in source and binary forms, with or without 6aaea26efSSam Leffler * modification, are permitted provided that the following conditions 7aaea26efSSam Leffler * are met: 8aaea26efSSam Leffler * 1. Redistributions of source code must retain the above copyright 9aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer. 10aaea26efSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 11aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer in the 12aaea26efSSam Leffler * documentation and/or other materials provided with the distribution. 13aaea26efSSam Leffler * 14aaea26efSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15aaea26efSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16aaea26efSSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17aaea26efSSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18aaea26efSSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19aaea26efSSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20aaea26efSSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21aaea26efSSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22aaea26efSSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23aaea26efSSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24aaea26efSSam Leffler * SUCH DAMAGE. 25aaea26efSSam Leffler * 26aaea26efSSam Leffler * $FreeBSD$ 27aaea26efSSam Leffler */ 2888768458SSam Leffler 2988768458SSam Leffler /* 3088768458SSam Leffler * IPsec-specific mbuf routines. 3188768458SSam Leffler */ 3288768458SSam Leffler 3388768458SSam Leffler #include "opt_param.h" 3488768458SSam Leffler 3588768458SSam Leffler #include <sys/param.h> 3688768458SSam Leffler #include <sys/systm.h> 37*8ec07310SGleb Smirnoff #include <sys/malloc.h> 3888768458SSam Leffler #include <sys/mbuf.h> 3988768458SSam Leffler #include <sys/socket.h> 4088768458SSam Leffler 41eddfbb76SRobert Watson #include <net/vnet.h> 4288768458SSam Leffler #include <netinet/in.h> 4388768458SSam Leffler #include <netipsec/ipsec.h> 4488768458SSam Leffler 4588768458SSam Leffler /* 46972136faSSam Leffler * Make space for a new header of length hlen at skip bytes 47972136faSSam Leffler * into the packet. When doing this we allocate new mbufs only 4888768458SSam Leffler * when absolutely necessary. The mbuf where the new header 4988768458SSam Leffler * is to go is returned together with an offset into the mbuf. 5088768458SSam Leffler * If NULL is returned then the mbuf chain may have been modified; 5188768458SSam Leffler * the caller is assumed to always free the chain. 5288768458SSam Leffler */ 5388768458SSam Leffler struct mbuf * 5488768458SSam Leffler m_makespace(struct mbuf *m0, int skip, int hlen, int *off) 5588768458SSam Leffler { 5688768458SSam Leffler struct mbuf *m; 5788768458SSam Leffler unsigned remain; 5888768458SSam Leffler 599ffa9677SSam Leffler IPSEC_ASSERT(m0 != NULL, ("null mbuf")); 609ffa9677SSam Leffler IPSEC_ASSERT(hlen < MHLEN, ("hlen too big: %u", hlen)); 6188768458SSam Leffler 6288768458SSam Leffler for (m = m0; m && skip > m->m_len; m = m->m_next) 6388768458SSam Leffler skip -= m->m_len; 6488768458SSam Leffler if (m == NULL) 6588768458SSam Leffler return (NULL); 6688768458SSam Leffler /* 6788768458SSam Leffler * At this point skip is the offset into the mbuf m 6888768458SSam Leffler * where the new header should be placed. Figure out 6988768458SSam Leffler * if there's space to insert the new header. If so, 70023795f0SBjoern A. Zeeb * and copying the remainder makes sense then do so. 7188768458SSam Leffler * Otherwise insert a new mbuf in the chain, splitting 7288768458SSam Leffler * the contents of m as needed. 7388768458SSam Leffler */ 7488768458SSam Leffler remain = m->m_len - skip; /* data to move */ 7588768458SSam Leffler if (hlen > M_TRAILINGSPACE(m)) { 76357c11c9SVANHULLEBUS Yvan struct mbuf *n0, *n, **np; 77357c11c9SVANHULLEBUS Yvan int todo, len, done, alloc; 7888768458SSam Leffler 79357c11c9SVANHULLEBUS Yvan n0 = NULL; 80357c11c9SVANHULLEBUS Yvan np = &n0; 81357c11c9SVANHULLEBUS Yvan alloc = 0; 82357c11c9SVANHULLEBUS Yvan done = 0; 83357c11c9SVANHULLEBUS Yvan todo = remain; 84357c11c9SVANHULLEBUS Yvan while (todo > 0) { 85357c11c9SVANHULLEBUS Yvan if (todo > MHLEN) { 86eb1b1807SGleb Smirnoff n = m_getcl(M_NOWAIT, m->m_type, 0); 87357c11c9SVANHULLEBUS Yvan len = MCLBYTES; 88357c11c9SVANHULLEBUS Yvan } 89357c11c9SVANHULLEBUS Yvan else { 90eb1b1807SGleb Smirnoff n = m_get(M_NOWAIT, m->m_type); 91357c11c9SVANHULLEBUS Yvan len = MHLEN; 92357c11c9SVANHULLEBUS Yvan } 93357c11c9SVANHULLEBUS Yvan if (n == NULL) { 94357c11c9SVANHULLEBUS Yvan m_freem(n0); 95357c11c9SVANHULLEBUS Yvan return NULL; 96357c11c9SVANHULLEBUS Yvan } 97357c11c9SVANHULLEBUS Yvan *np = n; 98357c11c9SVANHULLEBUS Yvan np = &n->m_next; 99357c11c9SVANHULLEBUS Yvan alloc++; 100357c11c9SVANHULLEBUS Yvan len = min(todo, len); 101357c11c9SVANHULLEBUS Yvan memcpy(n->m_data, mtod(m, char *) + skip + done, len); 102357c11c9SVANHULLEBUS Yvan n->m_len = len; 103357c11c9SVANHULLEBUS Yvan done += len; 104357c11c9SVANHULLEBUS Yvan todo -= len; 105357c11c9SVANHULLEBUS Yvan } 106357c11c9SVANHULLEBUS Yvan 10788768458SSam Leffler if (hlen <= M_TRAILINGSPACE(m) + remain) { 10888768458SSam Leffler m->m_len = skip + hlen; 10988768458SSam Leffler *off = skip; 110357c11c9SVANHULLEBUS Yvan if (n0 != NULL) { 111357c11c9SVANHULLEBUS Yvan *np = m->m_next; 112357c11c9SVANHULLEBUS Yvan m->m_next = n0; 11388768458SSam Leffler } 114357c11c9SVANHULLEBUS Yvan } 115357c11c9SVANHULLEBUS Yvan else { 116eb1b1807SGleb Smirnoff n = m_get(M_NOWAIT, m->m_type); 117357c11c9SVANHULLEBUS Yvan if (n == NULL) { 118357c11c9SVANHULLEBUS Yvan m_freem(n0); 119357c11c9SVANHULLEBUS Yvan return NULL; 120357c11c9SVANHULLEBUS Yvan } 121357c11c9SVANHULLEBUS Yvan alloc++; 122357c11c9SVANHULLEBUS Yvan 123357c11c9SVANHULLEBUS Yvan if ((n->m_next = n0) == NULL) 124357c11c9SVANHULLEBUS Yvan np = &n->m_next; 125357c11c9SVANHULLEBUS Yvan n0 = n; 126357c11c9SVANHULLEBUS Yvan 127357c11c9SVANHULLEBUS Yvan *np = m->m_next; 128357c11c9SVANHULLEBUS Yvan m->m_next = n0; 129357c11c9SVANHULLEBUS Yvan 130357c11c9SVANHULLEBUS Yvan n->m_len = hlen; 131357c11c9SVANHULLEBUS Yvan m->m_len = skip; 132357c11c9SVANHULLEBUS Yvan 13388768458SSam Leffler m = n; /* header is at front ... */ 13488768458SSam Leffler *off = 0; /* ... of new mbuf */ 13588768458SSam Leffler } 1366659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_mbinserted); 13788768458SSam Leffler } else { 13888768458SSam Leffler /* 13988768458SSam Leffler * Copy the remainder to the back of the mbuf 14088768458SSam Leffler * so there's space to write the new header. 14188768458SSam Leffler */ 1422aebee88SDag-Erling Smørgrav bcopy(mtod(m, caddr_t) + skip, 14388768458SSam Leffler mtod(m, caddr_t) + skip + hlen, remain); 14488768458SSam Leffler m->m_len += hlen; 14588768458SSam Leffler *off = skip; 14688768458SSam Leffler } 14788768458SSam Leffler m0->m_pkthdr.len += hlen; /* adjust packet length */ 14888768458SSam Leffler return m; 14988768458SSam Leffler } 15088768458SSam Leffler 15188768458SSam Leffler /* 15288768458SSam Leffler * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header 15388768458SSam Leffler * length is updated, and a pointer to the first byte of the padding 15488768458SSam Leffler * (which is guaranteed to be all in one mbuf) is returned. 15588768458SSam Leffler */ 15688768458SSam Leffler caddr_t 15788768458SSam Leffler m_pad(struct mbuf *m, int n) 15888768458SSam Leffler { 15988768458SSam Leffler register struct mbuf *m0, *m1; 16088768458SSam Leffler register int len, pad; 16188768458SSam Leffler caddr_t retval; 16288768458SSam Leffler 16388768458SSam Leffler if (n <= 0) { /* No stupid arguments. */ 1649ffa9677SSam Leffler DPRINTF(("%s: pad length invalid (%d)\n", __func__, n)); 16588768458SSam Leffler m_freem(m); 16688768458SSam Leffler return NULL; 16788768458SSam Leffler } 16888768458SSam Leffler 16988768458SSam Leffler len = m->m_pkthdr.len; 17088768458SSam Leffler pad = n; 17188768458SSam Leffler m0 = m; 17288768458SSam Leffler 17388768458SSam Leffler while (m0->m_len < len) { 17488768458SSam Leffler len -= m0->m_len; 17588768458SSam Leffler m0 = m0->m_next; 17688768458SSam Leffler } 17788768458SSam Leffler 17888768458SSam Leffler if (m0->m_len != len) { 1799ffa9677SSam Leffler DPRINTF(("%s: length mismatch (should be %d instead of %d)\n", 1809ffa9677SSam Leffler __func__, m->m_pkthdr.len, 1819ffa9677SSam Leffler m->m_pkthdr.len + m0->m_len - len)); 18288768458SSam Leffler 18388768458SSam Leffler m_freem(m); 18488768458SSam Leffler return NULL; 18588768458SSam Leffler } 18688768458SSam Leffler 18788768458SSam Leffler /* Check for zero-length trailing mbufs, and find the last one. */ 18888768458SSam Leffler for (m1 = m0; m1->m_next; m1 = m1->m_next) { 18988768458SSam Leffler if (m1->m_next->m_len != 0) { 1909ffa9677SSam Leffler DPRINTF(("%s: length mismatch (should be %d instead " 1919ffa9677SSam Leffler "of %d)\n", __func__, 19288768458SSam Leffler m->m_pkthdr.len, 19388768458SSam Leffler m->m_pkthdr.len + m1->m_next->m_len)); 19488768458SSam Leffler 19588768458SSam Leffler m_freem(m); 19688768458SSam Leffler return NULL; 19788768458SSam Leffler } 19888768458SSam Leffler 19988768458SSam Leffler m0 = m1->m_next; 20088768458SSam Leffler } 20188768458SSam Leffler 20288768458SSam Leffler if (pad > M_TRAILINGSPACE(m0)) { 20388768458SSam Leffler /* Add an mbuf to the chain. */ 204eb1b1807SGleb Smirnoff MGET(m1, M_NOWAIT, MT_DATA); 20588768458SSam Leffler if (m1 == 0) { 20688768458SSam Leffler m_freem(m0); 2079ffa9677SSam Leffler DPRINTF(("%s: unable to get extra mbuf\n", __func__)); 20888768458SSam Leffler return NULL; 20988768458SSam Leffler } 21088768458SSam Leffler 21188768458SSam Leffler m0->m_next = m1; 21288768458SSam Leffler m0 = m1; 21388768458SSam Leffler m0->m_len = 0; 21488768458SSam Leffler } 21588768458SSam Leffler 21688768458SSam Leffler retval = m0->m_data + m0->m_len; 21788768458SSam Leffler m0->m_len += pad; 21888768458SSam Leffler m->m_pkthdr.len += pad; 21988768458SSam Leffler 22088768458SSam Leffler return retval; 22188768458SSam Leffler } 22288768458SSam Leffler 22388768458SSam Leffler /* 22488768458SSam Leffler * Remove hlen data at offset skip in the packet. This is used by 22588768458SSam Leffler * the protocols strip protocol headers and associated data (e.g. IV, 22688768458SSam Leffler * authenticator) on input. 22788768458SSam Leffler */ 22888768458SSam Leffler int 22988768458SSam Leffler m_striphdr(struct mbuf *m, int skip, int hlen) 23088768458SSam Leffler { 23188768458SSam Leffler struct mbuf *m1; 23288768458SSam Leffler int roff; 23388768458SSam Leffler 23488768458SSam Leffler /* Find beginning of header */ 23588768458SSam Leffler m1 = m_getptr(m, skip, &roff); 23688768458SSam Leffler if (m1 == NULL) 23788768458SSam Leffler return (EINVAL); 23888768458SSam Leffler 23988768458SSam Leffler /* Remove the header and associated data from the mbuf. */ 24088768458SSam Leffler if (roff == 0) { 24188768458SSam Leffler /* The header was at the beginning of the mbuf */ 2426659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_input_front); 24388768458SSam Leffler m_adj(m1, hlen); 24488768458SSam Leffler if ((m1->m_flags & M_PKTHDR) == 0) 24588768458SSam Leffler m->m_pkthdr.len -= hlen; 24688768458SSam Leffler } else if (roff + hlen >= m1->m_len) { 24788768458SSam Leffler struct mbuf *mo; 24888768458SSam Leffler 24988768458SSam Leffler /* 25088768458SSam Leffler * Part or all of the header is at the end of this mbuf, 25188768458SSam Leffler * so first let's remove the remainder of the header from 25288768458SSam Leffler * the beginning of the remainder of the mbuf chain, if any. 25388768458SSam Leffler */ 2546659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_input_end); 25588768458SSam Leffler if (roff + hlen > m1->m_len) { 25688768458SSam Leffler /* Adjust the next mbuf by the remainder */ 25788768458SSam Leffler m_adj(m1->m_next, roff + hlen - m1->m_len); 25888768458SSam Leffler 25988768458SSam Leffler /* The second mbuf is guaranteed not to have a pkthdr... */ 26088768458SSam Leffler m->m_pkthdr.len -= (roff + hlen - m1->m_len); 26188768458SSam Leffler } 26288768458SSam Leffler 26388768458SSam Leffler /* Now, let's unlink the mbuf chain for a second...*/ 26488768458SSam Leffler mo = m1->m_next; 26588768458SSam Leffler m1->m_next = NULL; 26688768458SSam Leffler 26788768458SSam Leffler /* ...and trim the end of the first part of the chain...sick */ 26888768458SSam Leffler m_adj(m1, -(m1->m_len - roff)); 26988768458SSam Leffler if ((m1->m_flags & M_PKTHDR) == 0) 27088768458SSam Leffler m->m_pkthdr.len -= (m1->m_len - roff); 27188768458SSam Leffler 27288768458SSam Leffler /* Finally, let's relink */ 27388768458SSam Leffler m1->m_next = mo; 27488768458SSam Leffler } else { 27588768458SSam Leffler /* 27688768458SSam Leffler * The header lies in the "middle" of the mbuf; copy 27788768458SSam Leffler * the remainder of the mbuf down over the header. 27888768458SSam Leffler */ 2796659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_input_middle); 28088768458SSam Leffler bcopy(mtod(m1, u_char *) + roff + hlen, 28188768458SSam Leffler mtod(m1, u_char *) + roff, 28288768458SSam Leffler m1->m_len - (roff + hlen)); 28388768458SSam Leffler m1->m_len -= hlen; 28488768458SSam Leffler m->m_pkthdr.len -= hlen; 28588768458SSam Leffler } 28688768458SSam Leffler return (0); 28788768458SSam Leffler } 28888768458SSam Leffler 28988768458SSam Leffler /* 29088768458SSam Leffler * Diagnostic routine to check mbuf alignment as required by the 29188768458SSam Leffler * crypto device drivers (that use DMA). 29288768458SSam Leffler */ 29388768458SSam Leffler void 29488768458SSam Leffler m_checkalignment(const char* where, struct mbuf *m0, int off, int len) 29588768458SSam Leffler { 29688768458SSam Leffler int roff; 29788768458SSam Leffler struct mbuf *m = m_getptr(m0, off, &roff); 29888768458SSam Leffler caddr_t addr; 29988768458SSam Leffler 30088768458SSam Leffler if (m == NULL) 30188768458SSam Leffler return; 30288768458SSam Leffler printf("%s (off %u len %u): ", where, off, len); 30388768458SSam Leffler addr = mtod(m, caddr_t) + roff; 30488768458SSam Leffler do { 30588768458SSam Leffler int mlen; 30688768458SSam Leffler 30788768458SSam Leffler if (((uintptr_t) addr) & 3) { 30888768458SSam Leffler printf("addr misaligned %p,", addr); 30988768458SSam Leffler break; 31088768458SSam Leffler } 31188768458SSam Leffler mlen = m->m_len; 31288768458SSam Leffler if (mlen > len) 31388768458SSam Leffler mlen = len; 31488768458SSam Leffler len -= mlen; 31588768458SSam Leffler if (len && (mlen & 3)) { 31688768458SSam Leffler printf("len mismatch %u,", mlen); 31788768458SSam Leffler break; 31888768458SSam Leffler } 31988768458SSam Leffler m = m->m_next; 32088768458SSam Leffler addr = m ? mtod(m, caddr_t) : NULL; 32188768458SSam Leffler } while (m && len > 0); 32288768458SSam Leffler for (m = m0; m; m = m->m_next) 32388768458SSam Leffler printf(" [%p:%u]", mtod(m, caddr_t), m->m_len); 32488768458SSam Leffler printf("\n"); 32588768458SSam Leffler } 326