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