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