1/*
2 * Copyright (c) 2012-2014 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/kern_control.h>
31#include <net/kpi_protocol.h>
32#include <net/kpi_interface.h>
33#include <sys/socket.h>
34#include <sys/socketvar.h>
35#include <net/if.h>
36#include <net/if_types.h>
37#include <net/bpf.h>
38#include <net/if_ipsec.h>
39#include <libkern/OSMalloc.h>
40#include <libkern/OSAtomic.h>
41#include <sys/mbuf.h>
42#include <sys/sockio.h>
43#include <netinet/in.h>
44#include <netinet/ip6.h>
45#include <netinet6/in6_var.h>
46#include <netinet6/ip6_var.h>
47#include <sys/kauth.h>
48#include <netinet6/ipsec.h>
49#include <netinet6/ipsec6.h>
50#include <netinet/ip.h>
51#include <net/flowadv.h>
52#include <net/necp.h>
53
54/* Kernel Control functions */
55static errno_t	ipsec_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
56								  void **unitinfo);
57static errno_t	ipsec_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit,
58									 void *unitinfo);
59static errno_t	ipsec_ctl_send(kern_ctl_ref kctlref, u_int32_t unit,
60							   void *unitinfo, mbuf_t m, int flags);
61static errno_t	ipsec_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
62								 int opt, void *data, size_t *len);
63static errno_t	ipsec_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
64								 int opt, void *data, size_t len);
65
66/* Network Interface functions */
67static void     ipsec_start(ifnet_t	interface);
68static errno_t	ipsec_output(ifnet_t interface, mbuf_t data);
69static errno_t	ipsec_demux(ifnet_t interface, mbuf_t data, char *frame_header,
70							protocol_family_t *protocol);
71static errno_t	ipsec_add_proto(ifnet_t interface, protocol_family_t protocol,
72								const struct ifnet_demux_desc *demux_array,
73								u_int32_t demux_count);
74static errno_t	ipsec_del_proto(ifnet_t interface, protocol_family_t protocol);
75static errno_t	ipsec_ioctl(ifnet_t interface, u_long cmd, void *data);
76static void		ipsec_detached(ifnet_t interface);
77
78/* Protocol handlers */
79static errno_t	ipsec_attach_proto(ifnet_t interface, protocol_family_t proto);
80static errno_t	ipsec_proto_input(ifnet_t interface, protocol_family_t protocol,
81								  mbuf_t m, char *frame_header);
82static errno_t ipsec_proto_pre_output(ifnet_t interface, protocol_family_t protocol,
83									  mbuf_t *packet, const struct sockaddr *dest, void *route,
84									  char *frame_type, char *link_layer_dest);
85
86static kern_ctl_ref	ipsec_kctlref;
87static u_int32_t	ipsec_family;
88static OSMallocTag	ipsec_malloc_tag;
89static SInt32		ipsec_ifcount = 0;
90
91#define IPSECQ_MAXLEN 256
92
93/* Prepend length */
94static void*
95ipsec_alloc(size_t size)
96{
97	size_t	*mem = OSMalloc(size + sizeof(size_t), ipsec_malloc_tag);
98
99	if (mem) {
100		*mem = size + sizeof(size_t);
101		mem++;
102	}
103
104	return (void*)mem;
105}
106
107static void
108ipsec_free(void *ptr)
109{
110	size_t	*size = ptr;
111	size--;
112	OSFree(size, *size, ipsec_malloc_tag);
113}
114
115errno_t
116ipsec_register_control(void)
117{
118	struct kern_ctl_reg	kern_ctl;
119	errno_t				result = 0;
120
121	/* Create a tag to allocate memory */
122	ipsec_malloc_tag = OSMalloc_Tagalloc(IPSEC_CONTROL_NAME, OSMT_DEFAULT);
123
124	/* Find a unique value for our interface family */
125	result = mbuf_tag_id_find(IPSEC_CONTROL_NAME, &ipsec_family);
126	if (result != 0) {
127		printf("ipsec_register_control - mbuf_tag_id_find_internal failed: %d\n", result);
128		return result;
129	}
130
131	bzero(&kern_ctl, sizeof(kern_ctl));
132	strlcpy(kern_ctl.ctl_name, IPSEC_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
133	kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
134	kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; /* Require root */
135	kern_ctl.ctl_sendsize = 64 * 1024;
136	kern_ctl.ctl_recvsize = 64 * 1024;
137	kern_ctl.ctl_connect = ipsec_ctl_connect;
138	kern_ctl.ctl_disconnect = ipsec_ctl_disconnect;
139	kern_ctl.ctl_send = ipsec_ctl_send;
140	kern_ctl.ctl_setopt = ipsec_ctl_setopt;
141	kern_ctl.ctl_getopt = ipsec_ctl_getopt;
142
143	result = ctl_register(&kern_ctl, &ipsec_kctlref);
144	if (result != 0) {
145		printf("ipsec_register_control - ctl_register failed: %d\n", result);
146		return result;
147	}
148
149	/* Register the protocol plumbers */
150	if ((result = proto_register_plumber(PF_INET, ipsec_family,
151										 ipsec_attach_proto, NULL)) != 0) {
152		printf("ipsec_register_control - proto_register_plumber(PF_INET, %d) failed: %d\n",
153			   ipsec_family, result);
154		ctl_deregister(ipsec_kctlref);
155		return result;
156	}
157
158	/* Register the protocol plumbers */
159	if ((result = proto_register_plumber(PF_INET6, ipsec_family,
160										 ipsec_attach_proto, NULL)) != 0) {
161		proto_unregister_plumber(PF_INET, ipsec_family);
162		ctl_deregister(ipsec_kctlref);
163		printf("ipsec_register_control - proto_register_plumber(PF_INET6, %d) failed: %d\n",
164			   ipsec_family, result);
165		return result;
166	}
167
168	return 0;
169}
170
171/* Helpers */
172int
173ipsec_interface_isvalid (ifnet_t interface)
174{
175    struct ipsec_pcb *pcb = NULL;
176
177    if (interface == NULL)
178        return 0;
179
180    pcb = ifnet_softc(interface);
181
182    if (pcb == NULL)
183        return 0;
184
185    /* When ctl disconnects, ipsec_unit is set to 0 */
186    if (pcb->ipsec_unit == 0)
187        return 0;
188
189    return 1;
190}
191
192/* Kernel control functions */
193
194static errno_t
195ipsec_ctl_connect(kern_ctl_ref		kctlref,
196				  struct sockaddr_ctl	*sac,
197				  void				**unitinfo)
198{
199	struct ifnet_init_eparams	ipsec_init;
200	struct ipsec_pcb				*pcb;
201	errno_t						result;
202	struct ifnet_stats_param 	stats;
203
204	/* kernel control allocates, interface frees */
205	pcb = ipsec_alloc(sizeof(*pcb));
206	if (pcb == NULL)
207		return ENOMEM;
208
209	/* Setup the protocol control block */
210	bzero(pcb, sizeof(*pcb));
211	*unitinfo = pcb;
212	pcb->ipsec_ctlref = kctlref;
213	pcb->ipsec_unit = sac->sc_unit;
214	pcb->ipsec_output_service_class = MBUF_SC_OAM;
215
216	printf("ipsec_ctl_connect: creating interface ipsec%d\n", pcb->ipsec_unit - 1);
217
218	/* Create the interface */
219	bzero(&ipsec_init, sizeof(ipsec_init));
220	ipsec_init.ver = IFNET_INIT_CURRENT_VERSION;
221	ipsec_init.len = sizeof (ipsec_init);
222	ipsec_init.name = "ipsec";
223	ipsec_init.start = ipsec_start;
224	ipsec_init.unit = pcb->ipsec_unit - 1;
225	ipsec_init.family = ipsec_family;
226	ipsec_init.type = IFT_OTHER;
227	ipsec_init.demux = ipsec_demux;
228	ipsec_init.add_proto = ipsec_add_proto;
229	ipsec_init.del_proto = ipsec_del_proto;
230	ipsec_init.softc = pcb;
231	ipsec_init.ioctl = ipsec_ioctl;
232	ipsec_init.detach = ipsec_detached;
233
234	result = ifnet_allocate_extended(&ipsec_init, &pcb->ipsec_ifp);
235	if (result != 0) {
236		printf("ipsec_ctl_connect - ifnet_allocate failed: %d\n", result);
237		ipsec_free(pcb);
238		return result;
239	}
240	OSIncrementAtomic(&ipsec_ifcount);
241
242	/* Set flags and additional information. */
243	ifnet_set_mtu(pcb->ipsec_ifp, 1500);
244	ifnet_set_flags(pcb->ipsec_ifp, IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT, 0xffff);
245
246	/* The interface must generate its own IPv6 LinkLocal address,
247	 * if possible following the recommendation of RFC2472 to the 64bit interface ID
248	 */
249	ifnet_set_eflags(pcb->ipsec_ifp, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
250
251	/* Reset the stats in case as the interface may have been recycled */
252	bzero(&stats, sizeof(struct ifnet_stats_param));
253	ifnet_set_stat(pcb->ipsec_ifp, &stats);
254
255	/* Attach the interface */
256	result = ifnet_attach(pcb->ipsec_ifp, NULL);
257	if (result != 0) {
258		printf("ipsec_ctl_connect - ifnet_allocate failed: %d\n", result);
259		ifnet_release(pcb->ipsec_ifp);
260		ipsec_free(pcb);
261	}
262
263	/* Attach to bpf */
264	if (result == 0)
265		bpfattach(pcb->ipsec_ifp, DLT_NULL, 4);
266
267	/* The interfaces resoures allocated, mark it as running */
268	if (result == 0)
269		ifnet_set_flags(pcb->ipsec_ifp, IFF_RUNNING, IFF_RUNNING);
270
271	return result;
272}
273
274static errno_t
275ipsec_detach_ip(ifnet_t				interface,
276				protocol_family_t	protocol,
277				socket_t			pf_socket)
278{
279	errno_t result = EPROTONOSUPPORT;
280
281	/* Attempt a detach */
282	if (protocol == PF_INET) {
283		struct ifreq	ifr;
284
285		bzero(&ifr, sizeof(ifr));
286		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
287				 ifnet_name(interface), ifnet_unit(interface));
288
289		result = sock_ioctl(pf_socket, SIOCPROTODETACH, &ifr);
290	}
291	else if (protocol == PF_INET6) {
292		struct in6_ifreq	ifr6;
293
294		bzero(&ifr6, sizeof(ifr6));
295		snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
296				 ifnet_name(interface), ifnet_unit(interface));
297
298		result = sock_ioctl(pf_socket, SIOCPROTODETACH_IN6, &ifr6);
299	}
300
301	return result;
302}
303
304static void
305ipsec_remove_address(ifnet_t				interface,
306					 protocol_family_t	protocol,
307					 ifaddr_t			address,
308					 socket_t			pf_socket)
309{
310	errno_t result = 0;
311
312	/* Attempt a detach */
313	if (protocol == PF_INET) {
314		struct ifreq	ifr;
315
316		bzero(&ifr, sizeof(ifr));
317		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
318				 ifnet_name(interface), ifnet_unit(interface));
319		result = ifaddr_address(address, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
320		if (result != 0) {
321			printf("ipsec_remove_address - ifaddr_address failed: %d", result);
322		}
323		else {
324			result = sock_ioctl(pf_socket, SIOCDIFADDR, &ifr);
325			if (result != 0) {
326				printf("ipsec_remove_address - SIOCDIFADDR failed: %d", result);
327			}
328		}
329	}
330	else if (protocol == PF_INET6) {
331		struct in6_ifreq	ifr6;
332
333		bzero(&ifr6, sizeof(ifr6));
334		snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
335				 ifnet_name(interface), ifnet_unit(interface));
336		result = ifaddr_address(address, (struct sockaddr*)&ifr6.ifr_addr,
337								sizeof(ifr6.ifr_addr));
338		if (result != 0) {
339			printf("ipsec_remove_address - ifaddr_address failed (v6): %d",
340				   result);
341		}
342		else {
343			result = sock_ioctl(pf_socket, SIOCDIFADDR_IN6, &ifr6);
344			if (result != 0) {
345				printf("ipsec_remove_address - SIOCDIFADDR_IN6 failed: %d",
346					   result);
347			}
348		}
349	}
350}
351
352static void
353ipsec_cleanup_family(ifnet_t				interface,
354					 protocol_family_t	protocol)
355{
356	errno_t		result = 0;
357	socket_t	pf_socket = NULL;
358	ifaddr_t	*addresses = NULL;
359	int			i;
360
361	if (protocol != PF_INET && protocol != PF_INET6) {
362		printf("ipsec_cleanup_family - invalid protocol family %d\n", protocol);
363		return;
364	}
365
366	/* Create a socket for removing addresses and detaching the protocol */
367	result = sock_socket(protocol, SOCK_DGRAM, 0, NULL, NULL, &pf_socket);
368	if (result != 0) {
369		if (result != EAFNOSUPPORT)
370			printf("ipsec_cleanup_family - failed to create %s socket: %d\n",
371				   protocol == PF_INET ? "IP" : "IPv6", result);
372		goto cleanup;
373	}
374
375	/* always set SS_PRIV, we want to close and detach regardless */
376	sock_setpriv(pf_socket, 1);
377
378	result = ipsec_detach_ip(interface, protocol, pf_socket);
379	if (result == 0 || result == ENXIO) {
380		/* We are done! We either detached or weren't attached. */
381		goto cleanup;
382	}
383	else if (result != EBUSY) {
384		/* Uh, not really sure what happened here... */
385		printf("ipsec_cleanup_family - ipsec_detach_ip failed: %d\n", result);
386		goto cleanup;
387	}
388
389	/*
390	 * At this point, we received an EBUSY error. This means there are
391	 * addresses attached. We should detach them and then try again.
392	 */
393	result = ifnet_get_address_list_family(interface, &addresses, protocol);
394	if (result != 0) {
395		printf("fnet_get_address_list_family(%s%d, 0xblah, %s) - failed: %d\n",
396			   ifnet_name(interface), ifnet_unit(interface),
397			   protocol == PF_INET ? "PF_INET" : "PF_INET6", result);
398		goto cleanup;
399	}
400
401	for (i = 0; addresses[i] != 0; i++) {
402		ipsec_remove_address(interface, protocol, addresses[i], pf_socket);
403	}
404	ifnet_free_address_list(addresses);
405	addresses = NULL;
406
407	/*
408	 * The addresses should be gone, we should try the remove again.
409	 */
410	result = ipsec_detach_ip(interface, protocol, pf_socket);
411	if (result != 0 && result != ENXIO) {
412		printf("ipsec_cleanup_family - ipsec_detach_ip failed: %d\n", result);
413	}
414
415cleanup:
416	if (pf_socket != NULL)
417		sock_close(pf_socket);
418
419	if (addresses != NULL)
420		ifnet_free_address_list(addresses);
421}
422
423static errno_t
424ipsec_ctl_disconnect(__unused kern_ctl_ref	kctlref,
425					 __unused u_int32_t		unit,
426					 void					*unitinfo)
427{
428	struct ipsec_pcb	*pcb = unitinfo;
429	ifnet_t			ifp = pcb->ipsec_ifp;
430	errno_t			result = 0;
431
432	pcb->ipsec_ctlref = NULL;
433	pcb->ipsec_unit = 0;
434
435	/*
436	 * We want to do everything in our power to ensure that the interface
437	 * really goes away when the socket is closed. We must remove IP/IPv6
438	 * addresses and detach the protocols. Finally, we can remove and
439	 * release the interface.
440	 */
441    key_delsp_for_ipsec_if(ifp);
442
443	ipsec_cleanup_family(ifp, AF_INET);
444	ipsec_cleanup_family(ifp, AF_INET6);
445
446	if ((result = ifnet_detach(ifp)) != 0) {
447		printf("ipsec_ctl_disconnect - ifnet_detach failed: %d\n", result);
448	}
449
450	return 0;
451}
452
453static errno_t
454ipsec_ctl_send(__unused kern_ctl_ref	kctlref,
455			   __unused u_int32_t		unit,
456			   __unused void			*unitinfo,
457			   mbuf_t                  m,
458			   __unused int			flags)
459{
460    /* Receive messages from the control socket. Currently unused. */
461    mbuf_freem(m);
462	return 0;
463}
464
465static errno_t
466ipsec_ctl_setopt(__unused kern_ctl_ref	kctlref,
467				 __unused u_int32_t		unit,
468				 void					*unitinfo,
469				 int						opt,
470				 void					*data,
471				 size_t					len)
472{
473	struct ipsec_pcb			*pcb = unitinfo;
474	errno_t					result = 0;
475
476	/* check for privileges for privileged options */
477	switch (opt) {
478		case IPSEC_OPT_FLAGS:
479		case IPSEC_OPT_EXT_IFDATA_STATS:
480		case IPSEC_OPT_SET_DELEGATE_INTERFACE:
481		case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS:
482			if (kauth_cred_issuser(kauth_cred_get()) == 0) {
483				return EPERM;
484			}
485			break;
486	}
487
488	switch (opt) {
489		case IPSEC_OPT_FLAGS:
490			if (len != sizeof(u_int32_t))
491				result = EMSGSIZE;
492			else
493				pcb->ipsec_flags = *(u_int32_t *)data;
494			break;
495
496		case IPSEC_OPT_EXT_IFDATA_STATS:
497			if (len != sizeof(int)) {
498				result = EMSGSIZE;
499				break;
500			}
501			pcb->ipsec_ext_ifdata_stats = (*(int *)data) ? 1 : 0;
502			break;
503
504		case IPSEC_OPT_INC_IFDATA_STATS_IN:
505		case IPSEC_OPT_INC_IFDATA_STATS_OUT: {
506			struct ipsec_stats_param *utsp = (struct ipsec_stats_param *)data;
507
508			if (utsp == NULL || len < sizeof(struct ipsec_stats_param)) {
509				result = EINVAL;
510				break;
511			}
512			if (!pcb->ipsec_ext_ifdata_stats) {
513				result = EINVAL;
514				break;
515			}
516			if (opt == IPSEC_OPT_INC_IFDATA_STATS_IN)
517				ifnet_stat_increment_in(pcb->ipsec_ifp, utsp->utsp_packets,
518										utsp->utsp_bytes, utsp->utsp_errors);
519			else
520				ifnet_stat_increment_out(pcb->ipsec_ifp, utsp->utsp_packets,
521										 utsp->utsp_bytes, utsp->utsp_errors);
522			break;
523		}
524
525		case IPSEC_OPT_SET_DELEGATE_INTERFACE: {
526			ifnet_t		del_ifp = NULL;
527			char            name[IFNAMSIZ];
528
529			if (len > IFNAMSIZ - 1) {
530				result = EMSGSIZE;
531				break;
532			}
533			if (len != 0) {   /* if len==0, del_ifp will be NULL causing the delegate to be removed */
534				bcopy(data, name, len);
535				name[len] = 0;
536				result = ifnet_find_by_name(name, &del_ifp);
537			}
538			if (result == 0) {
539				result = ifnet_set_delegate(pcb->ipsec_ifp, del_ifp);
540				if (del_ifp)
541					ifnet_release(del_ifp);
542			}
543			break;
544		}
545
546		case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS: {
547			if (len != sizeof(int)) {
548				result = EMSGSIZE;
549				break;
550			}
551			mbuf_svc_class_t output_service_class = so_tc2msc(*(int *)data);
552			if (output_service_class == MBUF_SC_UNSPEC) {
553				pcb->ipsec_output_service_class = MBUF_SC_OAM;
554			} else {
555				pcb->ipsec_output_service_class = output_service_class;
556			}
557			break;
558		}
559
560		default:
561			result = ENOPROTOOPT;
562			break;
563	}
564
565	return result;
566}
567
568static errno_t
569ipsec_ctl_getopt(__unused kern_ctl_ref	kctlref,
570				 __unused u_int32_t		unit,
571				 void					*unitinfo,
572				 int						opt,
573				 void					*data,
574				 size_t					*len)
575{
576	struct ipsec_pcb			*pcb = unitinfo;
577	errno_t					result = 0;
578
579	switch (opt) {
580		case IPSEC_OPT_FLAGS:
581			if (*len != sizeof(u_int32_t))
582				result = EMSGSIZE;
583			else
584				*(u_int32_t *)data = pcb->ipsec_flags;
585			break;
586
587		case IPSEC_OPT_EXT_IFDATA_STATS:
588			if (*len != sizeof(int))
589				result = EMSGSIZE;
590			else
591				*(int *)data = (pcb->ipsec_ext_ifdata_stats) ? 1 : 0;
592			break;
593
594		case IPSEC_OPT_IFNAME:
595			*len = snprintf(data, *len, "%s%d", ifnet_name(pcb->ipsec_ifp), ifnet_unit(pcb->ipsec_ifp)) + 1;
596			break;
597
598		case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS: {
599			if (*len != sizeof(int)) {
600				result = EMSGSIZE;
601				break;
602			}
603			*(int *)data = so_svc2tc(pcb->ipsec_output_service_class);
604			break;
605		}
606		default:
607			result = ENOPROTOOPT;
608			break;
609	}
610
611	return result;
612}
613
614/* Network Interface functions */
615static errno_t
616ipsec_output(ifnet_t	interface,
617             mbuf_t     data)
618{
619	struct ipsec_pcb	*pcb = ifnet_softc(interface);
620    struct ipsec_output_state ipsec_state;
621    struct route ro;
622    struct route_in6 ro6;
623    int	length;
624    struct ip *ip;
625    struct ip6_hdr *ip6;
626    struct ip_out_args ipoa;
627    struct ip6_out_args ip6oa;
628    int error = 0;
629    u_int ip_version = 0;
630    uint32_t af;
631    int flags = 0;
632    struct flowadv *adv = NULL;
633
634	// Make sure this packet isn't looping through the interface
635	if (necp_get_last_interface_index_from_packet(data) == interface->if_index) {
636		error = -1;
637		goto ipsec_output_err;
638	}
639
640	// Mark the interface so NECP can evaluate tunnel policy
641	necp_mark_packet_from_interface(data, interface);
642
643    ip = mtod(data, struct ip *);
644    ip_version = ip->ip_v;
645
646    switch (ip_version) {
647        case 4:
648            /* Tap */
649            af = AF_INET;
650            bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af));
651
652            /* Apply encryption */
653            bzero(&ipsec_state, sizeof(ipsec_state));
654            ipsec_state.m = data;
655            ipsec_state.dst = (struct sockaddr *)&ip->ip_dst;
656            bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
657
658			error = ipsec4_interface_output(&ipsec_state, interface);
659            data = ipsec_state.m;
660            if (error || data == NULL) {
661                printf("ipsec_output: ipsec4_output error %d.\n", error);
662                goto ipsec_output_err;
663            }
664
665            /* Set traffic class, set flow */
666            m_set_service_class(data, pcb->ipsec_output_service_class);
667            data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
668            data->m_pkthdr.pkt_flowid = interface->if_flowhash;
669            data->m_pkthdr.pkt_proto = ip->ip_p;
670            data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
671
672            /* Flip endian-ness for ip_output */
673            ip = mtod(data, struct ip *);
674            NTOHS(ip->ip_len);
675            NTOHS(ip->ip_off);
676
677            /* Increment statistics */
678            length = mbuf_pkthdr_len(data);
679            ifnet_stat_increment_out(interface, 1, length, 0);
680
681            /* Send to ip_output */
682            bzero(&ro, sizeof(ro));
683
684            flags = IP_OUTARGS |	/* Passing out args to specify interface */
685			IP_NOIPSEC;				/* To ensure the packet doesn't go through ipsec twice */
686
687            bzero(&ipoa, sizeof(ipoa));
688            ipoa.ipoa_flowadv.code = 0;
689            ipoa.ipoa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
690            if (ipsec_state.outgoing_if) {
691                ipoa.ipoa_boundif = ipsec_state.outgoing_if;
692                ipoa.ipoa_flags |= IPOAF_BOUND_IF;
693            }
694
695            adv = &ipoa.ipoa_flowadv;
696
697            (void) ip_output(data, NULL, &ro, flags, NULL, &ipoa);
698            data = NULL;
699
700            if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
701                error = ENOBUFS;
702                ifnet_disable_output(interface);
703            }
704
705            goto done;
706        case 6:
707            af = AF_INET6;
708            bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af));
709
710            data = ipsec6_splithdr(data);
711            ip6 = mtod(data, struct ip6_hdr *);
712
713            bzero(&ipsec_state, sizeof(ipsec_state));
714            ipsec_state.m = data;
715            ipsec_state.dst = (struct sockaddr *)&ip6->ip6_dst;
716            bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
717
718            error = ipsec6_interface_output(&ipsec_state, interface, &ip6->ip6_nxt, ipsec_state.m);
719            if (error == 0 && ipsec_state.tunneled == 4)	/* tunneled in IPv4 - packet is gone */
720				goto done;
721            data = ipsec_state.m;
722            if (error || data == NULL) {
723                printf("ipsec_output: ipsec6_output error %d.\n", error);
724                goto ipsec_output_err;
725            }
726
727            /* Set traffic class, set flow */
728            m_set_service_class(data, pcb->ipsec_output_service_class);
729            data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
730            data->m_pkthdr.pkt_flowid = interface->if_flowhash;
731            data->m_pkthdr.pkt_proto = ip6->ip6_nxt;
732            data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
733
734            /* Increment statistics */
735            length = mbuf_pkthdr_len(data);
736            ifnet_stat_increment_out(interface, 1, length, 0);
737
738            /* Send to ip6_output */
739            bzero(&ro6, sizeof(ro6));
740
741            flags = IPV6_OUTARGS;
742
743            bzero(&ip6oa, sizeof(ip6oa));
744            ip6oa.ip6oa_flowadv.code = 0;
745            ip6oa.ip6oa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
746            if (ipsec_state.outgoing_if) {
747                ip6oa.ip6oa_boundif = ipsec_state.outgoing_if;
748                ip6oa.ip6oa_flags |= IPOAF_BOUND_IF;
749            }
750
751            adv = &ip6oa.ip6oa_flowadv;
752
753            (void) ip6_output(data, NULL, &ro6, flags, NULL, NULL, &ip6oa);
754            data = NULL;
755
756            if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
757                error = ENOBUFS;
758                ifnet_disable_output(interface);
759            }
760
761            goto done;
762        default:
763            printf("ipsec_output: Received unknown packet version %d.\n", ip_version);
764            error = -1;
765            goto ipsec_output_err;
766    }
767
768done:
769    return error;
770
771ipsec_output_err:
772    if (data)
773        mbuf_freem(data);
774	goto done;
775}
776
777static void
778ipsec_start(ifnet_t	interface)
779{
780	mbuf_t data;
781
782	for (;;) {
783		if (ifnet_dequeue(interface, &data) != 0)
784			break;
785		if (ipsec_output(interface, data) != 0)
786			break;
787	}
788}
789
790/* Network Interface functions */
791static errno_t
792ipsec_demux(__unused ifnet_t	interface,
793			mbuf_t				data,
794			__unused char		*frame_header,
795			protocol_family_t	*protocol)
796{
797    struct ip *ip;
798    u_int ip_version;
799
800	while (data != NULL && mbuf_len(data) < 1) {
801		data = mbuf_next(data);
802	}
803
804	if (data == NULL)
805		return ENOENT;
806
807    ip = mtod(data, struct ip *);
808    ip_version = ip->ip_v;
809
810    switch(ip_version) {
811		case 4:
812            *protocol = PF_INET;
813			return 0;
814		case 6:
815            *protocol = PF_INET6;
816			return 0;
817		default:
818			break;
819	}
820
821	return 0;
822}
823
824static errno_t
825ipsec_add_proto(__unused ifnet_t						interface,
826				protocol_family_t						protocol,
827				__unused const struct ifnet_demux_desc	*demux_array,
828				__unused u_int32_t						demux_count)
829{
830	switch(protocol) {
831		case PF_INET:
832			return 0;
833		case PF_INET6:
834			return 0;
835		default:
836			break;
837	}
838
839	return ENOPROTOOPT;
840}
841
842static errno_t
843ipsec_del_proto(__unused ifnet_t 			interface,
844				__unused protocol_family_t	protocol)
845{
846	return 0;
847}
848
849static errno_t
850ipsec_ioctl(ifnet_t		interface,
851			u_long		command,
852			void		*data)
853{
854	errno_t	result = 0;
855
856	switch(command) {
857		case SIOCSIFMTU:
858			ifnet_set_mtu(interface, ((struct ifreq*)data)->ifr_mtu);
859			break;
860
861		case SIOCSIFFLAGS:
862			/* ifioctl() takes care of it */
863			break;
864
865		default:
866			result = EOPNOTSUPP;
867	}
868
869	return result;
870}
871
872static void
873ipsec_detached(
874			   ifnet_t	interface)
875{
876	struct ipsec_pcb	*pcb = ifnet_softc(interface);
877
878	ifnet_release(pcb->ipsec_ifp);
879	ipsec_free(pcb);
880
881	OSDecrementAtomic(&ipsec_ifcount);
882}
883
884/* Protocol Handlers */
885
886static errno_t
887ipsec_proto_input(ifnet_t interface,
888				  protocol_family_t	protocol,
889				  mbuf_t m,
890				  __unused char *frame_header)
891{
892	struct ip *ip;
893	uint32_t af = 0;
894	ip = mtod(m, struct ip *);
895	if (ip->ip_v == 4)
896		af = AF_INET;
897	else if (ip->ip_v == 6)
898		af = AF_INET6;
899
900	mbuf_pkthdr_setrcvif(m, interface);
901	bpf_tap_in(interface, DLT_NULL, m, &af, sizeof(af));
902
903	if (proto_input(protocol, m) != 0)
904		m_freem(m);
905
906	return 0;
907}
908
909static errno_t
910ipsec_proto_pre_output(__unused ifnet_t	interface,
911					   protocol_family_t	protocol,
912					   __unused mbuf_t		*packet,
913					   __unused const struct sockaddr *dest,
914					   __unused void *route,
915					   __unused char *frame_type,
916					   __unused char *link_layer_dest)
917{
918
919	*(protocol_family_t *)(void *)frame_type = protocol;
920	return 0;
921}
922
923static errno_t
924ipsec_attach_proto(ifnet_t				interface,
925				   protocol_family_t	protocol)
926{
927	struct ifnet_attach_proto_param	proto;
928	errno_t							result;
929
930	bzero(&proto, sizeof(proto));
931	proto.input = ipsec_proto_input;
932	proto.pre_output = ipsec_proto_pre_output;
933
934	result = ifnet_attach_protocol(interface, protocol, &proto);
935	if (result != 0 && result != EEXIST) {
936		printf("ipsec_attach_inet - ifnet_attach_protocol %d failed: %d\n",
937			   protocol, result);
938	}
939
940	return result;
941}
942
943errno_t
944ipsec_inject_inbound_packet(ifnet_t	interface,
945							mbuf_t packet)
946{
947	errno_t error;
948	protocol_family_t protocol;
949	if ((error = ipsec_demux(interface, packet, NULL, &protocol)) != 0) {
950		return error;
951	}
952
953	return ipsec_proto_input(interface, protocol, packet, NULL);
954}
955
956void
957ipsec_set_pkthdr_for_interface(ifnet_t interface, mbuf_t packet, int family)
958{
959	if (packet != NULL && interface != NULL) {
960		struct ipsec_pcb *pcb = ifnet_softc(interface);
961		if (pcb != NULL) {
962			/* Set traffic class, set flow */
963			m_set_service_class(packet, pcb->ipsec_output_service_class);
964			packet->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
965			packet->m_pkthdr.pkt_flowid = interface->if_flowhash;
966			if (family == AF_INET) {
967				struct ip *ip = mtod(packet, struct ip *);
968				packet->m_pkthdr.pkt_proto = ip->ip_p;
969			} else if (family == AF_INET) {
970				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
971				packet->m_pkthdr.pkt_proto = ip6->ip6_nxt;
972			}
973			packet->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
974		}
975	}
976}
977