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