]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_ipsec.c
xnu-2422.115.4.tar.gz
[apple/xnu.git] / bsd / net / if_ipsec.c
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 */
53 static errno_t ipsec_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
54 void **unitinfo);
55 static errno_t ipsec_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit,
56 void *unitinfo);
57 static errno_t ipsec_ctl_send(kern_ctl_ref kctlref, u_int32_t unit,
58 void *unitinfo, mbuf_t m, int flags);
59 static errno_t ipsec_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
60 int opt, void *data, size_t *len);
61 static 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 */
65 static void ipsec_start(ifnet_t interface);
66 static errno_t ipsec_output(ifnet_t interface, mbuf_t data);
67 static errno_t ipsec_demux(ifnet_t interface, mbuf_t data, char *frame_header,
68 protocol_family_t *protocol);
69 static 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);
72 static errno_t ipsec_del_proto(ifnet_t interface, protocol_family_t protocol);
73 static errno_t ipsec_ioctl(ifnet_t interface, u_long cmd, void *data);
74 static void ipsec_detached(ifnet_t interface);
75
76 /* Protocol handlers */
77 static errno_t ipsec_attach_proto(ifnet_t interface, protocol_family_t proto);
78 static errno_t ipsec_proto_input(ifnet_t interface, protocol_family_t protocol,
79 mbuf_t m, char *frame_header);
80 static 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
84 static kern_ctl_ref ipsec_kctlref;
85 static u_int32_t ipsec_family;
86 static OSMallocTag ipsec_malloc_tag;
87 static SInt32 ipsec_ifcount = 0;
88
89 #define IPSECQ_MAXLEN 256
90
91 /* Prepend length */
92 static void*
93 ipsec_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
105 static void
106 ipsec_free(void *ptr)
107 {
108 size_t *size = ptr;
109 size--;
110 OSFree(size, *size, ipsec_malloc_tag);
111 }
112
113 errno_t
114 ipsec_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 */
170 int
171 ipsec_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
192 static errno_t
193 ipsec_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
272 static errno_t
273 ipsec_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
302 static void
303 ipsec_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
350 static void
351 ipsec_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
413 cleanup:
414 if (pf_socket != NULL)
415 sock_close(pf_socket);
416
417 if (addresses != NULL)
418 ifnet_free_address_list(addresses);
419 }
420
421 static errno_t
422 ipsec_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
451 static errno_t
452 ipsec_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
463 static errno_t
464 ipsec_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
551 static errno_t
552 ipsec_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 */
590 static errno_t
591 ipsec_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
762 done:
763 if (sp != NULL) {
764 key_freesp(sp, KEY_SADB_UNLOCKED);
765 }
766 return error;
767
768 ipsec_output_err:
769 if (data)
770 mbuf_freem(data);
771 goto done;
772 }
773
774 static void
775 ipsec_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 */
787 static errno_t
788 ipsec_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
820 static errno_t
821 ipsec_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
838 static errno_t
839 ipsec_del_proto(__unused ifnet_t interface,
840 __unused protocol_family_t protocol)
841 {
842 return 0;
843 }
844
845 static errno_t
846 ipsec_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
868 static void
869 ipsec_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
882 static errno_t
883 ipsec_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
894 static errno_t
895 ipsec_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
908 static errno_t
909 ipsec_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 }