2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
35 #include <net/if_types.h>
37 #include <net/if_ipsec.h>
38 #include <libkern/OSMalloc.h>
39 #include <libkern/OSAtomic.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>
52 /* Kernel Control functions */
53 static errno_t
ipsec_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
,
55 static errno_t
ipsec_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t unit
,
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
);
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
);
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
);
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;
89 #define IPSECQ_MAXLEN 256
93 ipsec_alloc(size_t size
)
95 size_t *mem
= OSMalloc(size
+ sizeof(size_t), ipsec_malloc_tag
);
98 *mem
= size
+ sizeof(size_t);
106 ipsec_free(void *ptr
)
110 OSFree(size
, *size
, ipsec_malloc_tag
);
114 ipsec_register_control(void)
116 struct kern_ctl_reg kern_ctl
;
119 /* Create a tag to allocate memory */
120 ipsec_malloc_tag
= OSMalloc_Tagalloc(IPSEC_CONTROL_NAME
, OSMT_DEFAULT
);
122 /* Find a unique value for our interface family */
123 result
= mbuf_tag_id_find(IPSEC_CONTROL_NAME
, &ipsec_family
);
125 printf("ipsec_register_control - mbuf_tag_id_find_internal failed: %d\n", result
);
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
;
141 result
= ctl_register(&kern_ctl
, &ipsec_kctlref
);
143 printf("ipsec_register_control - ctl_register failed: %d\n", result
);
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
);
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
);
171 ipsec_interface_isvalid (ifnet_t interface
)
173 struct ipsec_pcb
*pcb
= NULL
;
175 if (interface
== NULL
)
178 pcb
= ifnet_softc(interface
);
183 /* When ctl disconnects, ipsec_unit is set to 0 */
184 if (pcb
->ipsec_unit
== 0)
190 /* Kernel control functions */
193 ipsec_ctl_connect(kern_ctl_ref kctlref
,
194 struct sockaddr_ctl
*sac
,
197 struct ifnet_init_eparams ipsec_init
;
198 struct ipsec_pcb
*pcb
;
200 struct ifnet_stats_param stats
;
202 /* kernel control allocates, interface frees */
203 pcb
= ipsec_alloc(sizeof(*pcb
));
207 /* Setup the protocol control block */
208 bzero(pcb
, sizeof(*pcb
));
210 pcb
->ipsec_ctlref
= kctlref
;
211 pcb
->ipsec_unit
= sac
->sc_unit
;
213 printf("ipsec_ctl_connect: creating interface ipsec%d\n", pcb
->ipsec_unit
- 1);
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
;
232 result
= ifnet_allocate_extended(&ipsec_init
, &pcb
->ipsec_ifp
);
234 printf("ipsec_ctl_connect - ifnet_allocate failed: %d\n", result
);
238 OSIncrementAtomic(&ipsec_ifcount
);
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);
244 /* The interface must generate its own IPv6 LinkLocal address,
245 * if possible following the recommendation of RFC2472 to the 64bit interface ID
247 ifnet_set_eflags(pcb
->ipsec_ifp
, IFEF_NOAUTOIPV6LL
, IFEF_NOAUTOIPV6LL
);
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
);
253 /* Attach the interface */
254 result
= ifnet_attach(pcb
->ipsec_ifp
, NULL
);
256 printf("ipsec_ctl_connect - ifnet_allocate failed: %d\n", result
);
257 ifnet_release(pcb
->ipsec_ifp
);
263 bpfattach(pcb
->ipsec_ifp
, DLT_NULL
, 4);
265 /* The interfaces resoures allocated, mark it as running */
267 ifnet_set_flags(pcb
->ipsec_ifp
, IFF_RUNNING
, IFF_RUNNING
);
273 ipsec_detach_ip(ifnet_t interface
,
274 protocol_family_t protocol
,
277 errno_t result
= EPROTONOSUPPORT
;
279 /* Attempt a detach */
280 if (protocol
== PF_INET
) {
283 bzero(&ifr
, sizeof(ifr
));
284 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d",
285 ifnet_name(interface
), ifnet_unit(interface
));
287 result
= sock_ioctl(pf_socket
, SIOCPROTODETACH
, &ifr
);
289 else if (protocol
== PF_INET6
) {
290 struct in6_ifreq ifr6
;
292 bzero(&ifr6
, sizeof(ifr6
));
293 snprintf(ifr6
.ifr_name
, sizeof(ifr6
.ifr_name
), "%s%d",
294 ifnet_name(interface
), ifnet_unit(interface
));
296 result
= sock_ioctl(pf_socket
, SIOCPROTODETACH_IN6
, &ifr6
);
303 ipsec_remove_address(ifnet_t interface
,
304 protocol_family_t protocol
,
310 /* Attempt a detach */
311 if (protocol
== PF_INET
) {
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
));
319 printf("ipsec_remove_address - ifaddr_address failed: %d", result
);
322 result
= sock_ioctl(pf_socket
, SIOCDIFADDR
, &ifr
);
324 printf("ipsec_remove_address - SIOCDIFADDR failed: %d", result
);
328 else if (protocol
== PF_INET6
) {
329 struct in6_ifreq ifr6
;
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
));
337 printf("ipsec_remove_address - ifaddr_address failed (v6): %d",
341 result
= sock_ioctl(pf_socket
, SIOCDIFADDR_IN6
, &ifr6
);
343 printf("ipsec_remove_address - SIOCDIFADDR_IN6 failed: %d",
351 ipsec_cleanup_family(ifnet_t interface
,
352 protocol_family_t protocol
)
355 socket_t pf_socket
= NULL
;
356 ifaddr_t
*addresses
= NULL
;
359 if (protocol
!= PF_INET
&& protocol
!= PF_INET6
) {
360 printf("ipsec_cleanup_family - invalid protocol family %d\n", protocol
);
364 /* Create a socket for removing addresses and detaching the protocol */
365 result
= sock_socket(protocol
, SOCK_DGRAM
, 0, NULL
, NULL
, &pf_socket
);
367 if (result
!= EAFNOSUPPORT
)
368 printf("ipsec_cleanup_family - failed to create %s socket: %d\n",
369 protocol
== PF_INET
? "IP" : "IPv6", result
);
373 /* always set SS_PRIV, we want to close and detach regardless */
374 sock_setpriv(pf_socket
, 1);
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. */
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
);
388 * At this point, we received an EBUSY error. This means there are
389 * addresses attached. We should detach them and then try again.
391 result
= ifnet_get_address_list_family(interface
, &addresses
, protocol
);
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
);
399 for (i
= 0; addresses
[i
] != 0; i
++) {
400 ipsec_remove_address(interface
, protocol
, addresses
[i
], pf_socket
);
402 ifnet_free_address_list(addresses
);
406 * The addresses should be gone, we should try the remove again.
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
);
414 if (pf_socket
!= NULL
)
415 sock_close(pf_socket
);
417 if (addresses
!= NULL
)
418 ifnet_free_address_list(addresses
);
422 ipsec_ctl_disconnect(__unused kern_ctl_ref kctlref
,
423 __unused u_int32_t unit
,
426 struct ipsec_pcb
*pcb
= unitinfo
;
427 ifnet_t ifp
= pcb
->ipsec_ifp
;
430 pcb
->ipsec_ctlref
= NULL
;
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.
439 key_delsp_for_ipsec_if(ifp
);
441 ipsec_cleanup_family(ifp
, AF_INET
);
442 ipsec_cleanup_family(ifp
, AF_INET6
);
444 if ((result
= ifnet_detach(ifp
)) != 0) {
445 printf("ipsec_ctl_disconnect - ifnet_detach failed: %d\n", result
);
452 ipsec_ctl_send(__unused kern_ctl_ref kctlref
,
453 __unused u_int32_t unit
,
454 __unused
void *unitinfo
,
458 /* Receive messages from the control socket. Currently unused. */
464 ipsec_ctl_setopt(__unused kern_ctl_ref kctlref
,
465 __unused u_int32_t unit
,
471 struct ipsec_pcb
*pcb
= unitinfo
;
474 /* check for privileges for privileged options */
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) {
486 case IPSEC_OPT_FLAGS
:
487 if (len
!= sizeof(u_int32_t
))
490 pcb
->ipsec_flags
= *(u_int32_t
*)data
;
493 case IPSEC_OPT_EXT_IFDATA_STATS
:
494 if (len
!= sizeof(int)) {
498 pcb
->ipsec_ext_ifdata_stats
= (*(int *)data
) ? 1 : 0;
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
;
505 if (utsp
== NULL
|| len
< sizeof(struct ipsec_stats_param
)) {
509 if (!pcb
->ipsec_ext_ifdata_stats
) {
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
);
517 ifnet_stat_increment_out(pcb
->ipsec_ifp
, utsp
->utsp_packets
,
518 utsp
->utsp_bytes
, utsp
->utsp_errors
);
522 case IPSEC_OPT_SET_DELEGATE_INTERFACE
: {
523 ifnet_t del_ifp
= NULL
;
526 if (len
> IFNAMSIZ
- 1) {
530 if (len
!= 0) { /* if len==0, del_ifp will be NULL causing the delegate to be removed */
531 bcopy(data
, name
, len
);
533 result
= ifnet_find_by_name(name
, &del_ifp
);
536 result
= ifnet_set_delegate(pcb
->ipsec_ifp
, del_ifp
);
538 ifnet_release(del_ifp
);
544 result
= ENOPROTOOPT
;
552 ipsec_ctl_getopt(__unused kern_ctl_ref kctlref
,
553 __unused u_int32_t unit
,
559 struct ipsec_pcb
*pcb
= unitinfo
;
563 case IPSEC_OPT_FLAGS
:
564 if (*len
!= sizeof(u_int32_t
))
567 *(u_int32_t
*)data
= pcb
->ipsec_flags
;
570 case IPSEC_OPT_EXT_IFDATA_STATS
:
571 if (*len
!= sizeof(int))
574 *(int *)data
= (pcb
->ipsec_ext_ifdata_stats
) ? 1 : 0;
577 case IPSEC_OPT_IFNAME
:
578 *len
= snprintf(data
, *len
, "%s%d", ifnet_name(pcb
->ipsec_ifp
), ifnet_unit(pcb
->ipsec_ifp
)) + 1;
582 result
= ENOPROTOOPT
;
589 /* Network Interface functions */
591 ipsec_output(ifnet_t interface
,
594 struct ipsec_pcb
*pcb
= ifnet_softc(interface
);
595 struct ipsec_output_state ipsec_state
;
597 struct route_in6 ro6
;
601 struct secpolicy
*sp
= NULL
;
602 struct ip_out_args ipoa
;
603 struct ip6_out_args ip6oa
;
605 u_int ip_version
= 0;
608 int out_interface_index
= 0;
609 struct flowadv
*adv
= NULL
;
611 uint32_t policy_id
= 0;
613 /* Find policy using ID in mbuf */
614 policy_id
= data
->m_pkthdr
.ipsec_policy
;
615 sp
= key_getspbyid(policy_id
);
618 printf("ipsec_output: No policy specified, dropping packet.\n");
619 goto ipsec_output_err
;
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
;
628 ip
= mtod(data
, struct ip
*);
629 ip_version
= ip
->ip_v
;
631 switch (ip_version
) {
635 bpf_tap_out(pcb
->ipsec_ifp
, DLT_NULL
, data
, &af
, sizeof(af
));
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
));
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
;
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
);
657 /* Flip endian-ness for ip_output */
658 ip
= mtod(data
, struct ip
*);
662 /* Increment statistics */
663 length
= mbuf_pkthdr_len(data
);
664 ifnet_stat_increment_out(interface
, 1, length
, 0);
666 /* Send to ip_output */
667 bzero(&ro
, sizeof(ro
));
669 flags
= IP_OUTARGS
| /* Passing out args to specify interface */
670 IP_NOIPSEC
; /* To ensure the packet doesn't go through ipsec twice */
672 if (sp
->outgoing_if
!= NULL
) {
673 out_interface_index
= sp
->outgoing_if
->if_index
;
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
;
684 adv
= &ipoa
.ipoa_flowadv
;
686 (void) ip_output(data
, NULL
, &ro
, flags
, NULL
, &ipoa
);
689 if (adv
->code
== FADV_FLOW_CONTROLLED
|| adv
->code
== FADV_SUSPENDED
) {
691 ifnet_disable_output(interface
);
697 bpf_tap_out(pcb
->ipsec_ifp
, DLT_NULL
, data
, &af
, sizeof(af
));
699 ip6
= mtod(data
, struct ip6_hdr
*);
701 u_char
*nexthdrp
= &ip6
->ip6_nxt
;
702 struct mbuf
*mprev
= data
;
704 int needipsectun
= 0;
705 error
= ipsec6_output_trans(&ipsec_state
, nexthdrp
, mprev
, sp
, flags
, &needipsectun
);
707 error
= ipsec6_output_tunnel(&ipsec_state
, sp
, flags
);
708 if (ipsec_state
.tunneled
== 4) /* tunneled in IPv4 - packet is gone */
711 data
= ipsec_state
.m
;
712 if (error
|| data
== NULL
) {
713 printf("ipsec_output: ipsec6_output error.\n");
714 goto ipsec_output_err
;
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
);
724 /* Increment statistics */
725 length
= mbuf_pkthdr_len(data
);
726 ifnet_stat_increment_out(interface
, 1, length
, 0);
728 /* Send to ip6_output */
729 bzero(&ro6
, sizeof(ro6
));
731 flags
= IPV6_OUTARGS
;
733 if (sp
->outgoing_if
!= NULL
) {
734 out_interface_index
= sp
->outgoing_if
->if_index
;
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
;
745 adv
= &ip6oa
.ip6oa_flowadv
;
747 (void) ip6_output(data
, NULL
, &ro6
, flags
, NULL
, NULL
, &ip6oa
);
750 if (adv
->code
== FADV_FLOW_CONTROLLED
|| adv
->code
== FADV_SUSPENDED
) {
752 ifnet_disable_output(interface
);
757 printf("ipsec_output: Received unknown packet version %d.\n", ip_version
);
759 goto ipsec_output_err
;
764 key_freesp(sp
, KEY_SADB_UNLOCKED
);
775 ipsec_start(ifnet_t interface
)
780 if (ifnet_dequeue(interface
, &data
) != 0)
782 (void) ipsec_output(interface
, data
);
786 /* Network Interface functions */
788 ipsec_demux(__unused ifnet_t interface
,
790 __unused
char *frame_header
,
791 protocol_family_t
*protocol
)
796 while (data
!= NULL
&& mbuf_len(data
) < 1) {
797 data
= mbuf_next(data
);
803 ip
= mtod(data
, struct ip
*);
804 ip_version
= ip
->ip_v
;
811 *protocol
= PF_INET6
;
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
)
839 ipsec_del_proto(__unused ifnet_t interface
,
840 __unused protocol_family_t protocol
)
846 ipsec_ioctl(ifnet_t interface
,
854 ifnet_set_mtu(interface
, ((struct ifreq
*)data
)->ifr_mtu
);
858 /* ifioctl() takes care of it */
872 struct ipsec_pcb
*pcb
= ifnet_softc(interface
);
874 ifnet_release(pcb
->ipsec_ifp
);
877 OSDecrementAtomic(&ipsec_ifcount
);
880 /* Protocol Handlers */
883 ipsec_proto_input(__unused ifnet_t interface
,
884 protocol_family_t protocol
,
886 __unused
char *frame_header
)
888 if (proto_input(protocol
, m
) != 0)
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
)
904 *(protocol_family_t
*)(void *)frame_type
= protocol
;
909 ipsec_attach_proto(ifnet_t interface
,
910 protocol_family_t protocol
)
912 struct ifnet_attach_proto_param proto
;
915 bzero(&proto
, sizeof(proto
));
916 proto
.input
= ipsec_proto_input
;
917 proto
.pre_output
= ipsec_proto_pre_output
;
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",