]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/pf_pbuf.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / net / pf_pbuf.c
CommitLineData
5ba3f43e 1/*
d9a64523 2 * Copyright (c) 2016-2018 Apple Inc. All rights reserved.
5ba3f43e
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/cdefs.h>
25#include <sys/systm.h>
26#include <sys/param.h>
27#include <sys/types.h>
28#include <sys/mcache.h>
29#include <kern/kern_types.h>
30#include <net/pf_pbuf.h>
cb323159 31#include <net/pfvar.h>
5ba3f43e
A
32#include <netinet/in.h>
33
34void
35pbuf_init_mbuf(pbuf_t *pbuf, struct mbuf *m, struct ifnet *ifp)
36{
5ba3f43e
A
37 VERIFY((m->m_flags & M_PKTHDR) != 0);
38
39 pbuf->pb_type = PBUF_TYPE_MBUF;
40 pbuf->pb_mbuf = m;
41 pbuf->pb_ifp = ifp;
42 pbuf->pb_next = NULL;
43 pbuf_sync(pbuf);
44}
45
46void
47pbuf_init_memory(pbuf_t *pbuf, const struct pbuf_memory *mp, struct ifnet *ifp)
48{
5ba3f43e
A
49 pbuf->pb_type = PBUF_TYPE_MEMORY;
50 pbuf->pb_memory = *mp;
51 pbuf->pb_ifp = ifp;
52 pbuf->pb_next = NULL;
53 pbuf_sync(pbuf);
54}
55
56void
57pbuf_destroy(pbuf_t *pbuf)
58{
5ba3f43e
A
59 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
60 if (pbuf->pb_mbuf) {
61 m_freem(pbuf->pb_mbuf);
62 pbuf->pb_mbuf = NULL;
63 }
0a7de745 64 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e
A
65 VERIFY(pbuf->pb_memory.pm_buffer != NULL);
66 (void) (pbuf->pb_memory.pm_action)(&pbuf->pb_memory,
67 PBUF_ACTION_DESTROY);
68 } else {
69 VERIFY(pbuf->pb_type == PBUF_TYPE_ZOMBIE);
70 }
71
72 memset(pbuf, 0, sizeof(*pbuf));
73}
74
75void
76pbuf_sync(pbuf_t *pbuf)
77{
5ba3f43e
A
78 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
79 struct mbuf *m = pbuf->pb_mbuf;
80
81 VERIFY(m != NULL);
82 VERIFY(m->m_flags & M_PKTHDR);
83
84 pbuf->pb_data = mtod(m, void *);
85 pbuf->pb_packet_len = m->m_pkthdr.len;
86 pbuf->pb_contig_len = m->m_len;
87 pbuf->pb_csum_flags = &m->m_pkthdr.csum_flags;
88 pbuf->pb_csum_data = &m->m_pkthdr.csum_data;
89 pbuf->pb_proto = &m->m_pkthdr.pkt_proto;
90 pbuf->pb_flowsrc = &m->m_pkthdr.pkt_flowsrc;
91 pbuf->pb_flowid = &m->m_pkthdr.pkt_flowid;
92 pbuf->pb_flags = &m->m_pkthdr.pkt_flags;
93 pbuf->pb_pftag = m_pftag(m);
cb323159
A
94 pbuf->pb_pf_fragtag = pf_find_fragment_tag(m);
95 ASSERT((pbuf->pb_pf_fragtag == NULL) ||
96 (pbuf->pb_pftag->pftag_flags & PF_TAG_REASSEMBLED));
0a7de745 97 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e
A
98 struct pbuf_memory *nm = &pbuf->pb_memory;
99
100 VERIFY(nm->pm_buffer != NULL);
101 VERIFY(nm->pm_buffer_len != 0);
102 VERIFY(nm->pm_len != 0);
103 VERIFY(nm->pm_len <= nm->pm_buffer_len);
104 VERIFY(nm->pm_offset < nm->pm_len);
105
106 pbuf->pb_data = &nm->pm_buffer[nm->pm_offset];
107 pbuf->pb_packet_len = nm->pm_len;
108 pbuf->pb_contig_len = nm->pm_len;
109 pbuf->pb_csum_flags = &nm->pm_csum_flags;
110 pbuf->pb_csum_data = &nm->pm_csum_data;
111 pbuf->pb_proto = &nm->pm_proto;
112 pbuf->pb_flowsrc = &nm->pm_flowsrc;
113 pbuf->pb_flowid = &nm->pm_flowid;
114 pbuf->pb_flags = &nm->pm_flags;
115 pbuf->pb_pftag = &nm->pm_pftag;
cb323159 116 pbuf->pb_pf_fragtag = &nm->pm_pf_fragtag;
0a7de745 117 } else {
5ba3f43e 118 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 119 }
5ba3f43e
A
120}
121
122struct mbuf *
123pbuf_to_mbuf(pbuf_t *pbuf, boolean_t release_ptr)
124{
125 struct mbuf *m = NULL;
126
127 pbuf_sync(pbuf);
128
129 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
130 m = pbuf->pb_mbuf;
131 if (release_ptr) {
132 pbuf->pb_mbuf = NULL;
5ba3f43e 133 }
0a7de745 134 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
cb323159
A
135 boolean_t fragtag = FALSE;
136
5ba3f43e
A
137 if (pbuf->pb_packet_len > (u_int)MHLEN) {
138 if (pbuf->pb_packet_len > (u_int)MCLBYTES) {
139 printf("%s: packet too big for cluster (%u)\n",
140 __func__, pbuf->pb_packet_len);
0a7de745 141 return NULL;
5ba3f43e
A
142 }
143 m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
144 } else {
145 m = m_gethdr(M_DONTWAIT, MT_DATA);
146 }
0a7de745 147 if (m == NULL) {
cb323159 148 goto done;
0a7de745 149 }
5ba3f43e
A
150
151 m_copyback(m, 0, pbuf->pb_packet_len, pbuf->pb_data);
152 m->m_pkthdr.csum_flags = *pbuf->pb_csum_flags;
153 m->m_pkthdr.csum_data = *pbuf->pb_csum_data;
154 m->m_pkthdr.pkt_proto = *pbuf->pb_proto;
155 m->m_pkthdr.pkt_flowsrc = *pbuf->pb_flowsrc;
156 m->m_pkthdr.pkt_flowid = *pbuf->pb_flowid;
157 m->m_pkthdr.pkt_flags = *pbuf->pb_flags;
158
159 if (pbuf->pb_pftag != NULL) {
160 struct pf_mtag *pftag = m_pftag(m);
161
cb323159
A
162 ASSERT(pftag != NULL);
163 *pftag = *pbuf->pb_pftag;
164 fragtag =
165 ((pftag->pftag_flags & PF_TAG_REASSEMBLED) != 0);
5ba3f43e
A
166 }
167
cb323159
A
168 if (fragtag && pbuf->pb_pf_fragtag != NULL) {
169 if (pf_copy_fragment_tag(m, pbuf->pb_pf_fragtag,
170 M_NOWAIT) == NULL) {
171 m_freem(m);
172 m = NULL;
173 goto done;
174 }
0a7de745 175 }
5ba3f43e
A
176 }
177
cb323159
A
178done:
179 if (release_ptr) {
180 pbuf_destroy(pbuf);
181 }
0a7de745 182 return m;
5ba3f43e
A
183}
184
185struct mbuf *
186pbuf_clone_to_mbuf(pbuf_t *pbuf)
187{
188 struct mbuf *m = NULL;
189
190 pbuf_sync(pbuf);
191
0a7de745 192 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
5ba3f43e 193 m = m_copy(pbuf->pb_mbuf, 0, M_COPYALL);
0a7de745 194 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e 195 m = pbuf_to_mbuf(pbuf, FALSE);
0a7de745 196 } else {
5ba3f43e 197 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 198 }
5ba3f43e 199
0a7de745 200 return m;
5ba3f43e
A
201}
202
203void *
204pbuf_ensure_writable(pbuf_t *pbuf, size_t len)
205{
5ba3f43e
A
206 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
207 struct mbuf *m = pbuf->pb_mbuf;
208
0a7de745
A
209 if (m_makewritable(&pbuf->pb_mbuf, 0, len, M_DONTWAIT)) {
210 return NULL;
211 }
5ba3f43e
A
212
213 if (pbuf->pb_mbuf == NULL) {
214 pbuf_destroy(pbuf);
0a7de745 215 return NULL;
5ba3f43e
A
216 }
217
0a7de745 218 if (m != pbuf->pb_mbuf) {
5ba3f43e 219 pbuf_sync(pbuf);
0a7de745
A
220 }
221 } else if (pbuf->pb_type != PBUF_TYPE_MEMORY) {
5ba3f43e 222 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 223 }
5ba3f43e 224
0a7de745 225 return pbuf->pb_data;
5ba3f43e
A
226}
227
228void *
229pbuf_resize_segment(pbuf_t *pbuf, int off, int olen, int nlen)
230{
231 void *rv = NULL;
232
233 VERIFY(off >= 0);
234 VERIFY((u_int)off <= pbuf->pb_packet_len);
235
236 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
237 struct mbuf *m, *n;
238
239 VERIFY(pbuf->pb_mbuf != NULL);
240
241 m = pbuf->pb_mbuf;
242
243 if (off > 0) {
244 /* Split the mbuf chain at the specified boundary */
0a7de745
A
245 if ((n = m_split(m, off, M_DONTWAIT)) == NULL) {
246 return NULL;
247 }
5ba3f43e
A
248 } else {
249 n = m;
250 }
251
252 /* Trim old length */
253 m_adj(n, olen);
254
255 /* Prepend new length */
0a7de745
A
256 if (M_PREPEND(n, nlen, M_DONTWAIT, 0) == NULL) {
257 return NULL;
258 }
5ba3f43e
A
259
260 rv = mtod(n, void *);
261
262 if (off > 0) {
263 /* Merge the two chains */
264 int mlen;
265
266 mlen = n->m_pkthdr.len;
267 m_cat(m, n);
268 m->m_pkthdr.len += mlen;
269 } else {
270 /* The new mbuf becomes the packet header */
271 pbuf->pb_mbuf = n;
272 }
273
274 pbuf_sync(pbuf);
d9a64523 275 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e
A
276 struct pbuf_memory *nm = &pbuf->pb_memory;
277 u_int true_offset, move_len;
278 int delta_len;
279 uint8_t *psrc, *pdst;
280
281 delta_len = nlen - olen;
282 VERIFY(nm->pm_offset + (nm->pm_len + delta_len) <=
283 nm->pm_buffer_len);
284
285 true_offset = (u_int)off + nm->pm_offset;
286 rv = &nm->pm_buffer[true_offset];
287 psrc = &nm->pm_buffer[true_offset + (u_int)olen];
288 pdst = &nm->pm_buffer[true_offset + (u_int)nlen];
289 move_len = pbuf->pb_packet_len - ((u_int)off + olen);
290 memmove(pdst, psrc, move_len);
291
292 nm->pm_len += delta_len;
293
294 VERIFY((nm->pm_len + nm->pm_offset) <= nm->pm_buffer_len);
295
296 pbuf_sync(pbuf);
d9a64523 297 } else {
5ba3f43e 298 panic("pbuf_csum_flags_get: bad pb_type: %d", pbuf->pb_type);
d9a64523 299 }
0a7de745 300 return rv;
5ba3f43e
A
301}
302
303void *
304pbuf_contig_segment(pbuf_t *pbuf, int off, int len)
305{
306 void *rv = NULL;
307
308 VERIFY(off >= 0);
309 VERIFY(len >= 0);
d9a64523 310 VERIFY((u_int)(off + len) <= pbuf->pb_packet_len);
5ba3f43e
A
311
312 /*
313 * Note: If this fails, then the pbuf is destroyed. This is a
314 * side-effect of m_pulldown().
315 *
316 * PF expects this behaviour so it's not a real problem.
317 */
5ba3f43e
A
318 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
319 struct mbuf *n;
320 int moff;
321
322 n = m_pulldown(pbuf->pb_mbuf, off, len, &moff);
323 if (n == NULL) {
324 /* mbuf is freed by m_pulldown() in this case */
325 pbuf->pb_mbuf = NULL;
326 pbuf_destroy(pbuf);
0a7de745 327 return NULL;
5ba3f43e
A
328 }
329
330 pbuf_sync(pbuf);
331
332 rv = (void *)(mtod(n, uint8_t *) + moff);
0a7de745 333 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e
A
334 /*
335 * This always succeeds since memory pbufs are fully contig.
336 */
337 rv = (void *)(uintptr_t)(((uint8_t *)pbuf->pb_data)[off]);
0a7de745 338 } else {
5ba3f43e 339 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 340 }
5ba3f43e 341
0a7de745 342 return rv;
5ba3f43e
A
343}
344
345void
346pbuf_copy_back(pbuf_t *pbuf, int off, int len, void *src)
347{
5ba3f43e
A
348 VERIFY(off >= 0);
349 VERIFY(len >= 0);
350 VERIFY((u_int)(off + len) <= pbuf->pb_packet_len);
351
5ba3f43e 352 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
0a7de745 353 m_copyback(pbuf->pb_mbuf, off, len, src);
cb323159 354 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
0a7de745 355 if (len) {
5ba3f43e 356 memcpy(&((uint8_t *)pbuf->pb_data)[off], src, len);
0a7de745
A
357 }
358 } else {
5ba3f43e 359 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 360 }
5ba3f43e
A
361}
362
363void
364pbuf_copy_data(pbuf_t *pbuf, int off, int len, void *dst)
365{
5ba3f43e
A
366 VERIFY(off >= 0);
367 VERIFY(len >= 0);
368 VERIFY((u_int)(off + len) <= pbuf->pb_packet_len);
369
5ba3f43e 370 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
0a7de745 371 m_copydata(pbuf->pb_mbuf, off, len, dst);
cb323159 372 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
0a7de745 373 if (len) {
5ba3f43e 374 memcpy(dst, &((uint8_t *)pbuf->pb_data)[off], len);
0a7de745
A
375 }
376 } else {
5ba3f43e 377 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 378 }
5ba3f43e
A
379}
380
381uint16_t
382pbuf_inet_cksum(const pbuf_t *pbuf, uint32_t nxt, uint32_t off, uint32_t len)
383{
384 uint16_t sum = 0;
385
0a7de745 386 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
5ba3f43e 387 sum = inet_cksum(pbuf->pb_mbuf, nxt, off, len);
0a7de745 388 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e 389 sum = inet_cksum_buffer(pbuf->pb_data, nxt, off, len);
0a7de745 390 } else {
5ba3f43e 391 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 392 }
5ba3f43e 393
0a7de745 394 return sum;
5ba3f43e
A
395}
396
397uint16_t
398pbuf_inet6_cksum(const pbuf_t *pbuf, uint32_t nxt, uint32_t off, uint32_t len)
399{
400 uint16_t sum = 0;
401
0a7de745 402 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
5ba3f43e 403 sum = inet6_cksum(pbuf->pb_mbuf, nxt, off, len);
0a7de745 404 } else if (pbuf->pb_type == PBUF_TYPE_MEMORY) {
5ba3f43e 405 sum = inet6_cksum_buffer(pbuf->pb_data, nxt, off, len);
0a7de745 406 } else {
5ba3f43e 407 panic("%s: bad pb_type: %d", __func__, pbuf->pb_type);
0a7de745 408 }
5ba3f43e 409
0a7de745 410 return sum;
5ba3f43e
A
411}
412
413mbuf_svc_class_t
414pbuf_get_service_class(const pbuf_t *pbuf)
415{
0a7de745 416 if (pbuf->pb_type == PBUF_TYPE_MBUF) {
5ba3f43e 417 return m_get_service_class(pbuf->pb_mbuf);
0a7de745 418 }
5ba3f43e
A
419
420 VERIFY(pbuf->pb_type == PBUF_TYPE_MEMORY);
421
0a7de745 422 return MBUF_SC_BE;
5ba3f43e 423}