]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_ipsec.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / bsd / net / if_ipsec.c
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 */
55 static errno_t ipsec_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
56 void **unitinfo);
57 static errno_t ipsec_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit,
58 void *unitinfo);
59 static errno_t ipsec_ctl_send(kern_ctl_ref kctlref, u_int32_t unit,
60 void *unitinfo, mbuf_t m, int flags);
61 static errno_t ipsec_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
62 int opt, void *data, size_t *len);
63 static 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 */
67 static void ipsec_start(ifnet_t interface);
68 static errno_t ipsec_output(ifnet_t interface, mbuf_t data);
69 static errno_t ipsec_demux(ifnet_t interface, mbuf_t data, char *frame_header,
70 protocol_family_t *protocol);
71 static 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);
74 static errno_t ipsec_del_proto(ifnet_t interface, protocol_family_t protocol);
75 static errno_t ipsec_ioctl(ifnet_t interface, u_long cmd, void *data);
76 static void ipsec_detached(ifnet_t interface);
77
78 /* Protocol handlers */
79 static errno_t ipsec_attach_proto(ifnet_t interface, protocol_family_t proto);
80 static errno_t ipsec_proto_input(ifnet_t interface, protocol_family_t protocol,
81 mbuf_t m, char *frame_header);
82 static 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
86 static kern_ctl_ref ipsec_kctlref;
87 static u_int32_t ipsec_family;
88 static OSMallocTag ipsec_malloc_tag;
89 static SInt32 ipsec_ifcount = 0;
90
91 #define IPSECQ_MAXLEN 256
92
93 /* Prepend length */
94 static void*
95 ipsec_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
107 static void
108 ipsec_free(void *ptr)
109 {
110 size_t *size = ptr;
111 size--;
112 OSFree(size, *size, ipsec_malloc_tag);
113 }
114
115 errno_t
116 ipsec_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 */
172 int
173 ipsec_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
194 static errno_t
195 ipsec_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
274 static errno_t
275 ipsec_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
304 static void
305 ipsec_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
352 static void
353 ipsec_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
415 cleanup:
416 if (pf_socket != NULL)
417 sock_close(pf_socket);
418
419 if (addresses != NULL)
420 ifnet_free_address_list(addresses);
421 }
422
423 static errno_t
424 ipsec_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
453 static errno_t
454 ipsec_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
465 static errno_t
466 ipsec_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
568 static errno_t
569 ipsec_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 */
615 static errno_t
616 ipsec_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 /* Tunneled in IPv6 - packet is gone */
660 if (error == 0 && ipsec_state.tunneled == 6) {
661 goto done;
662 }
663
664 data = ipsec_state.m;
665 if (error || data == NULL) {
666 printf("ipsec_output: ipsec4_output error %d.\n", error);
667 goto ipsec_output_err;
668 }
669
670 /* Set traffic class, set flow */
671 m_set_service_class(data, pcb->ipsec_output_service_class);
672 data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
673 data->m_pkthdr.pkt_flowid = interface->if_flowhash;
674 data->m_pkthdr.pkt_proto = ip->ip_p;
675 data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
676
677 /* Flip endian-ness for ip_output */
678 ip = mtod(data, struct ip *);
679 NTOHS(ip->ip_len);
680 NTOHS(ip->ip_off);
681
682 /* Increment statistics */
683 length = mbuf_pkthdr_len(data);
684 ifnet_stat_increment_out(interface, 1, length, 0);
685
686 /* Send to ip_output */
687 bzero(&ro, sizeof(ro));
688
689 flags = IP_OUTARGS | /* Passing out args to specify interface */
690 IP_NOIPSEC; /* To ensure the packet doesn't go through ipsec twice */
691
692 bzero(&ipoa, sizeof(ipoa));
693 ipoa.ipoa_flowadv.code = 0;
694 ipoa.ipoa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
695 if (ipsec_state.outgoing_if) {
696 ipoa.ipoa_boundif = ipsec_state.outgoing_if;
697 ipoa.ipoa_flags |= IPOAF_BOUND_IF;
698 }
699
700 adv = &ipoa.ipoa_flowadv;
701
702 (void) ip_output(data, NULL, &ro, flags, NULL, &ipoa);
703 data = NULL;
704
705 if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
706 error = ENOBUFS;
707 ifnet_disable_output(interface);
708 }
709
710 goto done;
711 case 6:
712 af = AF_INET6;
713 bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af));
714
715 data = ipsec6_splithdr(data);
716 if (data == NULL) {
717 printf("ipsec_output: ipsec6_splithdr returned NULL\n");
718 goto ipsec_output_err;
719 }
720
721 ip6 = mtod(data, struct ip6_hdr *);
722
723 bzero(&ipsec_state, sizeof(ipsec_state));
724 ipsec_state.m = data;
725 ipsec_state.dst = (struct sockaddr *)&ip6->ip6_dst;
726 bzero(&ipsec_state.ro, sizeof(ipsec_state.ro));
727
728 error = ipsec6_interface_output(&ipsec_state, interface, &ip6->ip6_nxt, ipsec_state.m);
729 if (error == 0 && ipsec_state.tunneled == 4) /* tunneled in IPv4 - packet is gone */
730 goto done;
731 data = ipsec_state.m;
732 if (error || data == NULL) {
733 printf("ipsec_output: ipsec6_output error %d.\n", error);
734 goto ipsec_output_err;
735 }
736
737 /* Set traffic class, set flow */
738 m_set_service_class(data, pcb->ipsec_output_service_class);
739 data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
740 data->m_pkthdr.pkt_flowid = interface->if_flowhash;
741 data->m_pkthdr.pkt_proto = ip6->ip6_nxt;
742 data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
743
744 /* Increment statistics */
745 length = mbuf_pkthdr_len(data);
746 ifnet_stat_increment_out(interface, 1, length, 0);
747
748 /* Send to ip6_output */
749 bzero(&ro6, sizeof(ro6));
750
751 flags = IPV6_OUTARGS;
752
753 bzero(&ip6oa, sizeof(ip6oa));
754 ip6oa.ip6oa_flowadv.code = 0;
755 ip6oa.ip6oa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR;
756 if (ipsec_state.outgoing_if) {
757 ip6oa.ip6oa_boundif = ipsec_state.outgoing_if;
758 ip6oa.ip6oa_flags |= IPOAF_BOUND_IF;
759 }
760
761 adv = &ip6oa.ip6oa_flowadv;
762
763 (void) ip6_output(data, NULL, &ro6, flags, NULL, NULL, &ip6oa);
764 data = NULL;
765
766 if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) {
767 error = ENOBUFS;
768 ifnet_disable_output(interface);
769 }
770
771 goto done;
772 default:
773 printf("ipsec_output: Received unknown packet version %d.\n", ip_version);
774 error = -1;
775 goto ipsec_output_err;
776 }
777
778 done:
779 return error;
780
781 ipsec_output_err:
782 if (data)
783 mbuf_freem(data);
784 goto done;
785 }
786
787 static void
788 ipsec_start(ifnet_t interface)
789 {
790 mbuf_t data;
791
792 for (;;) {
793 if (ifnet_dequeue(interface, &data) != 0)
794 break;
795 if (ipsec_output(interface, data) != 0)
796 break;
797 }
798 }
799
800 /* Network Interface functions */
801 static errno_t
802 ipsec_demux(__unused ifnet_t interface,
803 mbuf_t data,
804 __unused char *frame_header,
805 protocol_family_t *protocol)
806 {
807 struct ip *ip;
808 u_int ip_version;
809
810 while (data != NULL && mbuf_len(data) < 1) {
811 data = mbuf_next(data);
812 }
813
814 if (data == NULL)
815 return ENOENT;
816
817 ip = mtod(data, struct ip *);
818 ip_version = ip->ip_v;
819
820 switch(ip_version) {
821 case 4:
822 *protocol = PF_INET;
823 return 0;
824 case 6:
825 *protocol = PF_INET6;
826 return 0;
827 default:
828 break;
829 }
830
831 return 0;
832 }
833
834 static errno_t
835 ipsec_add_proto(__unused ifnet_t interface,
836 protocol_family_t protocol,
837 __unused const struct ifnet_demux_desc *demux_array,
838 __unused u_int32_t demux_count)
839 {
840 switch(protocol) {
841 case PF_INET:
842 return 0;
843 case PF_INET6:
844 return 0;
845 default:
846 break;
847 }
848
849 return ENOPROTOOPT;
850 }
851
852 static errno_t
853 ipsec_del_proto(__unused ifnet_t interface,
854 __unused protocol_family_t protocol)
855 {
856 return 0;
857 }
858
859 static errno_t
860 ipsec_ioctl(ifnet_t interface,
861 u_long command,
862 void *data)
863 {
864 errno_t result = 0;
865
866 switch(command) {
867 case SIOCSIFMTU:
868 ifnet_set_mtu(interface, ((struct ifreq*)data)->ifr_mtu);
869 break;
870
871 case SIOCSIFFLAGS:
872 /* ifioctl() takes care of it */
873 break;
874
875 default:
876 result = EOPNOTSUPP;
877 }
878
879 return result;
880 }
881
882 static void
883 ipsec_detached(
884 ifnet_t interface)
885 {
886 struct ipsec_pcb *pcb = ifnet_softc(interface);
887
888 ifnet_release(pcb->ipsec_ifp);
889 ipsec_free(pcb);
890
891 OSDecrementAtomic(&ipsec_ifcount);
892 }
893
894 /* Protocol Handlers */
895
896 static errno_t
897 ipsec_proto_input(ifnet_t interface,
898 protocol_family_t protocol,
899 mbuf_t m,
900 __unused char *frame_header)
901 {
902 struct ip *ip;
903 uint32_t af = 0;
904 ip = mtod(m, struct ip *);
905 if (ip->ip_v == 4)
906 af = AF_INET;
907 else if (ip->ip_v == 6)
908 af = AF_INET6;
909
910 mbuf_pkthdr_setrcvif(m, interface);
911 bpf_tap_in(interface, DLT_NULL, m, &af, sizeof(af));
912
913 if (proto_input(protocol, m) != 0) {
914 ifnet_stat_increment_in(interface, 0, 0, 1);
915 m_freem(m);
916 } else {
917 ifnet_stat_increment_in(interface, 1, m->m_pkthdr.len, 0);
918 }
919
920 return 0;
921 }
922
923 static errno_t
924 ipsec_proto_pre_output(__unused ifnet_t interface,
925 protocol_family_t protocol,
926 __unused mbuf_t *packet,
927 __unused const struct sockaddr *dest,
928 __unused void *route,
929 __unused char *frame_type,
930 __unused char *link_layer_dest)
931 {
932
933 *(protocol_family_t *)(void *)frame_type = protocol;
934 return 0;
935 }
936
937 static errno_t
938 ipsec_attach_proto(ifnet_t interface,
939 protocol_family_t protocol)
940 {
941 struct ifnet_attach_proto_param proto;
942 errno_t result;
943
944 bzero(&proto, sizeof(proto));
945 proto.input = ipsec_proto_input;
946 proto.pre_output = ipsec_proto_pre_output;
947
948 result = ifnet_attach_protocol(interface, protocol, &proto);
949 if (result != 0 && result != EEXIST) {
950 printf("ipsec_attach_inet - ifnet_attach_protocol %d failed: %d\n",
951 protocol, result);
952 }
953
954 return result;
955 }
956
957 errno_t
958 ipsec_inject_inbound_packet(ifnet_t interface,
959 mbuf_t packet)
960 {
961 errno_t error;
962 protocol_family_t protocol;
963 if ((error = ipsec_demux(interface, packet, NULL, &protocol)) != 0) {
964 return error;
965 }
966
967 return ipsec_proto_input(interface, protocol, packet, NULL);
968 }
969
970 void
971 ipsec_set_pkthdr_for_interface(ifnet_t interface, mbuf_t packet, int family)
972 {
973 if (packet != NULL && interface != NULL) {
974 struct ipsec_pcb *pcb = ifnet_softc(interface);
975 if (pcb != NULL) {
976 /* Set traffic class, set flow */
977 m_set_service_class(packet, pcb->ipsec_output_service_class);
978 packet->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET;
979 packet->m_pkthdr.pkt_flowid = interface->if_flowhash;
980 if (family == AF_INET) {
981 struct ip *ip = mtod(packet, struct ip *);
982 packet->m_pkthdr.pkt_proto = ip->ip_p;
983 } else if (family == AF_INET6) {
984 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
985 packet->m_pkthdr.pkt_proto = ip6->ip6_nxt;
986 }
987 packet->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC);
988 }
989 }
990 }