]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_utun.c
xnu-2422.115.4.tar.gz
[apple/xnu.git] / bsd / net / if_utun.c
CommitLineData
b0d623f7 1/*
39236c6e 2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30
31/* ----------------------------------------------------------------------------------
32Application of kernel control for interface creation
33
34Theory of operation:
35utun (user tunnel) acts as glue between kernel control sockets and network interfaces.
36This kernel control will register an interface for every client that connects.
37---------------------------------------------------------------------------------- */
38
39#include <sys/systm.h>
40#include <sys/kern_control.h>
41#include <net/kpi_protocol.h>
42#include <net/kpi_interface.h>
43#include <sys/socket.h>
44#include <net/if.h>
45#include <net/if_types.h>
46#include <net/bpf.h>
47#include <net/if_utun.h>
48#include <libkern/OSMalloc.h>
49#include <libkern/OSAtomic.h>
50#include <sys/mbuf.h>
51#include <sys/sockio.h>
52#include <netinet/in.h>
53#include <netinet6/in6_var.h>
54#include <netinet6/in6_var.h>
55#include <sys/kauth.h>
56
57
58/* Kernel Control functions */
59static errno_t utun_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
60 void **unitinfo);
61static errno_t utun_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit,
62 void *unitinfo);
63static errno_t utun_ctl_send(kern_ctl_ref kctlref, u_int32_t unit,
64 void *unitinfo, mbuf_t m, int flags);
65static errno_t utun_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
66 int opt, void *data, size_t *len);
67static errno_t utun_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
68 int opt, void *data, size_t len);
69
70/* Network Interface functions */
71static errno_t utun_output(ifnet_t interface, mbuf_t data);
72static errno_t utun_demux(ifnet_t interface, mbuf_t data, char *frame_header,
73 protocol_family_t *protocol);
39236c6e
A
74static errno_t utun_framer(ifnet_t interface, mbuf_t *packet,
75 const struct sockaddr *dest, const char *desk_linkaddr,
76 const char *frame_type, u_int32_t *prepend_len, u_int32_t *postpend_len);
b0d623f7
A
77static errno_t utun_add_proto(ifnet_t interface, protocol_family_t protocol,
78 const struct ifnet_demux_desc *demux_array,
79 u_int32_t demux_count);
80static errno_t utun_del_proto(ifnet_t interface, protocol_family_t protocol);
81static errno_t utun_ioctl(ifnet_t interface, u_long cmd, void *data);
82static void utun_detached(ifnet_t interface);
83
84/* Protocol handlers */
85static errno_t utun_attach_proto(ifnet_t interface, protocol_family_t proto);
86static errno_t utun_proto_input(ifnet_t interface, protocol_family_t protocol,
87 mbuf_t m, char *frame_header);
88static errno_t utun_proto_pre_output(ifnet_t interface, protocol_family_t protocol,
89 mbuf_t *packet, const struct sockaddr *dest, void *route,
90 char *frame_type, char *link_layer_dest);
316670eb 91__private_extern__ errno_t utun_pkt_input (struct utun_pcb *pcb, mbuf_t m);
b0d623f7
A
92
93static kern_ctl_ref utun_kctlref;
94static u_int32_t utun_family;
95static OSMallocTag utun_malloc_tag;
96static SInt32 utun_ifcount = 0;
97
98/* Prepend length */
316670eb 99void*
b0d623f7
A
100utun_alloc(size_t size)
101{
102 size_t *mem = OSMalloc(size + sizeof(size_t), utun_malloc_tag);
103
104 if (mem) {
105 *mem = size + sizeof(size_t);
106 mem++;
107 }
108
109 return (void*)mem;
110}
111
316670eb 112void
b0d623f7
A
113utun_free(void *ptr)
114{
115 size_t *size = ptr;
116 size--;
117 OSFree(size, *size, utun_malloc_tag);
118}
119
120errno_t
121utun_register_control(void)
122{
123 struct kern_ctl_reg kern_ctl;
124 errno_t result = 0;
125
126 /* Create a tag to allocate memory */
127 utun_malloc_tag = OSMalloc_Tagalloc(UTUN_CONTROL_NAME, OSMT_DEFAULT);
128
129 /* Find a unique value for our interface family */
130 result = mbuf_tag_id_find(UTUN_CONTROL_NAME, &utun_family);
131 if (result != 0) {
132 printf("utun_register_control - mbuf_tag_id_find_internal failed: %d\n", result);
133 return result;
134 }
135
136 bzero(&kern_ctl, sizeof(kern_ctl));
137 strncpy(kern_ctl.ctl_name, UTUN_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
138 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
139 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; /* Require root */
39236c6e
A
140 kern_ctl.ctl_sendsize = 512 * 1024;
141 kern_ctl.ctl_recvsize = 512 * 1024;
b0d623f7
A
142 kern_ctl.ctl_connect = utun_ctl_connect;
143 kern_ctl.ctl_disconnect = utun_ctl_disconnect;
144 kern_ctl.ctl_send = utun_ctl_send;
145 kern_ctl.ctl_setopt = utun_ctl_setopt;
146 kern_ctl.ctl_getopt = utun_ctl_getopt;
39236c6e
A
147
148 utun_ctl_init_crypto();
149
b0d623f7
A
150 result = ctl_register(&kern_ctl, &utun_kctlref);
151 if (result != 0) {
152 printf("utun_register_control - ctl_register failed: %d\n", result);
153 return result;
154 }
155
156 /* Register the protocol plumbers */
157 if ((result = proto_register_plumber(PF_INET, utun_family,
158 utun_attach_proto, NULL)) != 0) {
159 printf("utun_register_control - proto_register_plumber(PF_INET, %d) failed: %d\n",
160 utun_family, result);
161 ctl_deregister(utun_kctlref);
162 return result;
163 }
164
165 /* Register the protocol plumbers */
166 if ((result = proto_register_plumber(PF_INET6, utun_family,
167 utun_attach_proto, NULL)) != 0) {
168 proto_unregister_plumber(PF_INET, utun_family);
169 ctl_deregister(utun_kctlref);
170 printf("utun_register_control - proto_register_plumber(PF_INET6, %d) failed: %d\n",
171 utun_family, result);
172 return result;
173 }
174
175 return 0;
176}
177
178/* Kernel control functions */
179
180static errno_t
181utun_ctl_connect(
182 kern_ctl_ref kctlref,
183 struct sockaddr_ctl *sac,
184 void **unitinfo)
185{
39236c6e 186 struct ifnet_init_eparams utun_init;
b0d623f7
A
187 struct utun_pcb *pcb;
188 errno_t result;
d1ecb069 189 struct ifnet_stats_param stats;
b0d623f7
A
190
191 /* kernel control allocates, interface frees */
192 pcb = utun_alloc(sizeof(*pcb));
193 if (pcb == NULL)
194 return ENOMEM;
195
196 /* Setup the protocol control block */
197 bzero(pcb, sizeof(*pcb));
198 *unitinfo = pcb;
d1ecb069
A
199 pcb->utun_ctlref = kctlref;
200 pcb->utun_unit = sac->sc_unit;
b0d623f7 201
d1ecb069 202 printf("utun_ctl_connect: creating interface utun%d\n", pcb->utun_unit - 1);
b0d623f7
A
203
204 /* Create the interface */
205 bzero(&utun_init, sizeof(utun_init));
39236c6e
A
206 utun_init.ver = IFNET_INIT_CURRENT_VERSION;
207 utun_init.len = sizeof (utun_init);
208 utun_init.flags = IFNET_INIT_LEGACY;
b0d623f7 209 utun_init.name = "utun";
d1ecb069 210 utun_init.unit = pcb->utun_unit - 1;
b0d623f7
A
211 utun_init.family = utun_family;
212 utun_init.type = IFT_OTHER;
213 utun_init.output = utun_output;
214 utun_init.demux = utun_demux;
39236c6e 215 utun_init.framer_extended = utun_framer;
b0d623f7
A
216 utun_init.add_proto = utun_add_proto;
217 utun_init.del_proto = utun_del_proto;
218 utun_init.softc = pcb;
219 utun_init.ioctl = utun_ioctl;
220 utun_init.detach = utun_detached;
221
39236c6e 222 result = ifnet_allocate_extended(&utun_init, &pcb->utun_ifp);
b0d623f7
A
223 if (result != 0) {
224 printf("utun_ctl_connect - ifnet_allocate failed: %d\n", result);
225 utun_free(pcb);
226 return result;
227 }
228 OSIncrementAtomic(&utun_ifcount);
229
230 /* Set flags and additional information. */
d1ecb069
A
231 ifnet_set_mtu(pcb->utun_ifp, 1500);
232 ifnet_set_flags(pcb->utun_ifp, IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT, 0xffff);
b0d623f7
A
233
234 /* The interface must generate its own IPv6 LinkLocal address,
235 * if possible following the recommendation of RFC2472 to the 64bit interface ID
236 */
d1ecb069 237 ifnet_set_eflags(pcb->utun_ifp, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
b0d623f7 238
d1ecb069
A
239 /* Reset the stats in case as the interface may have been recycled */
240 bzero(&stats, sizeof(struct ifnet_stats_param));
241 ifnet_set_stat(pcb->utun_ifp, &stats);
242
b0d623f7 243 /* Attach the interface */
d1ecb069 244 result = ifnet_attach(pcb->utun_ifp, NULL);
b0d623f7
A
245 if (result != 0) {
246 printf("utun_ctl_connect - ifnet_allocate failed: %d\n", result);
d1ecb069 247 ifnet_release(pcb->utun_ifp);
b0d623f7
A
248 utun_free(pcb);
249 }
250
251 /* Attach to bpf */
252 if (result == 0)
d1ecb069
A
253 bpfattach(pcb->utun_ifp, DLT_NULL, 4);
254
255 /* The interfaces resoures allocated, mark it as running */
256 if (result == 0)
257 ifnet_set_flags(pcb->utun_ifp, IFF_RUNNING, IFF_RUNNING);
b0d623f7
A
258
259 return result;
260}
261
262static errno_t
263utun_detach_ip(
264 ifnet_t interface,
265 protocol_family_t protocol,
266 socket_t pf_socket)
267{
268 errno_t result = EPROTONOSUPPORT;
269
270 /* Attempt a detach */
271 if (protocol == PF_INET) {
272 struct ifreq ifr;
273
274 bzero(&ifr, sizeof(ifr));
275 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
276 ifnet_name(interface), ifnet_unit(interface));
277
278 result = sock_ioctl(pf_socket, SIOCPROTODETACH, &ifr);
279 }
280 else if (protocol == PF_INET6) {
281 struct in6_ifreq ifr6;
282
283 bzero(&ifr6, sizeof(ifr6));
284 snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
285 ifnet_name(interface), ifnet_unit(interface));
286
287 result = sock_ioctl(pf_socket, SIOCPROTODETACH_IN6, &ifr6);
288 }
289
290 return result;
291}
292
293static void
294utun_remove_address(
295 ifnet_t interface,
296 protocol_family_t protocol,
297 ifaddr_t address,
298 socket_t pf_socket)
299{
300 errno_t result = 0;
301
302 /* Attempt a detach */
303 if (protocol == PF_INET) {
304 struct ifreq ifr;
305
306 bzero(&ifr, sizeof(ifr));
307 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
308 ifnet_name(interface), ifnet_unit(interface));
309 result = ifaddr_address(address, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
310 if (result != 0) {
311 printf("utun_remove_address - ifaddr_address failed: %d", result);
312 }
313 else {
314 result = sock_ioctl(pf_socket, SIOCDIFADDR, &ifr);
315 if (result != 0) {
316 printf("utun_remove_address - SIOCDIFADDR failed: %d", result);
317 }
318 }
319 }
320 else if (protocol == PF_INET6) {
321 struct in6_ifreq ifr6;
322
323 bzero(&ifr6, sizeof(ifr6));
324 snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
325 ifnet_name(interface), ifnet_unit(interface));
326 result = ifaddr_address(address, (struct sockaddr*)&ifr6.ifr_addr,
327 sizeof(ifr6.ifr_addr));
328 if (result != 0) {
329 printf("utun_remove_address - ifaddr_address failed (v6): %d",
330 result);
331 }
332 else {
333 result = sock_ioctl(pf_socket, SIOCDIFADDR_IN6, &ifr6);
334 if (result != 0) {
335 printf("utun_remove_address - SIOCDIFADDR_IN6 failed: %d",
336 result);
337 }
338 }
339 }
340}
341
342static void
343utun_cleanup_family(
344 ifnet_t interface,
345 protocol_family_t protocol)
346{
347 errno_t result = 0;
348 socket_t pf_socket = NULL;
349 ifaddr_t *addresses = NULL;
350 int i;
351
352 if (protocol != PF_INET && protocol != PF_INET6) {
353 printf("utun_cleanup_family - invalid protocol family %d\n", protocol);
354 return;
355 }
356
357 /* Create a socket for removing addresses and detaching the protocol */
358 result = sock_socket(protocol, SOCK_DGRAM, 0, NULL, NULL, &pf_socket);
359 if (result != 0) {
360 if (result != EAFNOSUPPORT)
361 printf("utun_cleanup_family - failed to create %s socket: %d\n",
362 protocol == PF_INET ? "IP" : "IPv6", result);
363 goto cleanup;
364 }
365
6d2010ae
A
366 /* always set SS_PRIV, we want to close and detach regardless */
367 sock_setpriv(pf_socket, 1);
368
b0d623f7
A
369 result = utun_detach_ip(interface, protocol, pf_socket);
370 if (result == 0 || result == ENXIO) {
371 /* We are done! We either detached or weren't attached. */
372 goto cleanup;
373 }
374 else if (result != EBUSY) {
375 /* Uh, not really sure what happened here... */
376 printf("utun_cleanup_family - utun_detach_ip failed: %d\n", result);
377 goto cleanup;
378 }
379
380 /*
381 * At this point, we received an EBUSY error. This means there are
382 * addresses attached. We should detach them and then try again.
383 */
384 result = ifnet_get_address_list_family(interface, &addresses, protocol);
385 if (result != 0) {
386 printf("fnet_get_address_list_family(%s%d, 0xblah, %s) - failed: %d\n",
387 ifnet_name(interface), ifnet_unit(interface),
388 protocol == PF_INET ? "PF_INET" : "PF_INET6", result);
389 goto cleanup;
390 }
391
392 for (i = 0; addresses[i] != 0; i++) {
393 utun_remove_address(interface, protocol, addresses[i], pf_socket);
394 }
395 ifnet_free_address_list(addresses);
396 addresses = NULL;
397
398 /*
399 * The addresses should be gone, we should try the remove again.
400 */
401 result = utun_detach_ip(interface, protocol, pf_socket);
402 if (result != 0 && result != ENXIO) {
403 printf("utun_cleanup_family - utun_detach_ip failed: %d\n", result);
404 }
405
406cleanup:
407 if (pf_socket != NULL)
408 sock_close(pf_socket);
409
410 if (addresses != NULL)
411 ifnet_free_address_list(addresses);
412}
413
414static errno_t
415utun_ctl_disconnect(
416 __unused kern_ctl_ref kctlref,
417 __unused u_int32_t unit,
418 void *unitinfo)
419{
420 struct utun_pcb *pcb = unitinfo;
d1ecb069 421 ifnet_t ifp = pcb->utun_ifp;
b0d623f7 422 errno_t result = 0;
316670eb
A
423
424 utun_cleanup_crypto(pcb);
425
d1ecb069
A
426 pcb->utun_ctlref = NULL;
427 pcb->utun_unit = 0;
b0d623f7
A
428
429 /*
430 * We want to do everything in our power to ensure that the interface
431 * really goes away when the socket is closed. We must remove IP/IPv6
432 * addresses and detach the protocols. Finally, we can remove and
433 * release the interface.
434 */
435 utun_cleanup_family(ifp, AF_INET);
436 utun_cleanup_family(ifp, AF_INET6);
437
438 if ((result = ifnet_detach(ifp)) != 0) {
439 printf("utun_ctl_disconnect - ifnet_detach failed: %d\n", result);
440 }
441
442 if ((result = ifnet_release(ifp)) != 0) {
443 printf("utun_ctl_disconnect - ifnet_release failed: %d\n", result);
444 }
445
446 return 0;
447}
448
449static errno_t
450utun_ctl_send(
451 __unused kern_ctl_ref kctlref,
452 __unused u_int32_t unit,
453 void *unitinfo,
454 mbuf_t m,
455 __unused int flags)
456{
39236c6e
A
457 /*
458 * The userland ABI requires the first four bytes have the protocol family
459 * in network byte order: swap them
460 */
461 if (m_pktlen(m) >= 4)
462 *(protocol_family_t *)mbuf_data(m) = ntohl(*(protocol_family_t *)mbuf_data(m));
463 else
464 printf("%s - unexpected short mbuf pkt len %d\n", __func__, m_pktlen(m) );
465
316670eb 466 return utun_pkt_input((struct utun_pcb *)unitinfo, m);
b0d623f7
A
467}
468
469static errno_t
470utun_ctl_setopt(
471 __unused kern_ctl_ref kctlref,
472 __unused u_int32_t unit,
473 void *unitinfo,
474 int opt,
475 void *data,
476 size_t len)
477{
478 struct utun_pcb *pcb = unitinfo;
479 errno_t result = 0;
480
481 /* check for privileges for privileged options */
482 switch (opt) {
483 case UTUN_OPT_FLAGS:
d1ecb069 484 case UTUN_OPT_EXT_IFDATA_STATS:
39236c6e 485 case UTUN_OPT_SET_DELEGATE_INTERFACE:
b0d623f7
A
486 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
487 return EPERM;
488 }
489 break;
490 }
491
492 switch (opt) {
493 case UTUN_OPT_FLAGS:
494 if (len != sizeof(u_int32_t))
495 result = EMSGSIZE;
496 else
d1ecb069
A
497 pcb->utun_flags = *(u_int32_t *)data;
498 break;
499
316670eb
A
500 case UTUN_OPT_ENABLE_CRYPTO:
501 result = utun_ctl_enable_crypto(kctlref, unit, unitinfo, opt, data, len);
502 break;
503
504 case UTUN_OPT_CONFIG_CRYPTO_KEYS:
505 result = utun_ctl_config_crypto_keys(kctlref, unit, unitinfo, opt, data, len);
506 break;
507
508 case UTUN_OPT_UNCONFIG_CRYPTO_KEYS:
509 result = utun_ctl_unconfig_crypto_keys(kctlref, unit, unitinfo, opt, data, len);
510 break;
511
512 case UTUN_OPT_DISABLE_CRYPTO:
513 result = utun_ctl_disable_crypto(kctlref, unit, unitinfo, opt, data, len);
514 break;
515
516 case UTUN_OPT_STOP_CRYPTO_DATA_TRAFFIC:
517 result = utun_ctl_stop_crypto_data_traffic(kctlref, unit, unitinfo, opt, data, len);
518 break;
519
520 case UTUN_OPT_START_CRYPTO_DATA_TRAFFIC:
521 result = utun_ctl_start_crypto_data_traffic(kctlref, unit, unitinfo, opt, data, len);
522 break;
523
39236c6e
A
524 case UTUN_OPT_CONFIG_CRYPTO_FRAMER:
525 result = utun_ctl_config_crypto_framer(kctlref, unit, unitinfo, opt, data, len);
526 break;
527
528 case UTUN_OPT_UNCONFIG_CRYPTO_FRAMER:
529 result = utun_ctl_unconfig_crypto_framer(kctlref, unit, unitinfo, opt, data, len);
530 break;
531
d1ecb069
A
532 case UTUN_OPT_EXT_IFDATA_STATS:
533 if (len != sizeof(int)) {
534 result = EMSGSIZE;
535 break;
536 }
537 pcb->utun_ext_ifdata_stats = (*(int *)data) ? 1 : 0;
538 break;
539
540 case UTUN_OPT_INC_IFDATA_STATS_IN:
541 case UTUN_OPT_INC_IFDATA_STATS_OUT: {
542 struct utun_stats_param *utsp = (struct utun_stats_param *)data;
543
544 if (utsp == NULL || len < sizeof(struct utun_stats_param)) {
545 result = EINVAL;
546 break;
547 }
548 if (!pcb->utun_ext_ifdata_stats) {
549 result = EINVAL;
550 break;
551 }
552 if (opt == UTUN_OPT_INC_IFDATA_STATS_IN)
553 ifnet_stat_increment_in(pcb->utun_ifp, utsp->utsp_packets,
554 utsp->utsp_bytes, utsp->utsp_errors);
555 else
556 ifnet_stat_increment_out(pcb->utun_ifp, utsp->utsp_packets,
557 utsp->utsp_bytes, utsp->utsp_errors);
b0d623f7 558 break;
d1ecb069 559 }
39236c6e
A
560
561 case UTUN_OPT_SET_DELEGATE_INTERFACE: {
562 ifnet_t del_ifp = NULL;
563 char name[IFNAMSIZ];
564
565 if (len > IFNAMSIZ - 1) {
566 result = EMSGSIZE;
567 break;
568 }
569 if (len != 0) { /* if len==0, del_ifp will be NULL causing the delegate to be removed */
570 bcopy(data, name, len);
571 name[len] = 0;
572 result = ifnet_find_by_name(name, &del_ifp);
573 }
574 if (result == 0) {
575 result = ifnet_set_delegate(pcb->utun_ifp, del_ifp);
576 if (del_ifp)
577 ifnet_release(del_ifp);
578 }
579 break;
580 }
581
582 default:
b0d623f7
A
583 result = ENOPROTOOPT;
584 break;
585 }
586
587 return result;
588}
589
590static errno_t
591utun_ctl_getopt(
592 __unused kern_ctl_ref kctlref,
593 __unused u_int32_t unit,
594 void *unitinfo,
595 int opt,
596 void *data,
597 size_t *len)
598{
599 struct utun_pcb *pcb = unitinfo;
600 errno_t result = 0;
601
602 switch (opt) {
603 case UTUN_OPT_FLAGS:
604 if (*len != sizeof(u_int32_t))
605 result = EMSGSIZE;
606 else
d1ecb069 607 *(u_int32_t *)data = pcb->utun_flags;
b0d623f7 608 break;
d1ecb069
A
609
610 case UTUN_OPT_EXT_IFDATA_STATS:
611 if (*len != sizeof(int))
612 result = EMSGSIZE;
613 else
614 *(int *)data = (pcb->utun_ext_ifdata_stats) ? 1 : 0;
615 break;
616
b0d623f7 617 case UTUN_OPT_IFNAME:
d1ecb069 618 *len = snprintf(data, *len, "%s%d", ifnet_name(pcb->utun_ifp), ifnet_unit(pcb->utun_ifp)) + 1;
b0d623f7 619 break;
d1ecb069 620
316670eb
A
621 case UTUN_OPT_GENERATE_CRYPTO_KEYS_IDX:
622 result = utun_ctl_generate_crypto_keys_idx(kctlref, unit, unitinfo, opt, data, len);
623 break;
624
b0d623f7
A
625 default:
626 result = ENOPROTOOPT;
627 break;
628 }
629
630 return result;
631}
632
633/* Network Interface functions */
634static errno_t
635utun_output(
636 ifnet_t interface,
637 mbuf_t data)
638{
639 struct utun_pcb *pcb = ifnet_softc(interface);
640 errno_t result;
641
39236c6e
A
642 if (m_pktlen(data) >= 4) {
643 bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0);
644 }
b0d623f7 645
d1ecb069 646 if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) {
b0d623f7
A
647 /* flush data */
648 mbuf_freem(data);
649 return 0;
650 }
651
316670eb 652 // otherwise, fall thru to ctl_enqueumbuf
d1ecb069 653 if (pcb->utun_ctlref) {
316670eb
A
654 int length;
655
656 // only pass packets to utun-crypto if crypto is enabled and 'suspend data traffic' is not.
657 if ((pcb->utun_flags & (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC)) == UTUN_FLAGS_CRYPTO) {
658 if (utun_pkt_crypto_output(pcb, &data) == 0) {
659 return 0;
660 }
661 }
662
39236c6e
A
663 /*
664 * The ABI requires the protocol in network byte order
665 */
666 if (m_pktlen(data) >= 4)
667 *(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data));
668
316670eb 669 length = mbuf_pkthdr_len(data);
d1ecb069 670 result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR);
b0d623f7
A
671 if (result != 0) {
672 mbuf_freem(data);
673 printf("utun_output - ctl_enqueuembuf failed: %d\n", result);
d1ecb069 674
b0d623f7
A
675 ifnet_stat_increment_out(interface, 0, 0, 1);
676 }
677 else {
d1ecb069
A
678 if (!pcb->utun_ext_ifdata_stats)
679 ifnet_stat_increment_out(interface, 1, length, 0);
b0d623f7
A
680 }
681 }
682 else
683 mbuf_freem(data);
684
685 return 0;
686}
687
688/* Network Interface functions */
689static errno_t
690utun_demux(
691 __unused ifnet_t interface,
692 mbuf_t data,
693 __unused char *frame_header,
694 protocol_family_t *protocol)
695{
696
697 while (data != NULL && mbuf_len(data) < 1) {
698 data = mbuf_next(data);
699 }
700
701 if (data == NULL)
702 return ENOENT;
703
39236c6e 704 *protocol = *(u_int32_t *)mbuf_data(data);
b0d623f7
A
705 return 0;
706}
707
708static errno_t
709utun_framer(
d1ecb069 710 __unused ifnet_t interface,
b0d623f7
A
711 mbuf_t *packet,
712 __unused const struct sockaddr *dest,
713 __unused const char *desk_linkaddr,
39236c6e 714 const char *frame_type,
316670eb 715 u_int32_t *prepend_len,
39236c6e 716 u_int32_t *postpend_len)
b0d623f7 717{
b0d623f7
A
718 if (mbuf_prepend(packet, sizeof(protocol_family_t), MBUF_DONTWAIT) != 0) {
719 printf("utun_framer - ifnet_output prepend failed\n");
d1ecb069 720
b0d623f7 721 ifnet_stat_increment_out(interface, 0, 0, 1);
d1ecb069 722
b0d623f7
A
723 // just return, because the buffer was freed in mbuf_prepend
724 return EJUSTRETURN;
725 }
39236c6e
A
726 if (prepend_len != NULL)
727 *prepend_len = sizeof(protocol_family_t);
728 if (postpend_len != NULL)
729 *postpend_len = 0;
b0d623f7
A
730
731 // place protocol number at the beginning of the mbuf
39236c6e 732 *(protocol_family_t *)mbuf_data(*packet) = *(protocol_family_t *)(uintptr_t)(size_t)frame_type;
b0d623f7
A
733
734 return 0;
735}
736
737static errno_t
738utun_add_proto(
739 __unused ifnet_t interface,
740 protocol_family_t protocol,
741 __unused const struct ifnet_demux_desc *demux_array,
742 __unused u_int32_t demux_count)
743{
744 switch(protocol) {
745 case PF_INET:
746 return 0;
747 case PF_INET6:
748 return 0;
749 default:
750 break;
751 }
752
753 return ENOPROTOOPT;
754}
755
756static errno_t
757utun_del_proto(
758 __unused ifnet_t interface,
759 __unused protocol_family_t protocol)
760{
761 return 0;
762}
763
764static errno_t
765utun_ioctl(
d1ecb069
A
766 ifnet_t interface,
767 u_long command,
b0d623f7
A
768 void *data)
769{
770 errno_t result = 0;
b0d623f7
A
771
772 switch(command) {
773 case SIOCSIFMTU:
774 ifnet_set_mtu(interface, ((struct ifreq*)data)->ifr_mtu);
775 break;
d1ecb069
A
776
777 case SIOCSIFFLAGS:
778 /* ifioctl() takes care of it */
779 break;
780
b0d623f7
A
781 default:
782 result = EOPNOTSUPP;
783 }
784
785 return result;
786}
787
788static void
789utun_detached(
790 ifnet_t interface)
791{
792 struct utun_pcb *pcb = ifnet_softc(interface);
793
794 utun_free(pcb);
795
796 OSDecrementAtomic(&utun_ifcount);
797}
798
799/* Protocol Handlers */
800
801static errno_t
802utun_proto_input(
803 __unused ifnet_t interface,
804 protocol_family_t protocol,
805 mbuf_t m,
806 __unused char *frame_header)
807{
808
809 // remove protocol family first
810 mbuf_adj(m, sizeof(u_int32_t));
811
6d2010ae
A
812 if (proto_input(protocol, m) != 0)
813 m_freem(m);
b0d623f7
A
814
815 return 0;
816}
817
818static errno_t
819utun_proto_pre_output(
820 __unused ifnet_t interface,
821 protocol_family_t protocol,
822 __unused mbuf_t *packet,
823 __unused const struct sockaddr *dest,
824 __unused void *route,
825 __unused char *frame_type,
826 __unused char *link_layer_dest)
827{
828
6d2010ae
A
829 *(protocol_family_t *)(void *)frame_type = protocol;
830 return 0;
b0d623f7
A
831}
832
833static errno_t
834utun_attach_proto(
835 ifnet_t interface,
836 protocol_family_t protocol)
837{
838 struct ifnet_attach_proto_param proto;
839 errno_t result;
840
841 bzero(&proto, sizeof(proto));
842 proto.input = utun_proto_input;
843 proto.pre_output = utun_proto_pre_output;
844
845 result = ifnet_attach_protocol(interface, protocol, &proto);
846 if (result != 0 && result != EEXIST) {
847 printf("utun_attach_inet - ifnet_attach_protocol %d failed: %d\n",
848 protocol, result);
849 }
850
851 return result;
852}
853
316670eb
A
854errno_t
855utun_pkt_input (struct utun_pcb *pcb, mbuf_t m)
856{
857 errno_t result;
39236c6e 858 protocol_family_t protocol = 0;
316670eb
A
859
860 mbuf_pkthdr_setrcvif(m, pcb->utun_ifp);
861
39236c6e
A
862 if (m_pktlen(m) >= 4) {
863 protocol = *(u_int32_t *)mbuf_data(m);
864
865 bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0);
866 }
316670eb
A
867 if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) {
868 /* flush data */
869 mbuf_freem(m);
870 return 0;
871 }
316670eb
A
872
873 // quick exit for keepalive packets
874 if (protocol == AF_UTUN && pcb->utun_flags & UTUN_FLAGS_CRYPTO) {
875 if (utun_pkt_crypto_output(pcb, &m) == 0) {
876 return 0;
877 }
878 printf("%s: utun_pkt_crypto_output failed, flags %x\n", __FUNCTION__, pcb->utun_flags);
879 return EINVAL;
880 }
881
882 if (!pcb->utun_ext_ifdata_stats) {
883 struct ifnet_stat_increment_param incs;
884
885 bzero(&incs, sizeof(incs));
886 incs.packets_in = 1;
887 incs.bytes_in = mbuf_pkthdr_len(m);
888 result = ifnet_input(pcb->utun_ifp, m, &incs);
889 } else {
890 result = ifnet_input(pcb->utun_ifp, m, NULL);
891 }
892 if (result != 0) {
893 ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1);
894
895 printf("%s - ifnet_input failed: %d\n", __FUNCTION__, result);
896 mbuf_freem(m);
897 }
898
899 return 0;
900}