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