]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/packet_mangler.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / net / packet_mangler.c
CommitLineData
fe8ab488 1/*
f427ee49 2 * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
fe8ab488
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/*
25 * THEORY OF OPERATION
26 *
27 * The packet mangler subsystem provides a limited way for user space
28 * applications to apply certain actions on certain flows.
29 *
30 * A user space applications opens a kernel control socket with the name
31 * PACKET_MANGLER_CONTROL_NAME to attach to the packet mangler subsystem.
32 * When connected, a "struct packet_mangler" is created and set as the
33 * "unitinfo" of the corresponding kernel control socket instance.
34 * Connect call for packet mangler's kernel control socket also registers
35 * ip filers with cookie set to the packet_mangler instance.
36 * The ip filters are removed when control socket is disconnected.
37 */
38#include <sys/types.h>
39#include <sys/kern_control.h>
40#include <sys/domain.h>
41#include <sys/protosw.h>
42#include <sys/syslog.h>
43
44#include <kern/locks.h>
45#include <kern/zalloc.h>
46#include <kern/debug.h>
47
48#include <net/packet_mangler.h>
49
50#include <netinet/tcp.h>
51#include <netinet/tcp_var.h>
52#include <netinet/ip.h>
cb323159 53#include <netinet/ip6.h>
fe8ab488
A
54#include <netinet/kpi_ipfilter.h>
55#include <string.h>
56#include <libkern/libkern.h>
57
0a7de745 58#define MAX_PACKET_MANGLER 1
fe8ab488 59
0a7de745 60#define PKT_MNGLR_FLG_IPFILTER_ATTACHED 0x00000001
fe8ab488 61
0a7de745
A
62SYSCTL_NODE(_net, OID_AUTO, pktmnglr, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "pktmnglr");
63SYSCTL_INT(_net_pktmnglr, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED,
64 &pkt_mnglr_log_level, 0, "");
fe8ab488
A
65/*
66 * The structure packet_mangler represents a user space packet filter
67 * It's created and associated with a kernel control socket instance
68 */
69struct packet_mangler {
0a7de745
A
70 kern_ctl_ref pkt_mnglr_kcref;
71 uint32_t pkt_mnglr_kcunit;
72 uint32_t pkt_mnglr_flags;
fe8ab488 73 /* IP filter related params */
0a7de745
A
74 ipfilter_t pkt_mnglr_ipfref;
75 ipfilter_t pkt_mnglr_ipfrefv6;
76 struct ipf_filter pkt_mnglr_ipfilter;
fe8ab488
A
77
78 /* Options */
0a7de745
A
79 uint8_t activate;
80 Pkt_Mnglr_Flow dir;
81 struct sockaddr_storage lsaddr;
82 struct sockaddr_storage rsaddr;
83 struct sockaddr_storage swap_lsaddr;
84 struct sockaddr_storage swap_rsaddr;
85 uint32_t ip_action_mask;
86 uint16_t lport;
87 uint16_t rport;
88 uint32_t proto;
89 uint32_t proto_action_mask;
fe8ab488
A
90};
91
92/* Array of all the packet mangler instancesi */
93struct packet_mangler **packet_manglers = NULL;
94
0a7de745 95uint32_t pkt_mnglr_active_count = 0; /* Number of active packet filters */
fe8ab488
A
96uint32_t pkt_mnglr_close_wait_timeout = 1000; /* in milliseconds */
97
98static kern_ctl_ref pkt_mnglr_kctlref = NULL;
99
100static lck_grp_attr_t *pkt_mnglr_lck_grp_attr = NULL;
101static lck_attr_t *pkt_mnglr_lck_attr = NULL;
102static lck_grp_t *pkt_mnglr_lck_grp = NULL;
103
104/* The lock below protects packet_manglers DS, packet_mangler DS */
105decl_lck_rw_data(static, pkt_mnglr_lck_rw);
106
0a7de745 107#define PKT_MNGLR_RW_LCK_MAX 8
fe8ab488
A
108
109int pkt_mnglr_rw_nxt_lck = 0;
110void* pkt_mnglr_rw_lock_history[PKT_MNGLR_RW_LCK_MAX];
111
112int pkt_mnglr_rw_nxt_unlck = 0;
113void* pkt_mnglr_rw_unlock_history[PKT_MNGLR_RW_LCK_MAX];
114
f427ee49
A
115static ZONE_DECLARE(packet_mangler_zone, "packet_mangler",
116 sizeof(struct packet_mangler), ZC_NONE);
fe8ab488
A
117
118/*
119 * For troubleshooting
120 */
121int pkt_mnglr_log_level = LOG_ERR;
122int pkt_mnglr_debug = 1;
123
124/*
125 * Forward declaration to appease the compiler
126 */
127static void pkt_mnglr_rw_lock_exclusive(lck_rw_t *);
128static void pkt_mnglr_rw_unlock_exclusive(lck_rw_t *);
129static void pkt_mnglr_rw_lock_shared(lck_rw_t *);
130static void pkt_mnglr_rw_unlock_shared(lck_rw_t *);
131
132static errno_t pktmnglr_ipfilter_output(void *cookie, mbuf_t *data,
0a7de745 133 ipf_pktopts_t options);
fe8ab488 134static errno_t pktmnglr_ipfilter_input(void *cookie, mbuf_t *data,
0a7de745 135 int offset, u_int8_t protocol);
fe8ab488
A
136static void pktmnglr_ipfilter_detach(void *cookie);
137
138static void chksm_update(mbuf_t data);
139
0a7de745
A
140#define TCP_OPT_MULTIPATH_TCP 30
141#define MPTCP_SBT_VER_OFFSET 2
3e170ce0 142
0a7de745
A
143#define MPTCP_SUBTYPE_MPCAPABLE 0x0
144#define MPTCP_SUBTYPE_MPJOIN 0x1
145#define MPTCP_SUBTYPE_DSS 0x2
146#define MPTCP_SUBTYPE_ADD_ADDR 0x3
147#define MPTCP_SUBTYPE_REM_ADDR 0x4
148#define MPTCP_SUBTYPE_MP_PRIO 0x5
149#define MPTCP_SUBTYPE_MP_FAIL 0x6
150#define MPTCP_SUBTYPE_MP_FASTCLOSE 0x7
3e170ce0 151
fe8ab488
A
152/*
153 * packet filter global read write lock
154 */
155
156static void
157pkt_mnglr_rw_lock_exclusive(lck_rw_t *lck)
158{
159 void *lr_saved;
160
161 lr_saved = __builtin_return_address(0);
162
163 lck_rw_lock_exclusive(lck);
164
165 pkt_mnglr_rw_lock_history[pkt_mnglr_rw_nxt_lck] = lr_saved;
166 pkt_mnglr_rw_nxt_lck =
167 (pkt_mnglr_rw_nxt_lck + 1) % PKT_MNGLR_RW_LCK_MAX;
168}
169
170static void
171pkt_mnglr_rw_unlock_exclusive(lck_rw_t *lck)
172{
173 void *lr_saved;
174
175 lr_saved = __builtin_return_address(0);
176
177 lck_rw_unlock_exclusive(lck);
178
179 pkt_mnglr_rw_unlock_history[pkt_mnglr_rw_nxt_unlck] =
180 lr_saved;
181 pkt_mnglr_rw_nxt_unlck = (pkt_mnglr_rw_nxt_unlck + 1) % PKT_MNGLR_RW_LCK_MAX;
182}
183
184static void
185pkt_mnglr_rw_lock_shared(lck_rw_t *lck)
186{
187 void *lr_saved;
188
189 lr_saved = __builtin_return_address(0);
190
191 lck_rw_lock_shared(lck);
192
193 pkt_mnglr_rw_lock_history[pkt_mnglr_rw_nxt_lck] = lr_saved;
194 pkt_mnglr_rw_nxt_lck = (pkt_mnglr_rw_nxt_lck + 1) % PKT_MNGLR_RW_LCK_MAX;
195}
196
197static void
198pkt_mnglr_rw_unlock_shared(lck_rw_t *lck)
199{
200 void *lr_saved;
201
202 lr_saved = __builtin_return_address(0);
203
204 lck_rw_unlock_shared(lck);
205
206 pkt_mnglr_rw_unlock_history[pkt_mnglr_rw_nxt_unlck] = lr_saved;
207 pkt_mnglr_rw_nxt_unlck = (pkt_mnglr_rw_nxt_unlck + 1) % PKT_MNGLR_RW_LCK_MAX;
208}
209
210/*
211 * Packet Mangler's Kernel control socket callbacks
212 */
213static errno_t
214pkt_mnglr_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
0a7de745 215 void **unitinfo)
fe8ab488 216{
0a7de745 217 errno_t error = 0;
fe8ab488
A
218 struct packet_mangler *p_pkt_mnglr = NULL;
219
220 PKT_MNGLR_LOG(LOG_NOTICE, "Connecting packet mangler filter.");
221
222 p_pkt_mnglr = zalloc(packet_mangler_zone);
223 if (p_pkt_mnglr == NULL) {
224 PKT_MNGLR_LOG(LOG_ERR, "zalloc failed");
225 error = ENOMEM;
226 goto done;
227 }
228
229 bzero(p_pkt_mnglr, sizeof(struct packet_mangler));
230
231 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
232 if (packet_manglers == NULL) {
233 struct packet_mangler **tmp;
234
235 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
236
237 MALLOC(tmp,
238 struct packet_mangler **,
239 MAX_PACKET_MANGLER * sizeof(struct packet_mangler *),
240 M_TEMP,
241 M_WAITOK | M_ZERO);
242
243 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
244
245 if (tmp == NULL && packet_manglers == NULL) {
246 error = ENOMEM;
247 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
248 goto done;
249 }
250 /* Another thread may have won the race */
0a7de745 251 if (packet_manglers != NULL) {
fe8ab488 252 FREE(tmp, M_TEMP);
0a7de745 253 } else {
fe8ab488 254 packet_manglers = tmp;
0a7de745 255 }
fe8ab488
A
256 }
257
258 if (sac->sc_unit == 0 || sac->sc_unit > MAX_PACKET_MANGLER) {
259 PKT_MNGLR_LOG(LOG_ERR, "bad sc_unit %u", sac->sc_unit);
260 error = EINVAL;
261 } else if (packet_manglers[sac->sc_unit - 1] != NULL) {
262 PKT_MNGLR_LOG(LOG_ERR, "sc_unit %u in use", sac->sc_unit);
263 error = EADDRINUSE;
264 } else {
265 /*
266 * kernel control socket kcunit numbers start at 1
267 */
268 packet_manglers[sac->sc_unit - 1] = p_pkt_mnglr;
269
270 p_pkt_mnglr->pkt_mnglr_kcref = kctlref;
271 p_pkt_mnglr->pkt_mnglr_kcunit = sac->sc_unit;
272
273 *unitinfo = p_pkt_mnglr;
274 pkt_mnglr_active_count++;
275 }
276
277 p_pkt_mnglr->pkt_mnglr_ipfilter.cookie = p_pkt_mnglr;
278 p_pkt_mnglr->pkt_mnglr_ipfilter.name = "com.apple.pktmnglripfilter";
279 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_input = pktmnglr_ipfilter_input;
280 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_output = pktmnglr_ipfilter_output;
281 p_pkt_mnglr->pkt_mnglr_ipfilter.ipf_detach = pktmnglr_ipfilter_detach;
282 error = ipf_addv4(&(p_pkt_mnglr->pkt_mnglr_ipfilter), &(p_pkt_mnglr->pkt_mnglr_ipfref));
283 if (error) {
284 PKT_MNGLR_LOG(LOG_ERR, "Could not register packet mangler's IPv4 Filter");
285 goto done;
286 }
287 error = ipf_addv6(&(p_pkt_mnglr->pkt_mnglr_ipfilter), &(p_pkt_mnglr->pkt_mnglr_ipfrefv6));
288 if (error) {
289 ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfref);
290 PKT_MNGLR_LOG(LOG_ERR, "Could not register packet mangler's IPv6 Filter");
291 goto done;
292 }
293
294 PKT_MNGLR_LOG(LOG_INFO, "Registered packet mangler's IP Filters");
0a7de745 295 p_pkt_mnglr->pkt_mnglr_flags |= PKT_MNGLR_FLG_IPFILTER_ATTACHED;
fe8ab488
A
296 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
297
298done:
0a7de745 299 if (error != 0 && p_pkt_mnglr != NULL) {
fe8ab488 300 zfree(packet_mangler_zone, p_pkt_mnglr);
0a7de745 301 }
fe8ab488
A
302
303 PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
304 error, pkt_mnglr_active_count, sac->sc_unit);
305
0a7de745 306 return error;
fe8ab488
A
307}
308
309static errno_t
310pkt_mnglr_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo)
311{
312#pragma unused(kctlref)
0a7de745 313 errno_t error = 0;
fe8ab488
A
314 struct packet_mangler *p_pkt_mnglr;
315
316 PKT_MNGLR_LOG(LOG_INFO, "Disconnecting packet mangler kernel control");
317
318 if (packet_manglers == NULL) {
319 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
320 error = EINVAL;
321 goto done;
322 }
323 if (kcunit > MAX_PACKET_MANGLER) {
324 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
325 kcunit, MAX_PACKET_MANGLER);
326 error = EINVAL;
327 goto done;
328 }
329
330 p_pkt_mnglr = (struct packet_mangler *)unitinfo;
331 if (p_pkt_mnglr == NULL) {
332 PKT_MNGLR_LOG(LOG_ERR, "Unit info is NULL");
333 goto done;
334 }
335
336 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
337 if (packet_manglers[kcunit - 1] != p_pkt_mnglr || p_pkt_mnglr->pkt_mnglr_kcunit != kcunit) {
338 PKT_MNGLR_LOG(LOG_ERR, "bad unit info %u)",
339 kcunit);
340 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
341 goto done;
342 }
343
344 /*
345 * Make filter inactive
346 */
347 packet_manglers[kcunit - 1] = NULL;
348 pkt_mnglr_active_count--;
349 if (p_pkt_mnglr->pkt_mnglr_flags & PKT_MNGLR_FLG_IPFILTER_ATTACHED) {
350 (void) ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfref);
351 (void) ipf_remove(p_pkt_mnglr->pkt_mnglr_ipfrefv6);
352 }
353 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
354 zfree(packet_mangler_zone, p_pkt_mnglr);
355done:
356 PKT_MNGLR_LOG(LOG_INFO, "return %d pkt_mnglr_active_count %u kcunit %u",
357 error, pkt_mnglr_active_count, kcunit);
358
0a7de745 359 return error;
fe8ab488
A
360}
361
362static errno_t
363pkt_mnglr_ctl_getopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
0a7de745 364 int opt, void *data, size_t *len)
fe8ab488
A
365{
366#pragma unused(kctlref, opt)
0a7de745 367 errno_t error = 0;
fe8ab488
A
368 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
369
370 PKT_MNGLR_LOG(LOG_NOTICE, "");
371
372 pkt_mnglr_rw_lock_shared(&pkt_mnglr_lck_rw);
373
374 if (packet_manglers == NULL) {
375 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
376 error = EINVAL;
377 goto done;
378 }
379 if (kcunit > MAX_PACKET_MANGLER) {
380 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
381 kcunit, MAX_PACKET_MANGLER);
382 error = EINVAL;
383 goto done;
384 }
385 if (p_pkt_mnglr != (void *)packet_manglers[kcunit - 1]) {
386 PKT_MNGLR_LOG(LOG_ERR, "unitinfo does not match for kcunit %u",
387 kcunit);
388 error = EINVAL;
389 goto done;
390 }
391 switch (opt) {
0a7de745
A
392 case PKT_MNGLR_OPT_PROTO_ACT_MASK:
393 if (*len < sizeof(uint32_t)) {
394 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
395 "len too small %lu", *len);
396 error = EINVAL;
397 goto done;
398 }
fe8ab488 399
0a7de745
A
400 if (data != NULL) {
401 *(uint32_t *)data = p_pkt_mnglr->proto_action_mask;
402 }
403 break;
404 case PKT_MNGLR_OPT_IP_ACT_MASK:
405 if (*len < sizeof(uint32_t)) {
406 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
407 "len too small %lu", *len);
408 error = EINVAL;
409 goto done;
410 }
fe8ab488 411
0a7de745
A
412 if (data != NULL) {
413 *(uint32_t *)data = p_pkt_mnglr->ip_action_mask;
414 }
415 break;
416 case PKT_MNGLR_OPT_LOCAL_IP:
417 if (*len < sizeof(struct sockaddr_storage)) {
418 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
419 "len too small %lu", *len);
420 error = EINVAL;
421 goto done;
422 }
fe8ab488 423
0a7de745
A
424 if (data != NULL) {
425 *(struct sockaddr_storage *)data = p_pkt_mnglr->lsaddr;
426 }
427 break;
428 case PKT_MNGLR_OPT_REMOTE_IP:
429 if (*len < sizeof(struct sockaddr_storage)) {
430 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
431 "len too small %lu", *len);
432 error = EINVAL;
433 goto done;
434 }
fe8ab488 435
0a7de745
A
436 if (data != NULL) {
437 *(struct sockaddr_storage *)data = p_pkt_mnglr->rsaddr;
438 }
439 break;
440 case PKT_MNGLR_OPT_LOCAL_PORT:
441 if (*len < sizeof(uint16_t)) {
442 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
443 "len too small %lu", *len);
444 error = EINVAL;
445 goto done;
446 }
fe8ab488 447
0a7de745
A
448 if (data != NULL) {
449 *(uint16_t *)data = p_pkt_mnglr->lport;
450 }
451 break;
452 case PKT_MNGLR_OPT_REMOTE_PORT:
453 if (*len < sizeof(uint16_t)) {
454 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
455 "len too small %lu", *len);
456 error = EINVAL;
457 goto done;
458 }
fe8ab488 459
0a7de745
A
460 if (data != NULL) {
461 *(uint16_t *)data = p_pkt_mnglr->rport;
462 }
463 break;
464 case PKT_MNGLR_OPT_DIRECTION:
465 if (*len < sizeof(uint32_t)) {
466 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
467 "len too small %lu", *len);
468 error = EINVAL;
469 goto done;
470 }
471 if (data != NULL) {
472 *(uint32_t *)data = p_pkt_mnglr->dir;
473 }
474 break;
475 case PKT_MNGLR_OPT_PROTOCOL:
476 if (*len < sizeof(uint32_t)) {
477 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
478 "len too small %lu", *len);
479 error = EINVAL;
480 goto done;
481 }
482 if (data != NULL) {
483 *(uint32_t *)data = p_pkt_mnglr->proto;
484 }
485 break;
486 case PKT_MNGLR_OPT_ACTIVATE:
487 if (*len < sizeof(uint8_t)) {
488 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
489 "len too small %lu", *len);
490 error = EINVAL;
491 goto done;
492 }
fe8ab488 493
0a7de745
A
494 if (data != NULL) {
495 *(uint8_t *)data = p_pkt_mnglr->activate;
496 }
497 break;
498 default:
499 error = ENOPROTOOPT;
500 break;
fe8ab488
A
501 }
502done:
503 pkt_mnglr_rw_unlock_shared(&pkt_mnglr_lck_rw);
504
0a7de745 505 return error;
fe8ab488
A
506}
507
508static errno_t
509pkt_mnglr_ctl_setopt(kern_ctl_ref kctlref, u_int32_t kcunit, void *unitinfo,
0a7de745 510 int opt, void *data, size_t len)
fe8ab488
A
511{
512#pragma unused(kctlref, opt)
0a7de745 513 errno_t error = 0;
fe8ab488
A
514 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)unitinfo;
515
516 PKT_MNGLR_LOG(LOG_NOTICE, "");
517
518 pkt_mnglr_rw_lock_exclusive(&pkt_mnglr_lck_rw);
519
520 if (packet_manglers == NULL) {
521 PKT_MNGLR_LOG(LOG_ERR, "no packet filter");
522 error = EINVAL;
523 goto done;
524 }
525 if (kcunit > MAX_PACKET_MANGLER) {
526 PKT_MNGLR_LOG(LOG_ERR, "kcunit %u > MAX_PACKET_MANGLER (%d)",
527 kcunit, MAX_PACKET_MANGLER);
528 error = EINVAL;
529 goto done;
530 }
531 if (p_pkt_mnglr != (void *)packet_manglers[kcunit - 1]) {
532 PKT_MNGLR_LOG(LOG_ERR, "unitinfo does not match for kcunit %u",
533 kcunit);
534 error = EINVAL;
535 goto done;
536 }
537 switch (opt) {
0a7de745
A
538 case PKT_MNGLR_OPT_PROTO_ACT_MASK:
539 if (len < sizeof(uint32_t)) {
540 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
541 "len too small %lu", len);
542 error = EINVAL;
543 goto done;
544 }
545 if (p_pkt_mnglr->proto_action_mask != 0) {
546 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTO_ACT_MASK "
547 "already set %u",
548 p_pkt_mnglr->proto_action_mask);
549 error = EINVAL;
550 goto done;
551 }
552 p_pkt_mnglr->proto_action_mask = *(uint32_t *)data;
553 PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr->proto_action_mask set to :%d", p_pkt_mnglr->proto_action_mask);
554 break;
555 case PKT_MNGLR_OPT_IP_ACT_MASK:
556 if (len < sizeof(uint32_t)) {
557 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
558 "len too small %lu", len);
559 error = EINVAL;
560 goto done;
561 }
562 if (p_pkt_mnglr->ip_action_mask != 0) {
563 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_IP_ACT_MASK "
564 "already set %u",
565 p_pkt_mnglr->ip_action_mask);
566 error = EINVAL;
567 goto done;
568 }
569 p_pkt_mnglr->ip_action_mask = *(uint32_t *)data;
570 break;
571 case PKT_MNGLR_OPT_LOCAL_IP:
572 if (len < sizeof(struct sockaddr_storage)) {
573 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
574 "len too small %lu", len);
575 error = EINVAL;
576 goto done;
577 }
578 if (p_pkt_mnglr->lsaddr.ss_family) {
579 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_IP "
580 "already set");
581 error = EINVAL;
582 goto done;
583 }
584 p_pkt_mnglr->lsaddr = *(struct sockaddr_storage *)data;
585 break;
586 case PKT_MNGLR_OPT_REMOTE_IP:
587 if (len < sizeof(struct sockaddr_storage)) {
588 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
589 "len too small %lu", len);
590 error = EINVAL;
591 goto done;
592 }
593 if (p_pkt_mnglr->rsaddr.ss_family) {
594 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_IP "
595 "already set");
596 error = EINVAL;
597 goto done;
598 }
fe8ab488 599
0a7de745
A
600 p_pkt_mnglr->rsaddr = *(struct sockaddr_storage *)data;
601 PKT_MNGLR_LOG(LOG_INFO,
602 "Remote IP registered for address family: %d",
603 p_pkt_mnglr->rsaddr.ss_family);
604 break;
605 case PKT_MNGLR_OPT_LOCAL_PORT:
606 if (len < sizeof(uint16_t)) {
607 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
608 "len too small %lu", len);
609 error = EINVAL;
610 goto done;
611 }
612 if (p_pkt_mnglr->lport != 0) {
613 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_LOCAL_PORT "
614 "already set %d",
615 p_pkt_mnglr->lport);
616 error = EINVAL;
617 goto done;
618 }
619 p_pkt_mnglr->lport = *(uint16_t *)data;
620 break;
621 case PKT_MNGLR_OPT_REMOTE_PORT:
622 if (len < sizeof(uint16_t)) {
623 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
624 "len too small %lu", len);
625 error = EINVAL;
626 goto done;
627 }
628 if (p_pkt_mnglr->rport != 0) {
629 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_REMOTE_PORT "
630 "already set %d",
631 p_pkt_mnglr->rport);
632 error = EINVAL;
633 goto done;
634 }
635 p_pkt_mnglr->rport = *(uint16_t *)data;
636 break;
637 case PKT_MNGLR_OPT_DIRECTION:
638 if (len < sizeof(uint32_t)) {
639 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
640 "len too small %lu", len);
641 error = EINVAL;
642 goto done;
643 }
644 if (p_pkt_mnglr->dir != 0) {
645 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_DIRECTION "
646 "already set %u",
647 p_pkt_mnglr->dir);
648 error = EINVAL;
649 goto done;
650 }
651 p_pkt_mnglr->dir = *(uint32_t *)data;
652 break;
653 case PKT_MNGLR_OPT_PROTOCOL:
654 if (len < sizeof(uint32_t)) {
655 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
656 "len too small %lu", len);
657 error = EINVAL;
658 goto done;
659 }
660 if (p_pkt_mnglr->proto != 0) {
661 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_PROTOCOL "
662 "already set %u",
663 p_pkt_mnglr->proto);
664 error = EINVAL;
665 goto done;
666 }
667 p_pkt_mnglr->proto = *(uint32_t *)data;
668 break;
669 case PKT_MNGLR_OPT_ACTIVATE:
670 if (len < sizeof(uint8_t)) {
671 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
672 "len too small %lu", len);
673 error = EINVAL;
674 goto done;
675 }
676 if (p_pkt_mnglr->activate != 0) {
677 PKT_MNGLR_LOG(LOG_ERR, "PKT_MNGLR_OPT_ACTIVATE "
678 "already set %u",
fe8ab488 679 p_pkt_mnglr->activate);
0a7de745
A
680 error = EINVAL;
681 goto done;
682 }
683 p_pkt_mnglr->activate = *(uint8_t *)data;
684 PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr->activate set to :%d",
685 p_pkt_mnglr->activate);
686 break;
687 default:
688 error = ENOPROTOOPT;
689 break;
fe8ab488
A
690 }
691done:
692 pkt_mnglr_rw_unlock_exclusive(&pkt_mnglr_lck_rw);
693
0a7de745 694 return error;
fe8ab488
A
695}
696
697void
698pkt_mnglr_init(void)
699{
700 struct kern_ctl_reg kern_ctl;
0a7de745 701 errno_t error = 0;
fe8ab488
A
702
703 PKT_MNGLR_LOG(LOG_NOTICE, "");
704
705 /*
706 * Compile time verifications
707 */
708 _CASSERT(PKT_MNGLR_MAX_FILTER_COUNT == MAX_PACKET_MANGLER);
709
fe8ab488
A
710 /*
711 * Allocate locks
712 */
713 pkt_mnglr_lck_grp_attr = lck_grp_attr_alloc_init();
714 if (pkt_mnglr_lck_grp_attr == NULL) {
715 panic("%s: lck_grp_attr_alloc_init failed", __func__);
716 /* NOTREACHED */
717 }
718 pkt_mnglr_lck_grp = lck_grp_alloc_init("packet manglerr",
719 pkt_mnglr_lck_grp_attr);
720 if (pkt_mnglr_lck_grp == NULL) {
721 panic("%s: lck_grp_alloc_init failed", __func__);
722 /* NOTREACHED */
723 }
724 pkt_mnglr_lck_attr = lck_attr_alloc_init();
725 if (pkt_mnglr_lck_attr == NULL) {
726 panic("%s: lck_attr_alloc_init failed", __func__);
727 /* NOTREACHED */
728 }
729 lck_rw_init(&pkt_mnglr_lck_rw, pkt_mnglr_lck_grp, pkt_mnglr_lck_attr);
730
731 /*
732 * Register kernel control
733 */
734 bzero(&kern_ctl, sizeof(kern_ctl));
735 strlcpy(kern_ctl.ctl_name, PACKET_MANGLER_CONTROL_NAME,
736 sizeof(kern_ctl.ctl_name));
737 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED | CTL_FLAG_REG_EXTENDED;
738 kern_ctl.ctl_connect = pkt_mnglr_ctl_connect;
739 kern_ctl.ctl_disconnect = pkt_mnglr_ctl_disconnect;
740 kern_ctl.ctl_getopt = pkt_mnglr_ctl_getopt;
741 kern_ctl.ctl_setopt = pkt_mnglr_ctl_setopt;
742 error = ctl_register(&kern_ctl, &pkt_mnglr_kctlref);
743 if (error != 0) {
744 PKT_MNGLR_LOG(LOG_ERR, "ctl_register failed: %d", error);
745 } else {
746 PKT_MNGLR_LOG(LOG_INFO, "Registered packet mangler kernel control.");
747 }
748}
749
0a7de745
A
750static errno_t
751pktmnglr_ipfilter_output(void *cookie, mbuf_t *data, ipf_pktopts_t options)
fe8ab488
A
752{
753 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
3e170ce0
A
754 struct ip ip;
755 struct tcphdr tcp;
fe8ab488 756 int optlen = 0;
3e170ce0 757 errno_t error = 0;
fe8ab488
A
758
759#pragma unused(tcp, optlen, options)
fe8ab488 760 if (p_pkt_mnglr == NULL) {
3e170ce0 761 goto output_done;
fe8ab488
A
762 }
763
764 if (!p_pkt_mnglr->activate) {
3e170ce0
A
765 goto output_done;
766 }
767
768 if (p_pkt_mnglr->dir == IN) {
769 goto output_done;
fe8ab488
A
770 }
771
772 if (data == NULL) {
3e170ce0
A
773 PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
774 goto output_done;
fe8ab488
A
775 }
776
3e170ce0
A
777 /* Check for IP filter options */
778 error = mbuf_copydata(*data, 0, sizeof(ip), &ip);
779 if (error) {
780 PKT_MNGLR_LOG(LOG_ERR, "Could not make local IP header copy");
781 goto output_done;
fe8ab488
A
782 }
783
3e170ce0
A
784 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip.ip_v == 4)) {
785 goto output_done;
fe8ab488
A
786 }
787
3e170ce0
A
788 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip.ip_v == 6)) {
789 goto output_done;
fe8ab488
A
790 }
791
792 if (p_pkt_mnglr->lsaddr.ss_family == AF_INET) {
793 struct sockaddr_in laddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->lsaddr));
3e170ce0
A
794 if (ip.ip_src.s_addr != laddr.sin_addr.s_addr) {
795 goto output_done;
fe8ab488
A
796 }
797 }
798
799 if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
800 struct sockaddr_in raddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->rsaddr));
3e170ce0
A
801 if (ip.ip_dst.s_addr != raddr.sin_addr.s_addr) {
802 goto output_done;
fe8ab488
A
803 }
804 }
805
3e170ce0
A
806 if (ip.ip_v != 4) {
807 PKT_MNGLR_LOG(LOG_INFO,
808 "%s:%d Not handling IP version %d\n",
5ba3f43e 809 __func__, __LINE__, ip.ip_v);
3e170ce0 810 goto output_done;
fe8ab488
A
811 }
812
3e170ce0 813output_done:
fe8ab488
A
814 /* Not handling output flow */
815 return 0;
816}
817
0a7de745 818#define TCP_MAX_OPTLEN 40
fe8ab488 819
0a7de745
A
820static errno_t
821pktmnglr_ipfilter_input(void *cookie, mbuf_t *data, int offset, u_int8_t protocol)
fe8ab488
A
822{
823 struct packet_mangler *p_pkt_mnglr = (struct packet_mangler *)cookie;
cb323159 824 struct ip6_hdr ip6;
fe8ab488
A
825 struct ip ip;
826 struct tcphdr tcp;
9d749ea3 827 int ip_pld_len;
fe8ab488
A
828 errno_t error = 0;
829
830 if (p_pkt_mnglr == NULL) {
831 PKT_MNGLR_LOG(LOG_ERR, "p_pkt_mnglr is NULL");
832 goto input_done;
833 }
834
835 if (p_pkt_mnglr->activate == 0) {
836 PKT_MNGLR_LOG(LOG_INFO, "p_pkt_mnglr not yet activated");
837 goto input_done;
838 }
839
3e170ce0 840 if (p_pkt_mnglr->dir == OUT) {
fe8ab488
A
841 goto input_done;
842 }
843
3e170ce0
A
844 if (data == NULL) {
845 PKT_MNGLR_LOG(LOG_ERR, "Data pointer is NULL");
fe8ab488
A
846 goto input_done;
847 }
848
849 /* Check for IP filter options */
850 error = mbuf_copydata(*data, 0, sizeof(ip), &ip);
851 if (error) {
852 PKT_MNGLR_LOG(LOG_ERR, "Could not make local IP header copy");
853 goto input_done;
854 }
855
cb323159
A
856 if (ip.ip_v == 6) {
857 error = mbuf_copydata(*data, 0, sizeof(ip6), &ip6);
858 if (error) {
859 PKT_MNGLR_LOG(LOG_ERR, "Could not make local IPv6 header copy");
860 goto input_done;
861 }
862 }
863
fe8ab488
A
864 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET6) && (ip.ip_v == 4)) {
865 PKT_MNGLR_LOG(LOG_INFO, "Skipping filtering as address family of packet is IPv4 but local "
866 "address is set to IPv6");
867 goto input_done;
868 }
869
870 if ((p_pkt_mnglr->lsaddr.ss_family == AF_INET) && (ip.ip_v == 6)) {
871 PKT_MNGLR_LOG(LOG_INFO, "Skipping filtering as address family "
872 "of packet is IPv6 but local address is set to IPv4");
873 goto input_done;
874 }
875
876 if (p_pkt_mnglr->lsaddr.ss_family == AF_INET) {
877 struct sockaddr_in laddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->lsaddr));
878 if (ip.ip_dst.s_addr != laddr.sin_addr.s_addr) {
879 goto input_done;
880 }
cb323159
A
881 } else if (p_pkt_mnglr->lsaddr.ss_family == AF_INET6) {
882 struct sockaddr_in6 laddr = *(struct sockaddr_in6 *)(&(p_pkt_mnglr->lsaddr));
883 if (!IN6_ARE_ADDR_EQUAL(&ip6.ip6_dst, &laddr.sin6_addr)) {
884 goto input_done;
885 }
fe8ab488
A
886 }
887
888 if (p_pkt_mnglr->rsaddr.ss_family == AF_INET) {
889 struct sockaddr_in raddr = *(struct sockaddr_in *)(&(p_pkt_mnglr->rsaddr));
890 if (ip.ip_src.s_addr != raddr.sin_addr.s_addr) {
891 goto input_done;
892 }
893 PKT_MNGLR_LOG(LOG_INFO, "Remote IP: %x Source IP: %x in input path",
894 raddr.sin_addr.s_addr,
895 ip.ip_src.s_addr);
cb323159
A
896 } else if (p_pkt_mnglr->rsaddr.ss_family == AF_INET6) {
897 struct sockaddr_in6 raddr = *(struct sockaddr_in6 *)(&(p_pkt_mnglr->rsaddr));
898 if (!IN6_ARE_ADDR_EQUAL(&ip6.ip6_src, &raddr.sin6_addr)) {
899 goto input_done;
900 }
fe8ab488
A
901 }
902
cb323159
A
903 if (ip.ip_v == 4) {
904 ip_pld_len = ntohs(ip.ip_len) - (ip.ip_hl << 2);
905 } else if (ip.ip_v == 6) {
906 if (ip6.ip6_nxt != p_pkt_mnglr->proto) {
907 /* Don't support IPv6 extension headers */
908 goto input_done;
909 }
910 ip_pld_len = ntohs(ip6.ip6_plen) + sizeof(struct ip6_hdr);
911 } else {
fe8ab488
A
912 goto input_done;
913 }
914
9d749ea3 915
fe8ab488
A
916 if (protocol != p_pkt_mnglr->proto) {
917 PKT_MNGLR_LOG(LOG_INFO, "Skip: Protocol mismatch");
918 goto input_done;
919 }
920
921 switch (protocol) {
0a7de745
A
922 case IPPROTO_TCP:
923 if (ip_pld_len < (int) sizeof(tcp)) {
924 PKT_MNGLR_LOG(LOG_ERR, "IP total len not big enough for TCP: %d", ip_pld_len);
925 goto drop_it;
926 }
fe8ab488 927
0a7de745
A
928 error = mbuf_copydata(*data, offset, sizeof(tcp), &tcp);
929 if (error) {
930 PKT_MNGLR_LOG(LOG_ERR, "Could not make local TCP header copy");
fe8ab488 931 goto input_done;
0a7de745
A
932 }
933
934 if (p_pkt_mnglr->lport && (p_pkt_mnglr->lport != tcp.th_dport)) {
935 PKT_MNGLR_LOG(LOG_INFO, "Local port and IP des port do not match");
fe8ab488 936 goto input_done;
0a7de745
A
937 }
938
939 if (p_pkt_mnglr->rport && (p_pkt_mnglr->rport != tcp.th_sport)) {
940 PKT_MNGLR_LOG(LOG_INFO, "Remote port and IP src port do not match");
fe8ab488 941 goto input_done;
0a7de745
A
942 }
943 break;
944 case IPPROTO_UDP:
945 goto input_done;
946 case IPPROTO_ICMP:
947 goto input_done;
948 case IPPROTO_ICMPV6:
949 goto input_done;
950 default:
951 goto input_done;
fe8ab488
A
952 }
953
954 /* XXX Do IP actions here */
955 PKT_MNGLR_LOG(LOG_INFO, "Proceeding with packet mangler actions on the packet");
956
957 /* Protocol actions */
958 switch (protocol) {
0a7de745
A
959 case IPPROTO_TCP:
960 if (p_pkt_mnglr->proto_action_mask) {
961 char tcp_opt_buf[TCP_MAX_OPTLEN] = {0};
962 int orig_tcp_optlen;
963 int tcp_optlen = 0;
964 int i = 0, off;
9d749ea3 965
0a7de745 966 off = (tcp.th_off << 2);
9d749ea3 967
0a7de745
A
968 if (off < (int) sizeof(struct tcphdr) || off > ip_pld_len) {
969 PKT_MNGLR_LOG(LOG_ERR, "TCP header offset is wrong: %d", off);
970 goto drop_it;
971 }
9d749ea3 972
0a7de745
A
973
974 tcp_optlen = off - sizeof(struct tcphdr);
975
976 PKT_MNGLR_LOG(LOG_INFO, "Packet from F5 is TCP\n");
977 PKT_MNGLR_LOG(LOG_INFO, "Optlen: %d\n", tcp_optlen);
978 orig_tcp_optlen = tcp_optlen;
979 if (orig_tcp_optlen) {
980 error = mbuf_copydata(*data, offset + sizeof(struct tcphdr), orig_tcp_optlen, tcp_opt_buf);
981 if (error) {
982 PKT_MNGLR_LOG(LOG_ERR, "Failed to copy tcp options: error %d offset %d optlen %d", error, offset, orig_tcp_optlen);
983 goto input_done;
fe8ab488 984 }
0a7de745 985 }
fe8ab488 986
0a7de745
A
987 while (tcp_optlen > 0) {
988 if (tcp_opt_buf[i] == 0x1) {
989 PKT_MNGLR_LOG(LOG_INFO, "Skipping NOP\n");
990 tcp_optlen--;
991 i++;
992 continue;
993 } else if ((tcp_opt_buf[i] != 0) && (tcp_opt_buf[i] != TCP_OPT_MULTIPATH_TCP)) {
994 PKT_MNGLR_LOG(LOG_INFO, "Skipping option %x\n", tcp_opt_buf[i]);
995
996 /* Minimum TCP option size is 2 */
997 if (tcp_opt_buf[i + 1] < 2) {
998 PKT_MNGLR_LOG(LOG_ERR, "Received suspicious TCP option");
999 goto drop_it;
1000 }
1001 tcp_optlen -= tcp_opt_buf[i + 1];
1002 i += tcp_opt_buf[i + 1];
1003 continue;
1004 } else if (tcp_opt_buf[i] == TCP_OPT_MULTIPATH_TCP) {
1005 int j = 0;
1006 unsigned char mptcpoptlen = tcp_opt_buf[i + 1];
1007 uint8_t sbtver = tcp_opt_buf[i + MPTCP_SBT_VER_OFFSET];
1008 uint8_t subtype = sbtver >> 4;
1009
1010 PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
1011 PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP subtype %x\n", subtype);
1012 if (subtype == MPTCP_SUBTYPE_DSS) {
1013 PKT_MNGLR_LOG(LOG_INFO, "Got DSS option\n");
1014 PKT_MNGLR_LOG(LOG_INFO, "Protocol option mask: %d\n", p_pkt_mnglr->proto_action_mask);
1015 if (p_pkt_mnglr->proto_action_mask &
1016 PKT_MNGLR_TCP_ACT_DSS_DROP) {
9d749ea3
A
1017 goto drop_it;
1018 }
0a7de745 1019 }
3e170ce0 1020
0a7de745
A
1021 PKT_MNGLR_LOG(LOG_INFO, "Got MPTCP option %x\n", tcp_opt_buf[i]);
1022 for (; j < mptcpoptlen && j < tcp_optlen; j++) {
1023 if (p_pkt_mnglr->proto_action_mask &
1024 PKT_MNGLR_TCP_ACT_NOP_MPTCP) {
1025 tcp_opt_buf[i + j] = 0x1;
fe8ab488 1026 }
fe8ab488 1027 }
0a7de745
A
1028 tcp_optlen -= mptcpoptlen;
1029 i += mptcpoptlen;
1030 } else {
1031 tcp_optlen--;
1032 i++;
fe8ab488 1033 }
0a7de745 1034 }
9d749ea3 1035
0a7de745
A
1036 if (orig_tcp_optlen) {
1037 error = mbuf_copyback(*data,
1038 offset + sizeof(struct tcphdr),
1039 orig_tcp_optlen, tcp_opt_buf, MBUF_WAITOK);
9d749ea3 1040
0a7de745
A
1041 if (error) {
1042 PKT_MNGLR_LOG(LOG_ERR,
1043 "Failed to copy tcp options back: error %d offset %d optlen %d",
1044 error, offset, orig_tcp_optlen);
1045 goto input_done;
fe8ab488
A
1046 }
1047 }
0a7de745
A
1048 }
1049 break;
1050 case IPPROTO_UDP:
1051 /* Don't handle UDP */
1052 break;
1053 case IPPROTO_ICMP:
1054 break;
1055 case IPPROTO_ICMPV6:
1056 break;
1057 default:
1058 break;
fe8ab488
A
1059 }
1060 chksm_update(*data);
1061input_done:
1062 return 0;
3e170ce0
A
1063
1064drop_it:
1065 PKT_MNGLR_LOG(LOG_INFO, "Dropping packet\n");
1066 mbuf_freem(*data);
1067 return EJUSTRETURN;
fe8ab488
A
1068}
1069
0a7de745
A
1070static void
1071pktmnglr_ipfilter_detach(void *cookie)
fe8ab488
A
1072{
1073#pragma unused(cookie)
1074 return;
1075}
1076
1077/* XXX Still need to modify this to use mbuf_copy* macros */
0a7de745
A
1078static void
1079chksm_update(mbuf_t data)
fe8ab488
A
1080{
1081 u_int16_t ip_sum;
1082 u_int16_t tsum;
1083 struct tcphdr *tcp;
d9a64523 1084 errno_t err;
fe8ab488
A
1085
1086 unsigned char *ptr = (unsigned char *)mbuf_data(data);
1087 struct ip *ip = (struct ip *)(void *)ptr;
1088 if (ip->ip_v != 4) {
1089 return;
1090 }
1091
1092 ip->ip_sum = 0;
d9a64523 1093 err = mbuf_inet_cksum(data, 0, 0, ip->ip_hl << 2, &ip_sum); // ip sum
0a7de745 1094 if (err == 0) {
d9a64523 1095 ip->ip_sum = ip_sum;
0a7de745 1096 }
fe8ab488 1097 switch (ip->ip_p) {
0a7de745
A
1098 case IPPROTO_TCP:
1099 tcp = (struct tcphdr *)(void *)(ptr + (ip->ip_hl << 2));
1100 tcp->th_sum = 0;
1101 err = mbuf_inet_cksum(data, IPPROTO_TCP, ip->ip_hl << 2,
1102 ntohs(ip->ip_len) - (ip->ip_hl << 2), &tsum);
1103 if (err == 0) {
1104 tcp->th_sum = tsum;
1105 }
1106 break;
1107 case IPPROTO_UDP:
1108 /* Don't handle UDP */
1109 break;
1110 case IPPROTO_ICMP:
1111 break;
1112 case IPPROTO_ICMPV6:
1113 break;
1114 default:
1115 break;
fe8ab488
A
1116 }
1117
1118 mbuf_clear_csum_performed(data);
1119 return;
1120}