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