1/*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/systm.h>
30#include <sys/socket.h>
31#include <net/if.h>
32#include <net/if_types.h>
33#include <net/if_utun.h>
34#include <sys/mbuf.h>
35#include <netinet/in.h>
36#include <netinet6/in6_var.h>
37#include <netinet6/in6_var.h>
38#include <netinet/ip.h>
39#include <netinet/ip6.h>
40#include <netinet/ip_var.h>
41#include <net/if_utun.h>
42#include <net/if_utun_crypto_dtls.h>
43#include <net/bpf.h>
44
45extern errno_t utun_pkt_input (struct utun_pcb *pcb, mbuf_t m);
46
47static UInt32                               dtls_kpi_callbacks_inited = FALSE;
48static unsigned int                         dtls_kpi_flags = 0;
49static utun_crypto_kpi_connect_func         dtls_kpi_connect = (__typeof__(dtls_kpi_connect))NULL;
50static utun_crypto_kpi_send_func            dtls_kpi_send = (__typeof__(dtls_kpi_send))NULL;
51
52// convert this mutex to shared lock
53static UInt32             dtls_ctl_mutex_inited = FALSE;
54static lck_grp_t         *dtls_ctl_mutex_grp = NULL;
55static lck_grp_attr_t    *dtls_ctl_mutex_grp_attr = NULL;
56static lck_attr_t        *dtls_ctl_mutex_attr = NULL;
57static lck_mtx_t          dtls_ctl_mutex;
58
59#define utun_ctl_get_first_framer(ctx, inner_type) (utun_crypto_framer_t *)LIST_FIRST(&ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(inner_type)])
60#define utun_get_framer_listhead(ctx, inner_type) &ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(inner_type)]
61
62static void
63utun_ctl_clr_dtls_framer (utun_crypto_framer_t *rem_framer)
64{
65	if (!rem_framer) return;
66
67	// TOFIX: switch to BPF
68	LIST_REMOVE(rem_framer, framer_chain); // unchain the framer
69	if (rem_framer->dir == UTUN_CRYPTO_DIR_IN) {
70		if (utun_crypto_framer_state_dtls_in(rem_framer).in_pattern) {
71			utun_free(utun_crypto_framer_state_dtls_in(rem_framer).in_pattern);
72		}
73		if (utun_crypto_framer_state_dtls_in(rem_framer).in_pattern_mask) {
74			utun_free(utun_crypto_framer_state_dtls_in(rem_framer).in_pattern_mask);
75		}
76		if (utun_crypto_framer_state_dtls_in(rem_framer).in_pattern_masked) {
77			utun_free(utun_crypto_framer_state_dtls_in(rem_framer).in_pattern_masked);
78		}
79	} else {
80		if (utun_crypto_framer_state_dtls_out(rem_framer).out_pattern) {
81			utun_free(utun_crypto_framer_state_dtls_out(rem_framer).out_pattern);
82		}
83	}
84	utun_free(rem_framer);
85
86	return;
87}
88
89static void
90utun_ctl_clr_dtls_framers (utun_crypto_framer_t *first_framer)
91{
92	utun_crypto_framer_t *cur_framer, *nxt_framer;
93
94	// check framer->state.u.dtls.u.in.listhead for duplicates;
95	for (cur_framer = first_framer;
96		 cur_framer != NULL;
97		 cur_framer = nxt_framer) {
98		nxt_framer = (__typeof__(nxt_framer))LIST_NEXT(cur_framer, framer_chain);
99		utun_ctl_clr_dtls_framer(cur_framer);
100	}
101
102	return;
103}
104
105static void
106utun_ctl_clr_dtls_all_framers (utun_crypto_ctx_t *crypto_ctx)
107{
108	utun_ctl_clr_dtls_framers(utun_ctl_get_first_framer(crypto_ctx, UTUN_CRYPTO_INNER_TYPE_IPv4));
109	utun_ctl_clr_dtls_framers(utun_ctl_get_first_framer(crypto_ctx, UTUN_CRYPTO_INNER_TYPE_IPv6));
110	crypto_ctx->num_framers = 0;
111}
112
113static void
114utun_ctl_restart_dtls_framers (utun_crypto_framer_t *first_framer)
115{
116	utun_crypto_framer_t *cur_framer;
117
118	// check framer->state.u.dtls.u.in.listhead for duplicates;
119	for (cur_framer = first_framer;
120		 cur_framer != NULL;
121		 cur_framer = (__typeof__(cur_framer))LIST_NEXT(cur_framer, framer_chain)) {
122		utun_crypto_framer_state_dtls_out(cur_framer).sequence_field = utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_initval;
123	}
124
125	return;
126}
127
128static void
129utun_ctl_restart_dtls_all_framers (utun_crypto_ctx_t *crypto_ctx)
130{
131	utun_ctl_restart_dtls_framers(utun_ctl_get_first_framer(crypto_ctx, UTUN_CRYPTO_INNER_TYPE_IPv4));
132	utun_ctl_restart_dtls_framers(utun_ctl_get_first_framer(crypto_ctx, UTUN_CRYPTO_INNER_TYPE_IPv6));
133}
134
135static int
136is_pattern_all_zeroes (u_int8_t *pattern,
137					   int       pattern_len)
138{
139	int i;
140
141	if (!pattern || !pattern_len) return FALSE; // false if args are NULL
142
143	for (i = 0; i < pattern_len; i++) {
144		if (pattern[i] != 0) return FALSE;
145	}
146	return TRUE;
147}
148
149static int
150is_pattern_masked_all_zeroes (u_int8_t *pattern,
151							  u_int8_t *pattern_mask,
152							  int       pattern_len)
153{
154	int i;
155
156	if (!pattern || !pattern_mask || !pattern_len) return FALSE; // false if args are NULL
157
158	for (i = 0; i < pattern_len; i++) {
159		if ((pattern[i] & pattern_mask[i])) return FALSE;
160	}
161	return TRUE;
162}
163
164static void
165utun_ctl_calc_dtls_framer_pattern_and_mask (u_int8_t *pattern_masked, u_int8_t *pattern, u_int8_t *mask, int len)
166{
167	int i;
168	for (i = 0; i < len; i++) {
169		pattern_masked[i] = (pattern[i] & mask[i]);
170	}
171}
172
173static Boolean
174utun_ctl_did_dtls_framer_pattern_match (u_int8_t *input, u_int8_t *pattern_masked, int len)
175{
176	int i;
177	for (i = 0; i < len; i++) {
178		if ((input[i] & pattern_masked[i]) != pattern_masked[i]) return FALSE;
179	}
180	return TRUE;
181}
182
183static Boolean
184utun_pkt_dtls_input_frame_is_data(utun_crypto_ctx_t *crypto_ctx,
185				  mbuf_t            *pkt,
186				  protocol_family_t  family,
187				  int               *striplen)
188{
189	u_int8_t *p;
190	utun_crypto_framer_t *cur_framer;
191
192	p = mtod(*pkt, __typeof__(p));
193	for (cur_framer = utun_ctl_get_first_framer(crypto_ctx, utun_crypto_framer_protocol_family_to_inner_type(family));
194	     cur_framer != NULL;
195	     cur_framer = (__typeof__(cur_framer))LIST_NEXT(cur_framer, framer_chain)) {
196		if (m_pktlen(*pkt) < utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len) {
197			continue;
198		}
199		if ((*pkt)->m_len < utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len) {
200		  *pkt = m_pullup(*pkt, utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len);
201			if (!*pkt ||
202			    (*pkt)->m_len < utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len) {
203				return FALSE;
204			}
205			p = mtod(*pkt, __typeof__(p));
206		}
207		// TOFIX: switch to BPF
208		if (utun_ctl_did_dtls_framer_pattern_match(p,
209							   utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_masked,
210							   utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len)) {
211			*striplen = utun_crypto_framer_state_dtls_in(cur_framer).in_data_offset;
212			return TRUE;
213		}
214	}
215	return FALSE;
216}
217
218#define GETLONG(l, cp) {               \
219	(l) = *(cp)++ << 8;	       \
220	(l) |= *(cp)++; (l) <<= 8;     \
221	(l) |= *(cp)++; (l) <<= 8;     \
222	(l) |= *(cp)++;		       \
223  }
224#define PUTLONG(l, cp) {                \
225	*(cp)++ = (u_char) ((l) >> 24); \
226	*(cp)++ = (u_char) ((l) >> 16); \
227	*(cp)++ = (u_char) ((l) >> 8);	\
228	*(cp)++ = (u_char) (l);		\
229  }
230
231static int
232utun_pkt_dtls_output_frame_encapsulate (utun_crypto_ctx_t *crypto_ctx,
233					mbuf_t            *pkt,
234					protocol_family_t  proto)
235{
236	u_int8_t *p;
237	utun_crypto_framer_t *cur_framer;
238	u_int32_t pkt_len;
239
240	// TOFIX: switch to BPF
241
242	if (!crypto_ctx->num_framers) {
243		return 0;
244	}
245	if (proto != AF_INET && proto != AF_INET6) {
246		printf("%s: unsupported proto %d\n", __FUNCTION__, proto);
247		return EINVAL;
248	}
249
250	for (cur_framer = utun_ctl_get_first_framer(crypto_ctx, utun_crypto_framer_protocol_family_to_inner_type(proto));
251	     cur_framer != NULL && !utun_crypto_framer_state_dtls_out(cur_framer).out_pattern;
252	     cur_framer = (__typeof__(cur_framer))LIST_NEXT(cur_framer, framer_chain));
253	if (!cur_framer ||
254	    !utun_crypto_framer_state_dtls_out(cur_framer).out_pattern_len) {
255		return 0;
256	}
257
258	pkt_len = m_pktlen(*pkt);
259
260	// prepend/encapsulate the output pattern
261	if (mbuf_prepend(pkt, utun_crypto_framer_state_dtls_out(cur_framer).out_pattern_len, MBUF_DONTWAIT) != 0) {
262		printf("%s - ifnet_output prepend failed\n", __FUNCTION__);
263		return ENOBUFS;
264	}
265
266	p = mtod(*pkt, __typeof__(p));
267	memcpy(p,
268	       utun_crypto_framer_state_dtls_out(cur_framer).out_pattern,
269	       utun_crypto_framer_state_dtls_out(cur_framer).out_pattern_len);
270	// fill a "length" field... if configured
271	if (utun_crypto_framer_state_dtls_out(cur_framer).len_field_mask) {
272		u_int32_t  tmp;
273		u_int8_t  *q = p + utun_crypto_framer_state_dtls_out(cur_framer).len_field_offset;
274		GETLONG(tmp, q);
275		tmp &= ((pkt_len + utun_crypto_framer_state_dtls_out(cur_framer).len_field_extra) & utun_crypto_framer_state_dtls_out(cur_framer).len_field_mask);
276		q = p + utun_crypto_framer_state_dtls_out(cur_framer).len_field_offset;
277		PUTLONG(tmp, q);
278	}
279	// fill a "sequence" field... if configured
280	if (utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_mask) {
281		u_int32_t  tmp = (utun_crypto_framer_state_dtls_out(cur_framer).sequence_field & utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_mask);
282		u_int8_t  *q = p + utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_offset;
283		GETLONG(tmp, q);
284		tmp &= (utun_crypto_framer_state_dtls_out(cur_framer).sequence_field & utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_mask);
285		q = p + utun_crypto_framer_state_dtls_out(cur_framer).sequence_field_offset;
286		PUTLONG(tmp, q);
287		utun_crypto_framer_state_dtls_out(cur_framer).sequence_field++;
288	}
289	return 0;
290}
291
292void
293utun_ctl_init_crypto_dtls (void)
294{
295	if (OSCompareAndSwap(FALSE, TRUE, &dtls_ctl_mutex_inited)) {
296		if (!dtls_ctl_mutex_grp_attr)
297			dtls_ctl_mutex_grp_attr = lck_grp_attr_alloc_init();
298		if (!dtls_ctl_mutex_grp)
299			dtls_ctl_mutex_grp = lck_grp_alloc_init("utun-crypto", dtls_ctl_mutex_grp_attr);
300		if (!dtls_ctl_mutex_attr)
301			dtls_ctl_mutex_attr = lck_attr_alloc_init();
302
303		lck_mtx_init(&dtls_ctl_mutex, dtls_ctl_mutex_grp, dtls_ctl_mutex_attr);
304	}
305}
306
307/*
308 * Summary: registers the DTLS Kext routines with UTUN... so that UTUN can make calls into DTLS
309 */
310errno_t
311utun_ctl_register_dtls (utun_crypto_kpi_reg_t *reg)
312{
313	//printf("%s: entering\n", __FUNCTION__);
314	if (!reg) return EINVAL;
315
316	//printf("%s: type %d\n", __FUNCTION__, reg->crypto_kpi_type);
317	if (reg->crypto_kpi_type != UTUN_CRYPTO_TYPE_DTLS) {
318		return EINVAL;
319	}
320
321	if (!reg->crypto_kpi_connect) {
322		return EINVAL;
323	}
324
325	if (!reg->crypto_kpi_send) {
326		return EINVAL;
327	}
328
329	//	printf("%s: pre-value of dtls_kpi_callbacks_inited %lu\n", __FUNCTION__,
330	//       dtls_kpi_callbacks_inited);
331	if (OSCompareAndSwap(FALSE, TRUE, &dtls_kpi_callbacks_inited)) {
332		dtls_kpi_flags = reg->crypto_kpi_flags;
333		dtls_kpi_connect = reg->crypto_kpi_connect;
334		dtls_kpi_send = reg->crypto_kpi_send;
335	}
336	//printf("%s: post-value of dtls_kpi_callbacks_inited %lu\n", __FUNCTION__,
337	//       dtls_kpi_callbacks_inited);
338	return 0;
339}
340
341/*
342 * Summary: enables dtls crypto info for the specified utun. dtls ref is passed into args.
343 */
344void
345utun_ctl_enable_crypto_dtls(struct utun_pcb   *pcb, utun_crypto_args_t *args)
346{
347	utun_crypto_ctx_t *crypto_ctx;
348
349	lck_mtx_lock(&dtls_ctl_mutex);
350
351	//printf("%s: entering, flags %x, kpi-handle %x, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, pcb->utun_flags, crypto_ctx->kpi_handle, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
352
353	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_IN)];
354	if (crypto_ctx->valid) {
355		printf("%s: dtls already enabled (prev %u, now %u)\n", __FUNCTION__,
356		       crypto_ctx->kpi_handle, args->u.dtls_v1.kpi_handle);
357		lck_mtx_unlock(&dtls_ctl_mutex);
358		return;
359	}
360
361	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT)];
362	if (!crypto_ctx->valid) {
363		crypto_ctx->kpi_handle = args->u.dtls_v1.kpi_handle;
364	} else {
365		printf("%s: dtls already enabled for egress (prev %u, now %u)\n", __FUNCTION__,
366		       crypto_ctx->kpi_handle, args->u.dtls_v1.kpi_handle);
367		lck_mtx_unlock(&dtls_ctl_mutex);
368		return;
369	}
370	// crypto_ctx->valid will be set in utun_ctl_enable_crypto
371	lck_mtx_unlock(&dtls_ctl_mutex);
372	return;
373}
374
375/*
376 * Summary: disables dtls crypto info for the specified utun.
377 */
378void
379utun_ctl_disable_crypto_dtls(struct utun_pcb   *pcb)
380{
381	utun_crypto_ctx_t *crypto_ctx;
382
383	lck_mtx_lock(&dtls_ctl_mutex);
384
385	//printf("%s: entering, flags %x, kpi-handle %d, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, pcb->utun_flags, crypto_ctx->kpi_handle, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
386
387	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_IN)];
388	if (crypto_ctx->valid &&
389	    crypto_ctx->type == UTUN_CRYPTO_TYPE_DTLS) {
390		utun_ctl_clr_dtls_all_framers(crypto_ctx);
391	}
392
393	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT)];
394	if (!crypto_ctx->valid ||
395	    crypto_ctx->type != UTUN_CRYPTO_TYPE_DTLS) {
396		lck_mtx_unlock(&dtls_ctl_mutex);
397		return;
398	}
399	if (crypto_ctx->kpi_ref) {
400		if (dtls_kpi_connect) {
401			(void)dtls_kpi_connect(crypto_ctx->kpi_handle, NULL);
402			if (--crypto_ctx->kpi_refcnt == 0) {
403				crypto_ctx->kpi_ref = (__typeof__(crypto_ctx->kpi_ref))NULL;
404				crypto_ctx->kpi_handle = UTUN_CRYPTO_DTLS_HANDLE_INVALID;
405			} else {
406			  //				printf("%s: ### dtls_kpi_refcnt %d not yet zero\n",
407			  //				       __FUNCTION__, crypto_ctx->kpi_refcnt);
408			}
409		} else {
410			printf("%s: ### dtls_ctl_connect unavailable\n", __FUNCTION__);
411			lck_mtx_unlock(&dtls_ctl_mutex);
412			return;
413		}
414	} else {
415		if (crypto_ctx->kpi_handle < 0) {
416			printf("%s: dtls already disabled\n", __FUNCTION__);
417			lck_mtx_unlock(&dtls_ctl_mutex);
418			return;
419		}
420		crypto_ctx->kpi_handle = UTUN_CRYPTO_DTLS_HANDLE_INVALID;
421	}
422	utun_ctl_clr_dtls_all_framers(crypto_ctx);
423	lck_mtx_unlock(&dtls_ctl_mutex);
424	return;
425}
426
427static utun_crypto_framer_t *
428utun_ctl_get_dtls_in_framer (utun_crypto_framer_t            *first_framer,
429			     u_int8_t                        *in_pattern,
430			     int                              in_pattern_len,
431			     u_int8_t                        *in_pattern_mask,
432			     int                              in_pattern_mask_len)
433{
434	utun_crypto_framer_t *cur_framer;
435
436	// check framer->u.listhead for duplicates;
437	for (cur_framer = first_framer;
438	     cur_framer != NULL;
439	     cur_framer = (__typeof__(cur_framer))LIST_NEXT(cur_framer, framer_chain)) {
440		// TOFIX: use in_pattern_masked
441		if (utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len == in_pattern_len &&
442		    memcmp(utun_crypto_framer_state_dtls_in(cur_framer).in_pattern,
443			   in_pattern,
444			   in_pattern_len) == 0 &&
445		    utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_len == in_pattern_mask_len &&
446		    memcmp(utun_crypto_framer_state_dtls_in(cur_framer).in_pattern_mask,
447			   in_pattern_mask,
448			   in_pattern_mask_len) == 0) {
449			// found
450			return cur_framer;
451		}
452	}
453
454	return NULL;
455}
456
457errno_t
458utun_ctl_config_crypto_dtls_framer (utun_crypto_ctx_t         *crypto_ctx,
459				    utun_crypto_framer_args_t *args)
460{
461	utun_crypto_framer_t *framer, *new_framer = NULL, *dup_framer;
462
463	if (args->ver != UTUN_CRYPTO_DTLS_VER_1) {
464		return EINVAL;
465	}
466	if (!args->type || args->type >= UTUN_CRYPTO_INNER_TYPE_MAX) {
467		return EINVAL;
468	}
469
470	lck_mtx_lock(&dtls_ctl_mutex);
471
472	if (args->dir == UTUN_CRYPTO_DIR_IN) {
473		// Input framer (for tunnel hdr detection and decapsulation). there can be several pattern that identify data (vs. control) packets.
474
475		// First, the args need to be verified for errors/inconsistencies
476		// pattern and mask have to be configured
477		if (!utun_crypto_framer_args_dtls_in(args).in_pattern_len ||
478		    !utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len) {
479			lck_mtx_unlock(&dtls_ctl_mutex);
480			printf("%s: invalid dtls in-pattern %d mask %d\n", __FUNCTION__,
481			       utun_crypto_framer_args_dtls_in(args).in_pattern_len,
482			       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len);
483			return EINVAL;
484		}
485		// pattern and mask lengths have to match
486		if (utun_crypto_framer_args_dtls_in(args).in_pattern_len != utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len) {
487			lck_mtx_unlock(&dtls_ctl_mutex);
488			printf("%s: inconsistent dtls in-pattern %d mask %d\n",__FUNCTION__,
489			       utun_crypto_framer_args_dtls_in(args).in_pattern_len,
490			       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len);
491			return EINVAL;
492		}
493		// check for len inconsistencies
494		if ((u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_len + (u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len != args->varargs_buflen) {
495			lck_mtx_unlock(&dtls_ctl_mutex);
496			printf("%s: inconsistent dtls in-pattern %d mask %d, total %d\n",__FUNCTION__,
497			       utun_crypto_framer_args_dtls_in(args).in_pattern_len,
498			       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len,
499			       args->varargs_buflen);
500			return EINVAL;
501		}
502		// utun_crypto_framer_args_dtls_in(args).in_pattern should not be all zeros
503		if (is_pattern_all_zeroes(&args->varargs_buf[0],
504					  utun_crypto_framer_args_dtls_in(args).in_pattern_len)) {
505			lck_mtx_unlock(&dtls_ctl_mutex);
506			printf("%s: in-pattern is all zeros, len %d\n",__FUNCTION__,
507			       utun_crypto_framer_args_dtls_in(args).in_pattern_len);
508			return EINVAL;
509		}
510		// utun_crypto_framer_args_dtls_in(args).in_pattern_mask should not be all zeros
511		if (is_pattern_all_zeroes(&args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
512					  utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len)) {
513			lck_mtx_unlock(&dtls_ctl_mutex);
514			printf("%s: in-pattern-mask is all zeros, len %d\n",__FUNCTION__,
515			       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len);
516			return EINVAL;
517		}
518		// utun_crypto_framer_args_dtls_in(args).in_pattern & utun_crypto_framer_args_dtls_in(args).in_pattern_mask should not be zeros
519		if (is_pattern_masked_all_zeroes(&args->varargs_buf[0],
520						 &args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
521						 utun_crypto_framer_args_dtls_in(args).in_pattern_len)) {
522			lck_mtx_unlock(&dtls_ctl_mutex);
523			printf("%s: in-pattern-masked is all zeros, len %d\n",__FUNCTION__,
524			       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len);
525			return EINVAL;
526		}
527
528		// Secondly, we need to be careful about existing framer configs
529		if (!(framer = utun_ctl_get_first_framer(crypto_ctx, args->inner_type))) {
530			// no framers configured
531			if (!(framer = utun_alloc(sizeof(*framer)))) {
532				lck_mtx_unlock(&dtls_ctl_mutex);
533				return ENOBUFS;
534			}
535			bzero(framer, sizeof(*framer));
536			// fall through to fill-in the 1st framer
537		} else {
538			// at least one framer configured... check framer->u.listhead for duplicates;
539			if ((dup_framer = utun_ctl_get_dtls_in_framer(framer /* could be a list */,
540								      &args->varargs_buf[0],
541								      utun_crypto_framer_args_dtls_in(args).in_pattern_len,
542								      &args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
543								      utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len))) {
544				// duplicate
545				lck_mtx_unlock(&dtls_ctl_mutex);
546				printf("%s: ignoring duplicate framer for type %d\n",__FUNCTION__,
547				       args->inner_type);
548				return 0;
549			}
550
551			if (!(new_framer = utun_alloc(sizeof(*new_framer)))) {
552				lck_mtx_unlock(&dtls_ctl_mutex);
553				return ENOBUFS;
554			}
555			bzero(new_framer, sizeof(*new_framer));
556			framer = new_framer;
557			// fall through to fill-in additional framer
558		}
559		LIST_INSERT_HEAD(utun_get_framer_listhead(crypto_ctx, args->inner_type),
560						 new_framer,
561						 framer_chain);
562
563		framer->inner_type = args->inner_type;
564		framer->inner_protocol_family = utun_crypto_framer_inner_type_to_protocol_family(args->inner_type);
565		// allocate and fill the pattern
566		if (!(utun_crypto_framer_state_dtls_in(framer).in_pattern = utun_alloc(utun_crypto_framer_args_dtls_in(args).in_pattern_len))) {
567			utun_ctl_clr_dtls_framer(framer);
568			lck_mtx_unlock(&dtls_ctl_mutex);
569			return ENOBUFS;
570		}
571		memcpy(utun_crypto_framer_state_dtls_in(framer).in_pattern,
572		       &args->varargs_buf[0],
573		       utun_crypto_framer_args_dtls_in(args).in_pattern_len);
574		utun_crypto_framer_state_dtls_in(framer).in_pattern_len = utun_crypto_framer_args_dtls_in(args).in_pattern_len;
575
576		// allocate and fill the pattern-mask
577		if (!(utun_crypto_framer_state_dtls_in(framer).in_pattern_mask = utun_alloc(utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len))) {
578			utun_ctl_clr_dtls_framer(framer);
579			lck_mtx_unlock(&dtls_ctl_mutex);
580			return ENOBUFS;
581		}
582		memcpy(utun_crypto_framer_state_dtls_in(framer).in_pattern_mask,
583		       &args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
584		       utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len);
585		utun_crypto_framer_state_dtls_in(framer).in_data_offset = utun_crypto_framer_args_dtls_in(args).in_data_offset;
586
587		if (!(utun_crypto_framer_state_dtls_in(framer).in_pattern_masked = utun_alloc(utun_crypto_framer_args_dtls_in(args).in_pattern_len))) {
588			utun_ctl_clr_dtls_framer(framer);
589			lck_mtx_unlock(&dtls_ctl_mutex);
590			return ENOBUFS;
591		}
592		utun_ctl_calc_dtls_framer_pattern_and_mask(utun_crypto_framer_state_dtls_in(framer).in_pattern_masked,
593							   utun_crypto_framer_state_dtls_in(framer).in_pattern,
594							   utun_crypto_framer_state_dtls_in(framer).in_pattern_mask,
595							   utun_crypto_framer_state_dtls_in(framer).in_pattern_len);
596		// TOFIX: switch to BPF
597		crypto_ctx->num_framers++;
598	} else {
599		// Output Framer (for tunnel hdr encapsulation)... there can only be one for each type of traffic (see caller of this function)
600
601		// pattern and mask have to be configured
602		if (!utun_crypto_framer_args_dtls_out(args).out_pattern_len) {
603			lck_mtx_unlock(&dtls_ctl_mutex);
604			printf("%s: invalid output framer, len %d\n",__FUNCTION__,
605			       utun_crypto_framer_args_dtls_out(args).out_pattern_len);
606			return EINVAL;
607		}
608		// utun_crypto_framer_args_dtls_out(args).out_pattern should not be all zeros;
609		if (is_pattern_all_zeroes(&args->varargs_buf[0],
610					  utun_crypto_framer_args_dtls_out(args).out_pattern_len)) {
611			lck_mtx_unlock(&dtls_ctl_mutex);
612			printf("%s: zeroed output framer, len %d\n",__FUNCTION__,
613			       utun_crypto_framer_args_dtls_out(args).out_pattern_len);
614			return EINVAL;
615		}
616
617		// can't have the offset/extra configured while the mask is cleared
618		if ((utun_crypto_framer_args_dtls_out(args).len_field_offset || utun_crypto_framer_args_dtls_out(args).len_field_extra) && !utun_crypto_framer_args_dtls_out(args).len_field_mask) {
619			lck_mtx_unlock(&dtls_ctl_mutex);
620			printf("%s: output framer has invalid length-field %d,%d,%x\n",__FUNCTION__,
621			       (int)utun_crypto_framer_args_dtls_out(args).len_field_offset,
622			       (int)utun_crypto_framer_args_dtls_out(args).len_field_extra,
623			       utun_crypto_framer_args_dtls_out(args).len_field_mask);
624			return EINVAL;
625		}
626		// any length field should be within the bounds of the out-pattern
627		if (utun_crypto_framer_args_dtls_out(args).len_field_offset >= utun_crypto_framer_args_dtls_out(args).out_pattern_len) {
628			lck_mtx_unlock(&dtls_ctl_mutex);
629			return EINVAL;
630		}
631
632		// can't have the offset configured while the mask is cleared
633		if ((utun_crypto_framer_args_dtls_out(args).sequence_field || utun_crypto_framer_args_dtls_out(args).sequence_field_offset) && !utun_crypto_framer_args_dtls_out(args).sequence_field_mask) {
634			lck_mtx_unlock(&dtls_ctl_mutex);
635			printf("%s: output framer has invalid sequence-field %d,%d,%x\n",__FUNCTION__,
636			       (int)utun_crypto_framer_args_dtls_out(args).sequence_field,
637			       (int)utun_crypto_framer_args_dtls_out(args).sequence_field_offset,
638			       utun_crypto_framer_args_dtls_out(args).sequence_field_mask);
639			return EINVAL;
640		}
641		// any sequence field should be within the bounds of the out-pattern
642		if (utun_crypto_framer_args_dtls_out(args).sequence_field_offset >= utun_crypto_framer_args_dtls_out(args).out_pattern_len) {
643			lck_mtx_unlock(&dtls_ctl_mutex);
644			return EINVAL;
645		}
646
647		// check for len inconsistencies
648		if ((u_int32_t)utun_crypto_framer_args_dtls_out(args).out_pattern_len != args->varargs_buflen) {
649			lck_mtx_unlock(&dtls_ctl_mutex);
650			return EINVAL;
651		}
652
653		if (!(framer = utun_ctl_get_first_framer(crypto_ctx, args->inner_type))) {
654			if (!(framer = utun_alloc(sizeof(*framer)))) {
655				lck_mtx_unlock(&dtls_ctl_mutex);
656				return ENOBUFS;
657			}
658			bzero(framer, sizeof(*framer));
659			LIST_INSERT_HEAD(utun_get_framer_listhead(crypto_ctx, args->inner_type),
660							 new_framer,
661							 framer_chain);
662			// fall through to fill-in 1st framer
663		} else {
664			// only one outbound framer may be configured.. is it a dup?
665			if (framer->inner_type == args->inner_type &&
666			    utun_crypto_framer_state_dtls_out(framer).out_pattern_len == utun_crypto_framer_args_dtls_out(args).out_pattern_len &&
667			    utun_crypto_framer_state_dtls_out(framer).out_pattern &&
668			    memcmp(utun_crypto_framer_state_dtls_out(framer).out_pattern,
669				   &args->varargs_buf[0],
670				   utun_crypto_framer_args_dtls_out(args).out_pattern_len) == 0) {
671				// found
672				lck_mtx_unlock(&dtls_ctl_mutex);
673				return 0;
674			}
675
676			// overwrite the previous one
677			if (utun_crypto_framer_state_dtls_out(framer).out_pattern) {
678				utun_free(utun_crypto_framer_state_dtls_out(framer).out_pattern);
679			}
680			// fall through to fill-in additional framer
681		}
682
683		framer->inner_type = args->inner_type;
684		framer->inner_protocol_family = utun_crypto_framer_inner_type_to_protocol_family(args->inner_type);
685
686		// alloc and fill in the out-pattern
687		if (!(utun_crypto_framer_state_dtls_out(framer).out_pattern = utun_alloc(utun_crypto_framer_args_dtls_out(args).out_pattern_len))) {
688			utun_ctl_clr_dtls_framer(framer);
689			lck_mtx_unlock(&dtls_ctl_mutex);
690			return ENOBUFS;
691		}
692		memcpy(utun_crypto_framer_state_dtls_out(framer).out_pattern,
693		       &args->varargs_buf[0],
694		       utun_crypto_framer_args_dtls_out(args).out_pattern_len);
695		utun_crypto_framer_state_dtls_out(framer).out_pattern_len = utun_crypto_framer_args_dtls_out(args).out_pattern_len;
696
697		utun_crypto_framer_state_dtls_out(framer).len_field_mask = utun_crypto_framer_args_dtls_out(args).len_field_mask;
698		utun_crypto_framer_state_dtls_out(framer).len_field_offset = utun_crypto_framer_args_dtls_out(args).len_field_offset;
699		utun_crypto_framer_state_dtls_out(framer).len_field_extra = utun_crypto_framer_args_dtls_out(args).len_field_extra;
700		utun_crypto_framer_state_dtls_out(framer).sequence_field_initval = utun_crypto_framer_args_dtls_out(args).sequence_field;
701		utun_crypto_framer_state_dtls_out(framer).sequence_field_mask = utun_crypto_framer_args_dtls_out(args).sequence_field_mask;
702		utun_crypto_framer_state_dtls_out(framer).sequence_field_offset = utun_crypto_framer_args_dtls_out(args).sequence_field_offset;
703		crypto_ctx->num_framers = 1;
704	}
705	framer->type = args->type;
706	framer->dir = args->dir;
707	framer->valid = 1;
708
709	lck_mtx_unlock(&dtls_ctl_mutex);
710	return 0;
711}
712
713int
714utun_ctl_unconfig_crypto_dtls_framer (utun_crypto_ctx_t         *crypto_ctx,
715				      utun_crypto_framer_args_t *args)
716{
717	utun_crypto_framer_t *framer, *rem_framer;
718
719	if (args->ver != UTUN_CRYPTO_DTLS_VER_1) {
720		return EINVAL;
721	}
722	if (!args->type || args->type >= UTUN_CRYPTO_INNER_TYPE_MAX) {
723		return EINVAL;
724	}
725
726	lck_mtx_lock(&dtls_ctl_mutex);
727
728	if (args->dir == UTUN_CRYPTO_DIR_IN) {
729		if (!utun_crypto_framer_args_dtls_in(args).in_pattern_len) {
730			// no pattern means... clear all
731			utun_ctl_clr_dtls_framers(utun_ctl_get_first_framer(crypto_ctx, args->inner_type));
732			lck_mtx_unlock(&dtls_ctl_mutex);
733			return 0;
734		}
735
736		// when both specified, pattern and mask lengths have to match
737		if (utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len &&
738		    utun_crypto_framer_args_dtls_in(args).in_pattern_len != utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len) {
739			lck_mtx_unlock(&dtls_ctl_mutex);
740			return EINVAL;
741		}
742		// check for len inconsistencies
743		if ((u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_len + (u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len != args->varargs_buflen) {
744			lck_mtx_unlock(&dtls_ctl_mutex);
745			return EINVAL;
746		}
747		// utun_crypto_framer_args_dtls_in(args).in_pattern should not be all zeros
748		if (is_pattern_all_zeroes(&args->varargs_buf[0],
749					  utun_crypto_framer_args_dtls_in(args).in_pattern_len)) {
750			lck_mtx_unlock(&dtls_ctl_mutex);
751			return EINVAL;
752		}
753		// when specified, utun_crypto_framer_args_dtls_in(args).in_pattern_mask should not be all zeros
754		if (utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len &&
755		    is_pattern_all_zeroes(&args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
756					  utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len)) {
757			lck_mtx_unlock(&dtls_ctl_mutex);
758			return EINVAL;
759		}
760		// utun_crypto_framer_args_dtls_in(args).in_pattern & utun_crypto_framer_args_dtls_in(args).in_pattern_mask should not be zeros
761		if (is_pattern_masked_all_zeroes(&args->varargs_buf[0],
762						 &args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
763						 utun_crypto_framer_args_dtls_in(args).in_pattern_len)) {
764			lck_mtx_unlock(&dtls_ctl_mutex);
765			return EINVAL;
766		}
767
768		if ((u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_len + (u_int32_t)utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len != args->varargs_buflen) {
769			lck_mtx_unlock(&dtls_ctl_mutex);
770			return EINVAL;
771		}
772
773		if (!(framer = utun_ctl_get_first_framer(crypto_ctx, args->inner_type))) {
774			// no framers
775			printf("%s: no framers configured\n", __FUNCTION__);
776			lck_mtx_unlock(&dtls_ctl_mutex);
777			return 0;
778		} else {
779			if ((rem_framer = utun_ctl_get_dtls_in_framer(framer,
780								      &args->varargs_buf[0],
781								      utun_crypto_framer_args_dtls_in(args).in_pattern_len,
782								      &args->varargs_buf[utun_crypto_framer_args_dtls_in(args).in_pattern_len],
783								      utun_crypto_framer_args_dtls_in(args).in_pattern_mask_len))) {
784				utun_ctl_clr_dtls_framer(rem_framer);
785				if (crypto_ctx->num_framers) crypto_ctx->num_framers--;
786			} else {
787				printf("%s: no matching ingress framer\n", __FUNCTION__);
788			}
789			lck_mtx_unlock(&dtls_ctl_mutex);
790			return 0;
791		}
792	} else {
793		framer = utun_ctl_get_first_framer(crypto_ctx, args->inner_type);
794		// overwrite the previous one
795		if (framer) {
796			if (framer->inner_type != args->inner_type ||
797				(utun_crypto_framer_args_dtls_out(args).out_pattern_len &&
798				 utun_crypto_framer_state_dtls_out(framer).out_pattern_len != utun_crypto_framer_args_dtls_out(args).out_pattern_len) ||
799				(utun_crypto_framer_args_dtls_out(args).out_pattern_len &&
800				 memcmp(utun_crypto_framer_state_dtls_out(framer).out_pattern,
801						&args->varargs_buf[0],
802						utun_crypto_framer_args_dtls_out(args).out_pattern_len))) {
803					printf("%s: no matching egress framer\n", __FUNCTION__);
804					lck_mtx_unlock(&dtls_ctl_mutex);
805					return EBADF;
806			}
807			utun_ctl_clr_dtls_framer(framer);
808			if (crypto_ctx->num_framers) crypto_ctx->num_framers--;
809		}
810	}
811
812	lck_mtx_unlock(&dtls_ctl_mutex);
813	return 0;
814}
815
816/*
817 * Summary: enables handling of data traffic
818 */
819void
820utun_ctl_start_datatraffic_crypto_dtls(struct utun_pcb   *pcb)
821{
822	utun_crypto_ctx_t *crypto_ctx;
823
824	lck_mtx_lock(&dtls_ctl_mutex);
825
826	//printf("%s: entering, flags %x, kpi-handle %d, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, pcb->utun_flags, crypto_ctx->kpi_handle, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
827
828	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT)];
829
830	if (crypto_ctx->kpi_handle < 0) {
831		printf("%s: dtls disabled\n", __FUNCTION__);
832		lck_mtx_unlock(&dtls_ctl_mutex);
833		return;
834	}
835
836	if (!crypto_ctx->kpi_ref) {
837		if (dtls_kpi_connect) {
838			crypto_ctx->kpi_ref = dtls_kpi_connect(crypto_ctx->kpi_handle, pcb);
839			if (!crypto_ctx->kpi_ref) {
840				printf("%s: ### dtls_kpi_connect failed\n", __FUNCTION__);
841				lck_mtx_unlock(&dtls_ctl_mutex);
842				return;
843			}
844			crypto_ctx->kpi_refcnt++;
845		} else {
846			printf("%s: ### dtls_kpi_connect unavailable\n", __FUNCTION__);
847			lck_mtx_unlock(&dtls_ctl_mutex);
848			return;
849		}
850	} else {
851		printf("%s: dtls already stitched\n", __FUNCTION__);
852		lck_mtx_unlock(&dtls_ctl_mutex);
853		return;
854	}
855	utun_ctl_restart_dtls_all_framers(crypto_ctx); // for dynamic egress hdrs
856
857	//printf("%s: leaving, flags %x, kpi-handle %d, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, pcb->utun_flags, crypto_ctx->kpi_handle, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
858	lck_mtx_unlock(&dtls_ctl_mutex);
859	return;
860}
861
862/*
863 * Summary: disables handling of data traffic
864 */
865void
866utun_ctl_stop_datatraffic_crypto_dtls(struct utun_pcb   *pcb)
867{
868	utun_crypto_ctx_t *crypto_ctx;
869
870	lck_mtx_lock(&dtls_ctl_mutex);
871
872	//printf("%s: entering, flags %x, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, pcb->utun_flags, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
873
874	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT)];
875
876	if (crypto_ctx->kpi_ref) {
877		if (dtls_kpi_connect) {
878			(void)dtls_kpi_connect(crypto_ctx->kpi_handle, NULL);
879			if (--crypto_ctx->kpi_refcnt == 0) {
880				crypto_ctx->kpi_ref = (__typeof__(crypto_ctx->kpi_ref))NULL;
881				crypto_ctx->kpi_handle = UTUN_CRYPTO_DTLS_HANDLE_INVALID;
882			} else {
883			  //				printf("%s: ### dtls_kpi_refcnt %d not yet zero\n",
884			  //				       __FUNCTION__, crypto_ctx->kpi_refcnt);
885			}
886		} else {
887			printf("%s: dtls_kpi_connect unavailable\n", __FUNCTION__);
888			lck_mtx_unlock(&dtls_ctl_mutex);
889			return;
890		}
891	} else {
892		printf("%s: dtls already not-stitched\n", __FUNCTION__);
893		lck_mtx_unlock(&dtls_ctl_mutex);
894		return;
895	}
896	lck_mtx_unlock(&dtls_ctl_mutex);
897	return;
898}
899
900#define utun_pkt_dtls_prepend_proto(pkt, pf) do {                               \
901		if (mbuf_prepend(pkt, sizeof(protocol_family_t), MBUF_DONTWAIT) != 0) { \
902			printf("%s - ifnet_output prepend failed\n", __FUNCTION__);         \
903			lck_mtx_unlock(&dtls_ctl_mutex);                                    \
904			return EBADF;                                                       \
905		}                                                                       \
906		*(protocol_family_t *)mbuf_data(*pkt) = pf;                             \
907	} while(0);
908
909#define utun_pkt_dtls_puntup(pcb, pkt, errstr, rc) do {                                                 \
910		*(protocol_family_t *)mbuf_data(*pkt) = htonl(*(protocol_family_t *)mbuf_data(*pkt));           \
911		rc = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, *pkt, CTL_DATA_EOR);                     \
912		if (rc != 0) {                                                                                  \
913			printf("%s: - ctl_enqueuembuf failed (rc %d) for %s:\n", __FUNCTION__, rc, (char *)errstr); \
914			mbuf_freem(*pkt);                                                                           \
915			ifnet_stat_increment_out(pcb->utun_ifp, 0, 0, 1);                                           \
916			lck_mtx_unlock(&dtls_ctl_mutex);                                                            \
917			return 0;                                                                                   \
918		}                                                                                               \
919		*pkt = NULL;                                                                                    \
920	} while(0);
921
922int
923utun_pkt_dtls_output(struct utun_pcb *pcb, mbuf_t *pkt)
924{
925	errno_t            rc = ENETUNREACH;
926	int                len;
927	utun_crypto_ctx_t *crypto_ctx;
928	protocol_family_t  proto;
929
930	//printf("%s: entering, flags %x, ifp %p\n", __FUNCTION__, pcb->utun_flags, pcb->utun_ifp);
931
932	if (!(pcb->utun_flags & UTUN_FLAGS_CRYPTO)) {
933		printf("%s - crypto disabled\n", __FUNCTION__);
934		return EINVAL;
935	}
936
937	if (!pcb->utun_ifp) {
938		printf("%s - utun ifp cleared\n", __FUNCTION__);
939		return EINVAL;
940	}
941
942	proto = *(mtod(*pkt, protocol_family_t *));
943
944	lck_mtx_lock(&dtls_ctl_mutex);
945
946	len = mbuf_pkthdr_len(*pkt);
947
948	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT)];
949
950	//printf("%s: entering, kpi-handle %d, kpi-ref %p, kpi-refcnt %d\n", __FUNCTION__, crypto_ctx->kpi_handle, crypto_ctx->kpi_ref, crypto_ctx->kpi_refcnt);
951
952	if (dtls_kpi_send && (crypto_ctx->kpi_handle >= 0) && crypto_ctx->kpi_ref) {
953		m_adj(*pkt, sizeof(protocol_family_t));
954
955		if (!(rc = utun_pkt_dtls_output_frame_encapsulate(crypto_ctx, pkt, proto))) {
956			rc = dtls_kpi_send(crypto_ctx->kpi_ref, pkt);
957			if (rc) {
958				printf("%s: DTLS failed to send pkt %d\n", __FUNCTION__, rc);
959				// <rdar://problem/11385397>
960				// dtls_kpi_send (by way of so_inject_data_out) frees mbuf during certain error cases,
961				ifnet_stat_increment_out(pcb->utun_ifp, 0, 0, 1); // increment errors
962				lck_mtx_unlock(&dtls_ctl_mutex);
963				return 0; // and drop packet
964			}
965		} else if (rc == EINVAL) {
966			// unsupported proto... fall through and punt (but 1st undo the protocol strip)
967			utun_pkt_dtls_prepend_proto(pkt, proto);
968			utun_pkt_dtls_puntup(pcb, pkt, (char *)"unsupported proto", rc);
969		} else {
970			// mbuf_prepend failure... mbuf will be already freed
971			printf("%s: failed to encrypsulate and send pkt %d\n", __FUNCTION__,rc);
972			ifnet_stat_increment_out(pcb->utun_ifp, 0, 0, 1); // increment errors
973			lck_mtx_unlock(&dtls_ctl_mutex);
974			return 0; // and drop packet
975		}
976	} else {
977		utun_pkt_dtls_puntup(pcb, pkt, (char *)"slowpath", rc);
978	}
979
980	if (!rc)
981		ifnet_stat_increment_out(pcb->utun_ifp, 1, len, 0);
982
983	lck_mtx_unlock(&dtls_ctl_mutex);
984	return rc;
985}
986
987int
988utun_pkt_dtls_input(struct utun_pcb *pcb, mbuf_t *pkt, __unused protocol_family_t family)
989{
990	utun_crypto_ctx_t *crypto_ctx;
991	int                striplen = 0;
992
993	//printf("%s: got pkt %d\n", __FUNCTION__,family);
994	if (!(pcb->utun_flags & UTUN_FLAGS_CRYPTO)) {
995		printf("%s - crypto disabled\n", __FUNCTION__);
996		return EINVAL;
997	}
998
999	if (!pcb->utun_ifp) {
1000		printf("%s - utun ifp cleared\n", __FUNCTION__);
1001		return EINVAL;
1002	}
1003
1004	lck_mtx_lock(&dtls_ctl_mutex);
1005
1006	/*
1007	 * make sure that family matches what the UTUN was configured for (punt those that don't... along with all that fail to match the data pattern.
1008	 */
1009	crypto_ctx = &pcb->utun_crypto_ctx[UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_IN)];
1010	if (crypto_ctx->num_framers &&
1011	    !utun_pkt_dtls_input_frame_is_data(crypto_ctx, pkt, AF_INET, &striplen) &&
1012	    !utun_pkt_dtls_input_frame_is_data(crypto_ctx, pkt, AF_INET6, &striplen)) {
1013		// control or unknown traffic, so punt up to the plugin
1014		errno_t rc;
1015
1016		utun_pkt_dtls_prepend_proto(pkt, family);
1017		*(protocol_family_t *)mbuf_data(*pkt) = htonl(*(protocol_family_t *)mbuf_data(*pkt));
1018		rc = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, *pkt, CTL_DATA_EOR);
1019		if (rc != 0) {
1020			// drop packet
1021	  		printf("%s: - ctl_enqueuembuf failed: %d\n", __FUNCTION__, rc);
1022			mbuf_freem(*pkt);
1023			lck_mtx_unlock(&dtls_ctl_mutex);
1024			return rc;
1025		}
1026		printf("%s: - ctl_enqueuembuf punted a packet up to UTUN ctrl sock: %d\n", __FUNCTION__, rc);
1027		ifnet_stat_increment_in(pcb->utun_ifp, 1, mbuf_pkthdr_len(*pkt), 0);
1028
1029		*pkt = NULL;
1030		lck_mtx_unlock(&dtls_ctl_mutex);
1031		return 0;
1032	}
1033	if (striplen) {
1034		//printf("%s: - about to strip tunneled hdr of len %d\n", __FUNCTION__, striplen);
1035		m_adj(*pkt, striplen);
1036	}
1037
1038	utun_pkt_dtls_prepend_proto(pkt, family);
1039
1040	ifnet_stat_increment_in(pcb->utun_ifp, 1, mbuf_pkthdr_len(*pkt), 0);
1041
1042	(void)utun_pkt_input(pcb, *pkt);
1043	lck_mtx_unlock(&dtls_ctl_mutex);
1044	return 0;
1045}
1046