]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_ipsec.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / bsd / net / if_ipsec.c
CommitLineData
39236c6e 1/*
fe8ab488 2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
39236c6e
A
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>
fe8ab488 34#include <sys/socketvar.h>
39236c6e
A
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>
fe8ab488 52#include <net/necp.h>
39236c6e
A
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));
fe8ab488 132 strlcpy(kern_ctl.ctl_name, IPSEC_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
39236c6e
A
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;
fe8ab488 214 pcb->ipsec_output_service_class = MBUF_SC_OAM;
39236c6e
A
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";
fe8ab488 223 ipsec_init.start = ipsec_start;
39236c6e
A
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:
fe8ab488 481 case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS:
39236c6e
A
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
fe8ab488
A
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
39236c6e
A
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
fe8ab488
A
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 }
39236c6e
A
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;
39236c6e
A
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;
fe8ab488 631 int flags = 0;
39236c6e
A
632 struct flowadv *adv = NULL;
633
fe8ab488
A
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);
39236c6e 642
39236c6e
A
643 ip = mtod(data, struct ip *);
644 ip_version = ip->ip_v;
fe8ab488 645
39236c6e
A
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;
fe8ab488 655 ipsec_state.dst = (struct sockaddr *)&ip->ip_dst;
39236c6e
A
656 bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
657
fe8ab488 658 error = ipsec4_interface_output(&ipsec_state, interface);
39236c6e
A
659 data = ipsec_state.m;
660 if (error || data == NULL) {
fe8ab488 661 printf("ipsec_output: ipsec4_output error %d.\n", error);
39236c6e
A
662 goto ipsec_output_err;
663 }
664
fe8ab488
A
665 /* Set traffic class, set flow */
666 m_set_service_class(data, pcb->ipsec_output_service_class);
39236c6e
A
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
fe8ab488
A
684 flags = IP_OUTARGS | /* Passing out args to specify interface */
685 IP_NOIPSEC; /* To ensure the packet doesn't go through ipsec twice */
39236c6e
A
686
687 bzero(&ipoa, sizeof(ipoa));
688 ipoa.ipoa_flowadv.code = 0;
689 ipoa.ipoa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
fe8ab488
A
690 if (ipsec_state.outgoing_if) {
691 ipoa.ipoa_boundif = ipsec_state.outgoing_if;
39236c6e
A
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
fe8ab488 710 data = ipsec6_splithdr(data);
39236c6e 711 ip6 = mtod(data, struct ip6_hdr *);
fe8ab488
A
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));
39236c6e 717
fe8ab488
A
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;
39236c6e
A
721 data = ipsec_state.m;
722 if (error || data == NULL) {
fe8ab488 723 printf("ipsec_output: ipsec6_output error %d.\n", error);
39236c6e
A
724 goto ipsec_output_err;
725 }
726
fe8ab488
A
727 /* Set traffic class, set flow */
728 m_set_service_class(data, pcb->ipsec_output_service_class);
39236c6e
A
729 data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
730 data->m_pkthdr.pkt_flowid = interface->if_flowhash;
fe8ab488 731 data->m_pkthdr.pkt_proto = ip6->ip6_nxt;
39236c6e
A
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
39236c6e
A
743 bzero(&ip6oa, sizeof(ip6oa));
744 ip6oa.ip6oa_flowadv.code = 0;
745 ip6oa.ip6oa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
fe8ab488
A
746 if (ipsec_state.outgoing_if) {
747 ip6oa.ip6oa_boundif = ipsec_state.outgoing_if;
39236c6e
A
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:
39236c6e
A
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{
fe8ab488
A
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 }
39236c6e
A
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
fe8ab488 887ipsec_proto_input(ifnet_t interface,
39236c6e 888 protocol_family_t protocol,
fe8ab488
A
889 mbuf_t m,
890 __unused char *frame_header)
39236c6e 891{
fe8ab488
A
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
39236c6e
A
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}
fe8ab488
A
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}