]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/if_utun.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / net / if_utun.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2008-2009 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
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);
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);
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);
91
92/* Control block allocated for each kernel control connection */
93struct utun_pcb {
94 kern_ctl_ref utun_ctlref;
95 ifnet_t utun_ifp;
96 u_int32_t utun_unit;
97 u_int32_t utun_flags;
98 int utun_ext_ifdata_stats;
99};
100
101static kern_ctl_ref utun_kctlref;
102static u_int32_t utun_family;
103static OSMallocTag utun_malloc_tag;
104static SInt32 utun_ifcount = 0;
105
106/* Prepend length */
107static void*
108utun_alloc(size_t size)
109{
110 size_t *mem = OSMalloc(size + sizeof(size_t), utun_malloc_tag);
111
112 if (mem) {
113 *mem = size + sizeof(size_t);
114 mem++;
115 }
116
117 return (void*)mem;
118}
119
120static void
121utun_free(void *ptr)
122{
123 size_t *size = ptr;
124 size--;
125 OSFree(size, *size, utun_malloc_tag);
126}
127
128errno_t
129utun_register_control(void)
130{
131 struct kern_ctl_reg kern_ctl;
132 errno_t result = 0;
133
134 /* Create a tag to allocate memory */
135 utun_malloc_tag = OSMalloc_Tagalloc(UTUN_CONTROL_NAME, OSMT_DEFAULT);
136
137 /* Find a unique value for our interface family */
138 result = mbuf_tag_id_find(UTUN_CONTROL_NAME, &utun_family);
139 if (result != 0) {
140 printf("utun_register_control - mbuf_tag_id_find_internal failed: %d\n", result);
141 return result;
142 }
143
144 bzero(&kern_ctl, sizeof(kern_ctl));
145 strncpy(kern_ctl.ctl_name, UTUN_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
146 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
147 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; /* Require root */
148 kern_ctl.ctl_sendsize = 64 * 1024;
149 kern_ctl.ctl_recvsize = 64 * 1024;
150 kern_ctl.ctl_connect = utun_ctl_connect;
151 kern_ctl.ctl_disconnect = utun_ctl_disconnect;
152 kern_ctl.ctl_send = utun_ctl_send;
153 kern_ctl.ctl_setopt = utun_ctl_setopt;
154 kern_ctl.ctl_getopt = utun_ctl_getopt;
155
156 result = ctl_register(&kern_ctl, &utun_kctlref);
157 if (result != 0) {
158 printf("utun_register_control - ctl_register failed: %d\n", result);
159 return result;
160 }
161
162 /* Register the protocol plumbers */
163 if ((result = proto_register_plumber(PF_INET, utun_family,
164 utun_attach_proto, NULL)) != 0) {
165 printf("utun_register_control - proto_register_plumber(PF_INET, %d) failed: %d\n",
166 utun_family, result);
167 ctl_deregister(utun_kctlref);
168 return result;
169 }
170
171 /* Register the protocol plumbers */
172 if ((result = proto_register_plumber(PF_INET6, utun_family,
173 utun_attach_proto, NULL)) != 0) {
174 proto_unregister_plumber(PF_INET, utun_family);
175 ctl_deregister(utun_kctlref);
176 printf("utun_register_control - proto_register_plumber(PF_INET6, %d) failed: %d\n",
177 utun_family, result);
178 return result;
179 }
180
181 return 0;
182}
183
184/* Kernel control functions */
185
186static errno_t
187utun_ctl_connect(
188 kern_ctl_ref kctlref,
189 struct sockaddr_ctl *sac,
190 void **unitinfo)
191{
192 struct ifnet_init_params utun_init;
193 struct utun_pcb *pcb;
194 errno_t result;
195 struct ifnet_stats_param stats;
196
197 /* kernel control allocates, interface frees */
198 pcb = utun_alloc(sizeof(*pcb));
199 if (pcb == NULL)
200 return ENOMEM;
201
202 /* Setup the protocol control block */
203 bzero(pcb, sizeof(*pcb));
204 *unitinfo = pcb;
205 pcb->utun_ctlref = kctlref;
206 pcb->utun_unit = sac->sc_unit;
207
208 printf("utun_ctl_connect: creating interface utun%d\n", pcb->utun_unit - 1);
209
210 /* Create the interface */
211 bzero(&utun_init, sizeof(utun_init));
212 utun_init.name = "utun";
213 utun_init.unit = pcb->utun_unit - 1;
214 utun_init.family = utun_family;
215 utun_init.type = IFT_OTHER;
216 utun_init.output = utun_output;
217 utun_init.demux = utun_demux;
218 utun_init.framer = utun_framer;
219 utun_init.add_proto = utun_add_proto;
220 utun_init.del_proto = utun_del_proto;
221 utun_init.softc = pcb;
222 utun_init.ioctl = utun_ioctl;
223 utun_init.detach = utun_detached;
224
225 result = ifnet_allocate(&utun_init, &pcb->utun_ifp);
226 if (result != 0) {
227 printf("utun_ctl_connect - ifnet_allocate failed: %d\n", result);
228 utun_free(pcb);
229 return result;
230 }
231 OSIncrementAtomic(&utun_ifcount);
232
233 /* Set flags and additional information. */
234 ifnet_set_mtu(pcb->utun_ifp, 1500);
235 ifnet_set_flags(pcb->utun_ifp, IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT, 0xffff);
236
237 /* The interface must generate its own IPv6 LinkLocal address,
238 * if possible following the recommendation of RFC2472 to the 64bit interface ID
239 */
240 ifnet_set_eflags(pcb->utun_ifp, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
241
242 /* Reset the stats in case as the interface may have been recycled */
243 bzero(&stats, sizeof(struct ifnet_stats_param));
244 ifnet_set_stat(pcb->utun_ifp, &stats);
245
246 /* Attach the interface */
247 result = ifnet_attach(pcb->utun_ifp, NULL);
248 if (result != 0) {
249 printf("utun_ctl_connect - ifnet_allocate failed: %d\n", result);
250 ifnet_release(pcb->utun_ifp);
251 utun_free(pcb);
252 }
253
254 /* Attach to bpf */
255 if (result == 0)
256 bpfattach(pcb->utun_ifp, DLT_NULL, 4);
257
258 /* The interfaces resoures allocated, mark it as running */
259 if (result == 0)
260 ifnet_set_flags(pcb->utun_ifp, IFF_RUNNING, IFF_RUNNING);
261
262 return result;
263}
264
265static errno_t
266utun_detach_ip(
267 ifnet_t interface,
268 protocol_family_t protocol,
269 socket_t pf_socket)
270{
271 errno_t result = EPROTONOSUPPORT;
272
273 /* Attempt a detach */
274 if (protocol == PF_INET) {
275 struct ifreq ifr;
276
277 bzero(&ifr, sizeof(ifr));
278 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
279 ifnet_name(interface), ifnet_unit(interface));
280
281 result = sock_ioctl(pf_socket, SIOCPROTODETACH, &ifr);
282 }
283 else if (protocol == PF_INET6) {
284 struct in6_ifreq ifr6;
285
286 bzero(&ifr6, sizeof(ifr6));
287 snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
288 ifnet_name(interface), ifnet_unit(interface));
289
290 result = sock_ioctl(pf_socket, SIOCPROTODETACH_IN6, &ifr6);
291 }
292
293 return result;
294}
295
296static void
297utun_remove_address(
298 ifnet_t interface,
299 protocol_family_t protocol,
300 ifaddr_t address,
301 socket_t pf_socket)
302{
303 errno_t result = 0;
304
305 /* Attempt a detach */
306 if (protocol == PF_INET) {
307 struct ifreq ifr;
308
309 bzero(&ifr, sizeof(ifr));
310 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
311 ifnet_name(interface), ifnet_unit(interface));
312 result = ifaddr_address(address, &ifr.ifr_addr, sizeof(ifr.ifr_addr));
313 if (result != 0) {
314 printf("utun_remove_address - ifaddr_address failed: %d", result);
315 }
316 else {
317 result = sock_ioctl(pf_socket, SIOCDIFADDR, &ifr);
318 if (result != 0) {
319 printf("utun_remove_address - SIOCDIFADDR failed: %d", result);
320 }
321 }
322 }
323 else if (protocol == PF_INET6) {
324 struct in6_ifreq ifr6;
325
326 bzero(&ifr6, sizeof(ifr6));
327 snprintf(ifr6.ifr_name, sizeof(ifr6.ifr_name), "%s%d",
328 ifnet_name(interface), ifnet_unit(interface));
329 result = ifaddr_address(address, (struct sockaddr*)&ifr6.ifr_addr,
330 sizeof(ifr6.ifr_addr));
331 if (result != 0) {
332 printf("utun_remove_address - ifaddr_address failed (v6): %d",
333 result);
334 }
335 else {
336 result = sock_ioctl(pf_socket, SIOCDIFADDR_IN6, &ifr6);
337 if (result != 0) {
338 printf("utun_remove_address - SIOCDIFADDR_IN6 failed: %d",
339 result);
340 }
341 }
342 }
343}
344
345static void
346utun_cleanup_family(
347 ifnet_t interface,
348 protocol_family_t protocol)
349{
350 errno_t result = 0;
351 socket_t pf_socket = NULL;
352 ifaddr_t *addresses = NULL;
353 int i;
354
355 if (protocol != PF_INET && protocol != PF_INET6) {
356 printf("utun_cleanup_family - invalid protocol family %d\n", protocol);
357 return;
358 }
359
360 /* Create a socket for removing addresses and detaching the protocol */
361 result = sock_socket(protocol, SOCK_DGRAM, 0, NULL, NULL, &pf_socket);
362 if (result != 0) {
363 if (result != EAFNOSUPPORT)
364 printf("utun_cleanup_family - failed to create %s socket: %d\n",
365 protocol == PF_INET ? "IP" : "IPv6", result);
366 goto cleanup;
367 }
368
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;
421 ifnet_t ifp = pcb->utun_ifp;
422 errno_t result = 0;
423
424 pcb->utun_ctlref = NULL;
425 pcb->utun_unit = 0;
426
427 /*
428 * We want to do everything in our power to ensure that the interface
429 * really goes away when the socket is closed. We must remove IP/IPv6
430 * addresses and detach the protocols. Finally, we can remove and
431 * release the interface.
432 */
433 utun_cleanup_family(ifp, AF_INET);
434 utun_cleanup_family(ifp, AF_INET6);
435
436 if ((result = ifnet_detach(ifp)) != 0) {
437 printf("utun_ctl_disconnect - ifnet_detach failed: %d\n", result);
438 }
439
440 if ((result = ifnet_release(ifp)) != 0) {
441 printf("utun_ctl_disconnect - ifnet_release failed: %d\n", result);
442 }
443
444 return 0;
445}
446
447static errno_t
448utun_ctl_send(
449 __unused kern_ctl_ref kctlref,
450 __unused u_int32_t unit,
451 void *unitinfo,
452 mbuf_t m,
453 __unused int flags)
454{
455 struct utun_pcb *pcb = unitinfo;
456 errno_t result;
457
458 mbuf_pkthdr_setrcvif(m, pcb->utun_ifp);
459
460 bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0);
461
462 if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) {
463 /* flush data */
464 mbuf_freem(m);
465 return 0;
466 }
467
468 if (!pcb->utun_ext_ifdata_stats) {
469 struct ifnet_stat_increment_param incs;
470
471 bzero(&incs, sizeof(incs));
472 incs.packets_in = 1;
473 incs.bytes_in = mbuf_pkthdr_len(m);
474 result = ifnet_input(pcb->utun_ifp, m, &incs);
475 } else {
476 result = ifnet_input(pcb->utun_ifp, m, NULL);
477 }
478 if (result != 0) {
479 ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1);
480
481 printf("utun_ctl_send - ifnet_input failed: %d\n", result);
482 mbuf_freem(m);
483 }
484
485 return 0;
486}
487
488static errno_t
489utun_ctl_setopt(
490 __unused kern_ctl_ref kctlref,
491 __unused u_int32_t unit,
492 void *unitinfo,
493 int opt,
494 void *data,
495 size_t len)
496{
497 struct utun_pcb *pcb = unitinfo;
498 errno_t result = 0;
499
500 /* check for privileges for privileged options */
501 switch (opt) {
502 case UTUN_OPT_FLAGS:
503 case UTUN_OPT_EXT_IFDATA_STATS:
504 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
505 return EPERM;
506 }
507 break;
508 }
509
510 switch (opt) {
511 case UTUN_OPT_FLAGS:
512 if (len != sizeof(u_int32_t))
513 result = EMSGSIZE;
514 else
515 pcb->utun_flags = *(u_int32_t *)data;
516 break;
517
518 case UTUN_OPT_EXT_IFDATA_STATS:
519 if (len != sizeof(int)) {
520 result = EMSGSIZE;
521 break;
522 }
523 pcb->utun_ext_ifdata_stats = (*(int *)data) ? 1 : 0;
524 break;
525
526 case UTUN_OPT_INC_IFDATA_STATS_IN:
527 case UTUN_OPT_INC_IFDATA_STATS_OUT: {
528 struct utun_stats_param *utsp = (struct utun_stats_param *)data;
529
530 if (utsp == NULL || len < sizeof(struct utun_stats_param)) {
531 result = EINVAL;
532 break;
533 }
534 if (!pcb->utun_ext_ifdata_stats) {
535 result = EINVAL;
536 break;
537 }
538 if (opt == UTUN_OPT_INC_IFDATA_STATS_IN)
539 ifnet_stat_increment_in(pcb->utun_ifp, utsp->utsp_packets,
540 utsp->utsp_bytes, utsp->utsp_errors);
541 else
542 ifnet_stat_increment_out(pcb->utun_ifp, utsp->utsp_packets,
543 utsp->utsp_bytes, utsp->utsp_errors);
544 break;
545 }
546
547 default:
548 result = ENOPROTOOPT;
549 break;
550 }
551
552 return result;
553}
554
555static errno_t
556utun_ctl_getopt(
557 __unused kern_ctl_ref kctlref,
558 __unused u_int32_t unit,
559 void *unitinfo,
560 int opt,
561 void *data,
562 size_t *len)
563{
564 struct utun_pcb *pcb = unitinfo;
565 errno_t result = 0;
566
567 switch (opt) {
568 case UTUN_OPT_FLAGS:
569 if (*len != sizeof(u_int32_t))
570 result = EMSGSIZE;
571 else
572 *(u_int32_t *)data = pcb->utun_flags;
573 break;
574
575 case UTUN_OPT_EXT_IFDATA_STATS:
576 if (*len != sizeof(int))
577 result = EMSGSIZE;
578 else
579 *(int *)data = (pcb->utun_ext_ifdata_stats) ? 1 : 0;
580 break;
581
582 case UTUN_OPT_IFNAME:
583 *len = snprintf(data, *len, "%s%d", ifnet_name(pcb->utun_ifp), ifnet_unit(pcb->utun_ifp)) + 1;
584 break;
585
586 default:
587 result = ENOPROTOOPT;
588 break;
589 }
590
591 return result;
592}
593
594/* Network Interface functions */
595static errno_t
596utun_output(
597 ifnet_t interface,
598 mbuf_t data)
599{
600 struct utun_pcb *pcb = ifnet_softc(interface);
601 errno_t result;
602
603 bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0);
604
605 if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) {
606 /* flush data */
607 mbuf_freem(data);
608 return 0;
609 }
610
611 if (pcb->utun_ctlref) {
612 int length = mbuf_pkthdr_len(data);
613 result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR);
614 if (result != 0) {
615 mbuf_freem(data);
616 printf("utun_output - ctl_enqueuembuf failed: %d\n", result);
617
618 ifnet_stat_increment_out(interface, 0, 0, 1);
619 }
620 else {
621 if (!pcb->utun_ext_ifdata_stats)
622 ifnet_stat_increment_out(interface, 1, length, 0);
623 }
624 }
625 else
626 mbuf_freem(data);
627
628 return 0;
629}
630
631/* Network Interface functions */
632static errno_t
633utun_demux(
634 __unused ifnet_t interface,
635 mbuf_t data,
636 __unused char *frame_header,
637 protocol_family_t *protocol)
638{
639
640 while (data != NULL && mbuf_len(data) < 1) {
641 data = mbuf_next(data);
642 }
643
644 if (data == NULL)
645 return ENOENT;
646
647 *protocol = ntohl(*(u_int32_t *)mbuf_data(data));
648 return 0;
649}
650
651static errno_t
652utun_framer(
653 __unused ifnet_t interface,
654 mbuf_t *packet,
655 __unused const struct sockaddr *dest,
656 __unused const char *desk_linkaddr,
657 const char *frame_type)
658{
659 if (mbuf_prepend(packet, sizeof(protocol_family_t), MBUF_DONTWAIT) != 0) {
660 printf("utun_framer - ifnet_output prepend failed\n");
661
662 ifnet_stat_increment_out(interface, 0, 0, 1);
663
664 // just return, because the buffer was freed in mbuf_prepend
665 return EJUSTRETURN;
666 }
667
668 // place protocol number at the beginning of the mbuf
669 *(protocol_family_t *)mbuf_data(*packet) = htonl(*(protocol_family_t *)(uintptr_t)(size_t)frame_type);
670
671 return 0;
672}
673
674static errno_t
675utun_add_proto(
676 __unused ifnet_t interface,
677 protocol_family_t protocol,
678 __unused const struct ifnet_demux_desc *demux_array,
679 __unused u_int32_t demux_count)
680{
681 switch(protocol) {
682 case PF_INET:
683 return 0;
684 case PF_INET6:
685 return 0;
686 default:
687 break;
688 }
689
690 return ENOPROTOOPT;
691}
692
693static errno_t
694utun_del_proto(
695 __unused ifnet_t interface,
696 __unused protocol_family_t protocol)
697{
698 return 0;
699}
700
701static errno_t
702utun_ioctl(
703 ifnet_t interface,
704 u_long command,
705 void *data)
706{
707 errno_t result = 0;
708 struct ifaddr *ifa = (struct ifaddr *)data;
709
710 switch(command) {
711 case SIOCSIFMTU:
712 ifnet_set_mtu(interface, ((struct ifreq*)data)->ifr_mtu);
713 break;
714
715 case SIOCSIFFLAGS:
716 /* ifioctl() takes care of it */
717 break;
718
719 case SIOCSIFADDR:
720 case SIOCAIFADDR:
721 /* This will be called for called for IPv6 Address additions */
722 if (ifa->ifa_addr->sa_family == AF_INET6)
723 break;
724 /* Fall though for other families like IPv4 */
725
726 default:
727 result = EOPNOTSUPP;
728 }
729
730 return result;
731}
732
733static void
734utun_detached(
735 ifnet_t interface)
736{
737 struct utun_pcb *pcb = ifnet_softc(interface);
738
739 utun_free(pcb);
740
741 OSDecrementAtomic(&utun_ifcount);
742}
743
744/* Protocol Handlers */
745
746static errno_t
747utun_proto_input(
748 __unused ifnet_t interface,
749 protocol_family_t protocol,
750 mbuf_t m,
751 __unused char *frame_header)
752{
753
754 // remove protocol family first
755 mbuf_adj(m, sizeof(u_int32_t));
756
757 proto_input(protocol, m);
758
759 return 0;
760}
761
762static errno_t
763utun_proto_pre_output(
764 __unused ifnet_t interface,
765 protocol_family_t protocol,
766 __unused mbuf_t *packet,
767 __unused const struct sockaddr *dest,
768 __unused void *route,
769 __unused char *frame_type,
770 __unused char *link_layer_dest)
771{
772
773 *(protocol_family_t *)(void *)frame_type = protocol;
774 return 0;
775}
776
777static errno_t
778utun_attach_proto(
779 ifnet_t interface,
780 protocol_family_t protocol)
781{
782 struct ifnet_attach_proto_param proto;
783 errno_t result;
784
785 bzero(&proto, sizeof(proto));
786 proto.input = utun_proto_input;
787 proto.pre_output = utun_proto_pre_output;
788
789 result = ifnet_attach_protocol(interface, protocol, &proto);
790 if (result != 0 && result != EEXIST) {
791 printf("utun_attach_inet - ifnet_attach_protocol %d failed: %d\n",
792 protocol, result);
793 }
794
795 return result;
796}
797