]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipsec/ipsec_mbuf.c
sys/{x86,amd64}: remove one of doubled ;s
[FreeBSD/FreeBSD.git] / sys / netipsec / ipsec_mbuf.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 /*
32  * IPsec-specific mbuf routines.
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40
41 #include <net/vnet.h>
42 #include <netinet/in.h>
43 #include <netipsec/ipsec.h>
44
45 /*
46  * Make space for a new header of length hlen at skip bytes
47  * into the packet.  When doing this we allocate new mbufs only
48  * when absolutely necessary.  The mbuf where the new header
49  * is to go is returned together with an offset into the mbuf.
50  * If NULL is returned then the mbuf chain may have been modified;
51  * the caller is assumed to always free the chain.
52  */
53 struct mbuf *
54 m_makespace(struct mbuf *m0, int skip, int hlen, int *off)
55 {
56         struct mbuf *m;
57         unsigned remain;
58
59         IPSEC_ASSERT(m0 != NULL, ("null mbuf"));
60         IPSEC_ASSERT(hlen < MHLEN, ("hlen too big: %u", hlen));
61
62         for (m = m0; m && skip > m->m_len; m = m->m_next)
63                 skip -= m->m_len;
64         if (m == NULL)
65                 return (NULL);
66         /*
67          * At this point skip is the offset into the mbuf m
68          * where the new header should be placed.  Figure out
69          * if there's space to insert the new header.  If so,
70          * and copying the remainder makes sense then do so.
71          * Otherwise insert a new mbuf in the chain, splitting
72          * the contents of m as needed.
73          */
74         remain = m->m_len - skip;               /* data to move */
75         if (remain > skip &&
76             hlen + max_linkhdr < M_LEADINGSPACE(m)) {
77                 /*
78                  * mbuf has enough free space at the beginning.
79                  * XXX: which operation is the most heavy - copying of
80                  *      possible several hundred of bytes or allocation
81                  *      of new mbuf? We can remove max_linkhdr check
82                  *      here, but it is possible that this will lead
83                  *      to allocation of new mbuf in Layer 2 code.
84                  */
85                 m->m_data -= hlen;
86                 bcopy(mtodo(m, hlen), mtod(m, caddr_t), skip);
87                 m->m_len += hlen;
88                 *off = skip;
89         } else if (hlen > M_TRAILINGSPACE(m)) {
90                 struct mbuf *n0, *n, **np;
91                 int todo, len, done, alloc;
92
93                 n0 = NULL;
94                 np = &n0;
95                 alloc = 0;
96                 done = 0;
97                 todo = remain;
98                 while (todo > 0) {
99                         if (todo > MHLEN) {
100                                 n = m_getcl(M_NOWAIT, m->m_type, 0);
101                                 len = MCLBYTES;
102                         }
103                         else {
104                                 n = m_get(M_NOWAIT, m->m_type);
105                                 len = MHLEN;
106                         }
107                         if (n == NULL) {
108                                 m_freem(n0);
109                                 return NULL;
110                         }
111                         *np = n;
112                         np = &n->m_next;
113                         alloc++;
114                         len = min(todo, len);
115                         memcpy(n->m_data, mtod(m, char *) + skip + done, len);
116                         n->m_len = len;
117                         done += len;
118                         todo -= len;
119                 }
120
121                 if (hlen <= M_TRAILINGSPACE(m) + remain) {
122                         m->m_len = skip + hlen;
123                         *off = skip;
124                         if (n0 != NULL) {
125                                 *np = m->m_next;
126                                 m->m_next = n0;
127                         }
128                 }
129                 else {
130                         n = m_get(M_NOWAIT, m->m_type);
131                         if (n == NULL) {
132                                 m_freem(n0);
133                                 return NULL;
134                         }
135                         alloc++;
136
137                         if ((n->m_next = n0) == NULL)
138                                 np = &n->m_next;
139                         n0 = n;
140
141                         *np = m->m_next;
142                         m->m_next = n0;
143
144                         n->m_len = hlen;
145                         m->m_len = skip;
146
147                         m = n;                  /* header is at front ... */
148                         *off = 0;               /* ... of new mbuf */
149                 }
150                 IPSECSTAT_INC(ips_mbinserted);
151         } else {
152                 /*
153                  * Copy the remainder to the back of the mbuf
154                  * so there's space to write the new header.
155                  */
156                 bcopy(mtod(m, caddr_t) + skip,
157                     mtod(m, caddr_t) + skip + hlen, remain);
158                 m->m_len += hlen;
159                 *off = skip;
160         }
161         m0->m_pkthdr.len += hlen;               /* adjust packet length */
162         return m;
163 }
164
165 /*
166  * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
167  * length is updated, and a pointer to the first byte of the padding
168  * (which is guaranteed to be all in one mbuf) is returned.
169  */
170 caddr_t
171 m_pad(struct mbuf *m, int n)
172 {
173         struct mbuf *m0, *m1;
174         int len, pad;
175         caddr_t retval;
176
177         if (n <= 0) {  /* No stupid arguments. */
178                 DPRINTF(("%s: pad length invalid (%d)\n", __func__, n));
179                 m_freem(m);
180                 return NULL;
181         }
182
183         len = m->m_pkthdr.len;
184         pad = n;
185         m0 = m;
186
187         while (m0->m_len < len) {
188                 len -= m0->m_len;
189                 m0 = m0->m_next;
190         }
191
192         if (m0->m_len != len) {
193                 DPRINTF(("%s: length mismatch (should be %d instead of %d)\n",
194                         __func__, m->m_pkthdr.len,
195                         m->m_pkthdr.len + m0->m_len - len));
196
197                 m_freem(m);
198                 return NULL;
199         }
200
201         /* Check for zero-length trailing mbufs, and find the last one. */
202         for (m1 = m0; m1->m_next; m1 = m1->m_next) {
203                 if (m1->m_next->m_len != 0) {
204                         DPRINTF(("%s: length mismatch (should be %d instead "
205                                 "of %d)\n", __func__,
206                                 m->m_pkthdr.len,
207                                 m->m_pkthdr.len + m1->m_next->m_len));
208
209                         m_freem(m);
210                         return NULL;
211                 }
212
213                 m0 = m1->m_next;
214         }
215
216         if (pad > M_TRAILINGSPACE(m0)) {
217                 /* Add an mbuf to the chain. */
218                 MGET(m1, M_NOWAIT, MT_DATA);
219                 if (m1 == NULL) {
220                         m_freem(m0);
221                         DPRINTF(("%s: unable to get extra mbuf\n", __func__));
222                         return NULL;
223                 }
224
225                 m0->m_next = m1;
226                 m0 = m1;
227                 m0->m_len = 0;
228         }
229
230         retval = m0->m_data + m0->m_len;
231         m0->m_len += pad;
232         m->m_pkthdr.len += pad;
233
234         return retval;
235 }
236
237 /*
238  * Remove hlen data at offset skip in the packet.  This is used by
239  * the protocols strip protocol headers and associated data (e.g. IV,
240  * authenticator) on input.
241  */
242 int
243 m_striphdr(struct mbuf *m, int skip, int hlen)
244 {
245         struct mbuf *m1;
246         int roff;
247
248         /* Find beginning of header */
249         m1 = m_getptr(m, skip, &roff);
250         if (m1 == NULL)
251                 return (EINVAL);
252
253         /* Remove the header and associated data from the mbuf. */
254         if (roff == 0) {
255                 /* The header was at the beginning of the mbuf */
256                 IPSECSTAT_INC(ips_input_front);
257                 m_adj(m1, hlen);
258                 if (m1 != m)
259                         m->m_pkthdr.len -= hlen;
260         } else if (roff + hlen >= m1->m_len) {
261                 struct mbuf *mo;
262                 int adjlen;
263
264                 /*
265                  * Part or all of the header is at the end of this mbuf,
266                  * so first let's remove the remainder of the header from
267                  * the beginning of the remainder of the mbuf chain, if any.
268                  */
269                 IPSECSTAT_INC(ips_input_end);
270                 if (roff + hlen > m1->m_len) {
271                         adjlen = roff + hlen - m1->m_len;
272
273                         /* Adjust the next mbuf by the remainder */
274                         m_adj(m1->m_next, adjlen);
275
276                         /* The second mbuf is guaranteed not to have a pkthdr... */
277                         m->m_pkthdr.len -= adjlen;
278                 }
279
280                 /* Now, let's unlink the mbuf chain for a second...*/
281                 mo = m1->m_next;
282                 m1->m_next = NULL;
283
284                 /* ...and trim the end of the first part of the chain...sick */
285                 adjlen = m1->m_len - roff;
286                 m_adj(m1, -adjlen);
287                 if (m1 != m)
288                         m->m_pkthdr.len -= adjlen;
289
290                 /* Finally, let's relink */
291                 m1->m_next = mo;
292         } else {
293                 /*
294                  * The header lies in the "middle" of the mbuf; copy
295                  * the remainder of the mbuf down over the header.
296                  */
297                 IPSECSTAT_INC(ips_input_middle);
298                 bcopy(mtod(m1, u_char *) + roff + hlen,
299                       mtod(m1, u_char *) + roff,
300                       m1->m_len - (roff + hlen));
301                 m1->m_len -= hlen;
302                 m->m_pkthdr.len -= hlen;
303         }
304         return (0);
305 }
306
307 /*
308  * Diagnostic routine to check mbuf alignment as required by the
309  * crypto device drivers (that use DMA).
310  */
311 void
312 m_checkalignment(const char* where, struct mbuf *m0, int off, int len)
313 {
314         int roff;
315         struct mbuf *m = m_getptr(m0, off, &roff);
316         caddr_t addr;
317
318         if (m == NULL)
319                 return;
320         printf("%s (off %u len %u): ", where, off, len);
321         addr = mtod(m, caddr_t) + roff;
322         do {
323                 int mlen;
324
325                 if (((uintptr_t) addr) & 3) {
326                         printf("addr misaligned %p,", addr);
327                         break;
328                 }
329                 mlen = m->m_len;
330                 if (mlen > len)
331                         mlen = len;
332                 len -= mlen;
333                 if (len && (mlen & 3)) {
334                         printf("len mismatch %u,", mlen);
335                         break;
336                 }
337                 m = m->m_next;
338                 addr = m ? mtod(m, caddr_t) : NULL;
339         } while (m && len > 0);
340         for (m = m0; m; m = m->m_next)
341                 printf(" [%p:%u]", mtod(m, caddr_t), m->m_len);
342         printf("\n");
343 }