xref: /xnu-12377.61.12/bsd/net/if_headless.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8) !
1 /*
2  * Copyright (c) 2019-2021 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 #if SKYWALK
29 
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/mbuf.h>
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/sockio.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39 #include <sys/kern_event.h>
40 #include <sys/mcache.h>
41 #include <sys/syslog.h>
42 
43 #include <net/bpf.h>
44 #include <net/ethernet.h>
45 #include <net/if.h>
46 #include <net/if_vlan_var.h>
47 #include <net/if_arp.h>
48 #include <net/if_dl.h>
49 #include <net/if_ether.h>
50 #include <net/if_types.h>
51 #include <libkern/OSAtomic.h>
52 
53 #include <net/dlil.h>
54 
55 #include <net/kpi_interface.h>
56 #include <net/kpi_protocol.h>
57 
58 #include <kern/locks.h>
59 #include <kern/zalloc.h>
60 
61 #ifdef INET
62 #include <netinet/in.h>
63 #include <netinet/if_ether.h>
64 #endif
65 
66 #include <net/if_media.h>
67 #include <net/ether_if_module.h>
68 #include <skywalk/os_skywalk_private.h>
69 #include <skywalk/nexus/netif/nx_netif.h>
70 #include <skywalk/channel/channel_var.h>
71 
72 static boolean_t
is_power_of_two(unsigned int val)73 is_power_of_two(unsigned int val)
74 {
75 	return (val & (val - 1)) == 0;
76 }
77 
78 #define HEADLESS_ZERO_IFNAME         "zero"
79 #define HEADLESS_NULL_IFNAME         "null"
80 
81 SYSCTL_DECL(_net_link);
82 SYSCTL_NODE(_net_link, OID_AUTO, headless, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
83     "headless interface");
84 
85 static int if_headless_nxattach = 0;
86 SYSCTL_INT(_net_link_headless, OID_AUTO, nxattach,
87     CTLFLAG_RW | CTLFLAG_LOCKED, &if_headless_nxattach, 0,
88     "headless interface auto-attach nexus");
89 
90 static int if_headless_debug = 0;
91 SYSCTL_INT(_net_link_headless, OID_AUTO, debug,
92     CTLFLAG_RW | CTLFLAG_LOCKED, &if_headless_debug, 0,
93     "headless interface debug logs");
94 
95 static int if_headless_multibuflet = 0;
96 SYSCTL_INT(_net_link_headless, OID_AUTO, multibuflet,
97     CTLFLAG_RW | CTLFLAG_LOCKED, &if_headless_multibuflet, 0,
98     "headless interface using multi-buflet packets");
99 
100 static int if_headless_packet_length = 1500;
101 SYSCTL_INT(_net_link_headless, OID_AUTO, packet_length,
102     CTLFLAG_RW | CTLFLAG_LOCKED, &if_headless_packet_length, 0,
103     "headless interface packet length");
104 
105 static int if_headless_create_payload = 0;
106 SYSCTL_INT(_net_link_headless, OID_AUTO, create_payload,
107     CTLFLAG_RW | CTLFLAG_LOCKED, &if_headless_create_payload, 0,
108     "headless interface create payload data or not");
109 
110 /*
111  * SIOCSDRVSPEC
112  */
113 enum {
114 	IF_HEADLESS_S_CMD_NONE              = 0,
115 	IF_HEADLESS_S_CMD_SET_MEDIA         = 1,
116 };
117 
118 #define IF_HEADLESS_MEDIA_LIST_MAX  27
119 
120 struct if_headless_media {
121 	int32_t         iffm_current;
122 	uint32_t        iffm_count;
123 	uint32_t        iffm_reserved[3];
124 	int32_t         iffm_list[IF_HEADLESS_MEDIA_LIST_MAX];
125 };
126 
127 struct if_headless_request {
128 	uint64_t        iffr_reserved[4];
129 	union {
130 		char    iffru_buf[128];         /* stable size */
131 		struct if_headless_media    iffru_media;
132 	} iffr_u;
133 #define iffr_media      iffr_u.iffru_media
134 };
135 
136 /* sysctl net.link.headless.tx_headroom */
137 #define headless_TX_HEADROOM_MAX      32
138 static uint16_t if_headless_tx_headroom = 0;
139 
140 extern void if_headless_init(void);
141 
142 static int
143 headless_tx_headroom_sysctl SYSCTL_HANDLER_ARGS
144 {
145 #pragma unused(oidp, arg1, arg2)
146 	uint16_t new_value;
147 	int changed;
148 	int error;
149 
150 	error = sysctl_io_number(req, if_headless_tx_headroom,
151 	    sizeof(if_headless_tx_headroom), &new_value, &changed);
152 	if (error == 0 && changed != 0) {
153 		if (new_value > headless_TX_HEADROOM_MAX ||
154 		    (new_value % 8) != 0) {
155 			return EINVAL;
156 		}
157 		if_headless_tx_headroom = new_value;
158 	}
159 	return 0;
160 }
161 
162 SYSCTL_PROC(_net_link_headless, OID_AUTO, tx_headroom,
163     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
164     0, 0, headless_tx_headroom_sysctl, "IU", "headless ethernet Tx headroom");
165 
166 /* sysctl net.link.headless.max_mtu */
167 #define headless_MAX_MTU_DEFAULT    2048
168 #define headless_MAX_MTU_MAX        ((16 * 1024) - ETHER_HDR_LEN)
169 
170 static unsigned int if_headless_max_mtu = headless_MAX_MTU_DEFAULT;
171 
172 /* sysctl net.link.headless.buflet_size */
173 #define headless_BUFLET_SIZE_MIN            512
174 #define headless_BUFLET_SIZE_MAX            2048
175 
176 static unsigned int if_headless_buflet_size = headless_BUFLET_SIZE_MIN;
177 
178 static int
179 headless_max_mtu_sysctl SYSCTL_HANDLER_ARGS
180 {
181 #pragma unused(oidp, arg1, arg2)
182 	unsigned int new_value;
183 	int changed;
184 	int error;
185 
186 	error = sysctl_io_number(req, if_headless_max_mtu,
187 	    sizeof(if_headless_max_mtu), &new_value, &changed);
188 	if (error == 0 && changed != 0) {
189 		if (new_value > headless_MAX_MTU_MAX ||
190 		    new_value < ETHERMTU ||
191 		    new_value <= if_headless_buflet_size) {
192 			return EINVAL;
193 		}
194 		if_headless_max_mtu = new_value;
195 	}
196 	return 0;
197 }
198 
199 SYSCTL_PROC(_net_link_headless, OID_AUTO, max_mtu,
200     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
201     0, 0, headless_max_mtu_sysctl, "IU", "headless interface maximum MTU");
202 
203 static int
204 headless_buflet_size_sysctl SYSCTL_HANDLER_ARGS
205 {
206 #pragma unused(oidp, arg1, arg2)
207 	unsigned int new_value;
208 	int changed;
209 	int error;
210 
211 	error = sysctl_io_number(req, if_headless_buflet_size,
212 	    sizeof(if_headless_buflet_size), &new_value, &changed);
213 	if (error == 0 && changed != 0) {
214 		/* must be a power of 2 between min and max */
215 		if (new_value > headless_BUFLET_SIZE_MAX ||
216 		    new_value < headless_BUFLET_SIZE_MIN ||
217 		    !is_power_of_two(new_value) ||
218 		    new_value >= if_headless_max_mtu) {
219 			return EINVAL;
220 		}
221 		if_headless_buflet_size = new_value;
222 	}
223 	return 0;
224 }
225 
226 SYSCTL_PROC(_net_link_headless, OID_AUTO, buflet_size,
227     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
228     0, 0, headless_buflet_size_sysctl, "IU", "headless interface buflet size");
229 
230 /**
231 ** virtual ethernet structures, types
232 **/
233 
234 #define IFF_NUM_TX_RINGS_WMM_MODE       4
235 #define IFF_NUM_RX_RINGS_WMM_MODE       1
236 #define IFF_MAX_TX_RINGS        IFF_NUM_TX_RINGS_WMM_MODE
237 #define IFF_MAX_RX_RINGS        IFF_NUM_RX_RINGS_WMM_MODE
238 
239 typedef uint16_t        iff_flags_t;
240 #define IFF_FLAGS_HWCSUM                0x0001
241 #define IFF_FLAGS_BSD_MODE              0x0002
242 #define IFF_FLAGS_DETACHING             0x0004
243 #define IFF_FLAGS_WMM_MODE              0x0008
244 #define IFF_FLAGS_MULTIBUFLETS          0x0010
245 #define IFF_FLAGS_COPYPKT_MODE          0x0020
246 
247 typedef struct {
248 	kern_pbufpool_t         fpp_pp;
249 	uint32_t                fpp_retain_count;
250 } headless_packet_pool, *headless_packet_pool_t;
251 
252 typedef struct {
253 	uuid_t                  fnx_provider;
254 	uuid_t                  fnx_instance;
255 } headless_nx, *headless_nx_t;
256 
257 struct if_headless {
258 	struct if_clone *       iff_cloner;
259 	char                    iff_name[IFNAMSIZ]; /* our unique id */
260 	ifnet_t                 iff_ifp;
261 	iff_flags_t             iff_flags;
262 	uint32_t                iff_retain_count;
263 	ifnet_t                 iff_peer;       /* the other end */
264 	int                     iff_media_current;
265 	int                     iff_media_active;
266 	uint32_t                iff_media_count;
267 	int                     iff_media_list[IF_HEADLESS_MEDIA_LIST_MAX];
268 	struct mbuf *           iff_pending_tx_packet;
269 	boolean_t               iff_start_busy;
270 	unsigned int            iff_max_mtu;
271 	headless_nx                 iff_nx;
272 	kern_channel_ring_t     iff_rx_ring[IFF_MAX_RX_RINGS];
273 	kern_channel_ring_t     iff_tx_ring[IFF_MAX_TX_RINGS];
274 	thread_call_t           iff_doorbell_tcall;
275 	boolean_t               iff_tcall_active;
276 	boolean_t               iff_waiting_for_tcall;
277 	boolean_t               iff_channel_connected;
278 	headless_packet_pool_t      iff_fpp;
279 	uint16_t                iff_tx_headroom;
280 };
281 
282 typedef struct if_headless * __single if_headless_ref;
283 
284 static if_headless_ref
285 ifnet_get_if_headless(ifnet_t ifp);
286 
287 #define HEADLESS_DPRINTF(fmt, ...)                                  \
288 	{ if (if_headless_debug != 0) printf("%s " fmt, __func__, ## __VA_ARGS__); }
289 
290 static inline void
headless_set_detaching(if_headless_ref headlessif)291 headless_set_detaching(if_headless_ref headlessif)
292 {
293 	headlessif->iff_flags |= IFF_FLAGS_DETACHING;
294 }
295 
296 static inline boolean_t
headless_is_detaching(if_headless_ref headlessif)297 headless_is_detaching(if_headless_ref headlessif)
298 {
299 	return (headlessif->iff_flags & IFF_FLAGS_DETACHING) != 0;
300 }
301 
302 static inline boolean_t
headless_using_multibuflets(if_headless_ref headlessif)303 headless_using_multibuflets(if_headless_ref headlessif)
304 {
305 	return (headlessif->iff_flags & IFF_FLAGS_MULTIBUFLETS) != 0;
306 }
307 
308 #define HEADLESS_MAXUNIT    IF_MAXUNIT
309 #define HEADLESS_ZONE_MAX_ELEM      MIN(IFNETS_MAX, HEADLESS_MAXUNIT)
310 
311 static  int headless_clone_create(struct if_clone *, u_int32_t, void *);
312 static  int headless_clone_destroy(ifnet_t);
313 static  int headless_ioctl(ifnet_t ifp, u_long cmd, void * addr);
314 static  void headless_if_free(ifnet_t ifp);
315 static  void headless_ifnet_set_attrs(if_headless_ref headlessif, ifnet_t ifp);
316 static  void headless_free(if_headless_ref headlessif);
317 
318 static struct if_clone
319     headless_zero_cloner = IF_CLONE_INITIALIZER(HEADLESS_ZERO_IFNAME,
320     headless_clone_create,
321     headless_clone_destroy,
322     0,
323     HEADLESS_MAXUNIT);
324 
325 static struct if_clone
326     headless_null_cloner = IF_CLONE_INITIALIZER(HEADLESS_NULL_IFNAME,
327     headless_clone_create,
328     headless_clone_destroy,
329     0,
330     HEADLESS_MAXUNIT);
331 
332 static  void interface_link_event(ifnet_t ifp, u_int32_t event_code);
333 
334 /* some media words to pretend to be ethernet */
335 static int default_media_words[] = {
336 	IFM_MAKEWORD(IFM_ETHER, 0, 0, 0),
337 	IFM_MAKEWORD(IFM_ETHER, IFM_10G_T, IFM_FDX, 0),
338 	IFM_MAKEWORD(IFM_ETHER, IFM_2500_T, IFM_FDX, 0),
339 	IFM_MAKEWORD(IFM_ETHER, IFM_5000_T, IFM_FDX, 0),
340 };
341 #define default_media_words_count (sizeof(default_media_words)          \
342 	                           / sizeof (default_media_words[0]))
343 
344 /**
345 ** veth locks
346 **/
347 
348 static LCK_GRP_DECLARE(headless_lck_grp, "headless");
349 static LCK_MTX_DECLARE(headless_lck_mtx, &headless_lck_grp);
350 
351 static inline void
headless_lock(void)352 headless_lock(void)
353 {
354 	lck_mtx_lock(&headless_lck_mtx);
355 }
356 
357 static inline void
headless_unlock(void)358 headless_unlock(void)
359 {
360 	lck_mtx_unlock(&headless_lck_mtx);
361 }
362 
363 static inline unsigned int
headless_max_mtu(ifnet_t ifp)364 headless_max_mtu(ifnet_t ifp)
365 {
366 	if_headless_ref     headlessif;
367 	unsigned int    max_mtu = ETHERMTU;
368 
369 	headless_lock();
370 	headlessif = ifnet_get_if_headless(ifp);
371 	if (headlessif != NULL) {
372 		max_mtu = headlessif->iff_max_mtu;
373 	}
374 	headless_unlock();
375 	return max_mtu;
376 }
377 
378 static void
headless_packet_pool_free(headless_packet_pool_t fpp)379 headless_packet_pool_free(headless_packet_pool_t fpp)
380 {
381 	kern_pbufpool_destroy(fpp->fpp_pp);
382 	kfree_type(headless_packet_pool, fpp);
383 }
384 
385 static void
headless_free(if_headless_ref headlessif)386 headless_free(if_headless_ref headlessif)
387 {
388 	assert(headlessif->iff_retain_count == 0);
389 	if (headlessif->iff_fpp != NULL) {
390 		headless_packet_pool_free(headlessif->iff_fpp);
391 	}
392 
393 	HEADLESS_DPRINTF("%s\n", headlessif->iff_name);
394 	kfree_type(struct if_headless, headlessif);
395 }
396 
397 static void
headless_release(if_headless_ref headlessif)398 headless_release(if_headless_ref headlessif)
399 {
400 	u_int32_t               old_retain_count;
401 
402 	old_retain_count = OSDecrementAtomic(&headlessif->iff_retain_count);
403 	switch (old_retain_count) {
404 	case 0:
405 		assert(old_retain_count != 0);
406 		break;
407 	case 1:
408 		headless_free(headlessif);
409 		break;
410 	default:
411 		break;
412 	}
413 	return;
414 }
415 
416 static void
headless_retain(if_headless_ref headlessif)417 headless_retain(if_headless_ref headlessif)
418 {
419 	OSIncrementAtomic(&headlessif->iff_retain_count);
420 }
421 
422 static int
headless_seg_ctor_fn(const kern_pbufpool_t pp,const kern_segment_t buf_seg,const IOSKMemoryDescriptor buf_desc)423 headless_seg_ctor_fn(const kern_pbufpool_t pp, const kern_segment_t buf_seg,
424     const IOSKMemoryDescriptor buf_desc)
425 {
426 #pragma unused(pp, buf_seg, buf_desc)
427 	return 0;
428 }
429 
430 static void
headless_seg_dtor_fn(const kern_pbufpool_t pp,const kern_segment_t buf_seg,const IOSKMemoryDescriptor buf_desc)431 headless_seg_dtor_fn(const kern_pbufpool_t pp, const kern_segment_t buf_seg,
432     const IOSKMemoryDescriptor buf_desc)
433 {
434 #pragma unused(pp, buf_seg, buf_desc)
435 }
436 
437 static headless_packet_pool_t
headless_packet_pool_alloc(boolean_t multi_buflet,unsigned int max_mtu)438 headless_packet_pool_alloc(boolean_t multi_buflet, unsigned int max_mtu)
439 {
440 	headless_packet_pool_t              fpp = NULL;
441 	errno_t                         error;
442 	struct kern_pbufpool *          pp __single;
443 	struct kern_pbufpool_init       pp_init;
444 
445 	bzero(&pp_init, sizeof(pp_init));
446 	pp_init.kbi_version = KERN_PBUFPOOL_CURRENT_VERSION;
447 	pp_init.kbi_flags |= KBIF_USER_ACCESS;
448 	pp_init.kbi_flags |= KBIF_VIRTUAL_DEVICE;
449 	(void)snprintf((char *)pp_init.kbi_name, sizeof(pp_init.kbi_name),
450 	    "%s", "headless ethernet");
451 	pp_init.kbi_packets = 4096; /* XXX make this configurable */
452 	if (multi_buflet) {
453 		pp_init.kbi_bufsize = if_headless_buflet_size;
454 		pp_init.kbi_max_frags = howmany(max_mtu, if_headless_buflet_size);
455 		pp_init.kbi_buflets = pp_init.kbi_packets *
456 		    pp_init.kbi_max_frags;
457 		pp_init.kbi_flags |= KBIF_BUFFER_ON_DEMAND;
458 	} else {
459 		pp_init.kbi_bufsize = max_mtu;
460 		pp_init.kbi_max_frags = 1;
461 		pp_init.kbi_buflets = pp_init.kbi_packets;
462 	}
463 	pp_init.kbi_buf_seg_size = skmem_usr_buf_seg_size;
464 	if (skywalk_netif_direct_enabled()) {
465 		pp_init.kbi_flags |= KBIF_USER_ACCESS;
466 	}
467 	pp_init.kbi_buf_seg_ctor = headless_seg_ctor_fn;
468 	pp_init.kbi_buf_seg_dtor = headless_seg_dtor_fn;
469 	pp_init.kbi_ctx = NULL;
470 	pp_init.kbi_ctx_retain = NULL;
471 	pp_init.kbi_ctx_release = NULL;
472 
473 	error = kern_pbufpool_create(&pp_init, &pp, NULL);
474 	if (error != 0) {
475 		printf("%s: kern_pbufpool_create failed %d\n", __func__, error);
476 	} else {
477 		fpp = kalloc_type(headless_packet_pool, Z_WAITOK | Z_ZERO);
478 		fpp->fpp_pp = pp;
479 		fpp->fpp_retain_count = 1;
480 	}
481 	return fpp;
482 }
483 
484 /**
485 ** nexus netif domain provider
486 **/
487 static errno_t
headless_nxdp_init(kern_nexus_domain_provider_t domprov)488 headless_nxdp_init(kern_nexus_domain_provider_t domprov)
489 {
490 #pragma unused(domprov)
491 	return 0;
492 }
493 
494 static void
headless_nxdp_fini(kern_nexus_domain_provider_t domprov)495 headless_nxdp_fini(kern_nexus_domain_provider_t domprov)
496 {
497 #pragma unused(domprov)
498 }
499 
500 static uuid_t                   headless_nx_dom_prov;
501 
502 static errno_t
headless_register_nexus_domain_provider(void)503 headless_register_nexus_domain_provider(void)
504 {
505 	const struct kern_nexus_domain_provider_init dp_init = {
506 		.nxdpi_version = KERN_NEXUS_DOMAIN_PROVIDER_CURRENT_VERSION,
507 		.nxdpi_flags = 0,
508 		.nxdpi_init = headless_nxdp_init,
509 		.nxdpi_fini = headless_nxdp_fini
510 	};
511 	errno_t                         err = 0;
512 
513 	nexus_domain_provider_name_t headless_provider_name = "com.apple.headless";
514 
515 	/* headless_nxdp_init() is called before this function returns */
516 	err = kern_nexus_register_domain_provider(NEXUS_TYPE_NET_IF,
517 	    headless_provider_name,
518 	    &dp_init, sizeof(dp_init),
519 	    &headless_nx_dom_prov);
520 	if (err != 0) {
521 		printf("%s: failed to register domain provider\n", __func__);
522 		return err;
523 	}
524 	return 0;
525 }
526 
527 /**
528 ** netif nexus routines
529 **/
530 static if_headless_ref
headless_nexus_context(kern_nexus_t nexus)531 headless_nexus_context(kern_nexus_t nexus)
532 {
533 	if_headless_ref headlessif;
534 
535 	headlessif = (if_headless_ref)kern_nexus_get_context(nexus);
536 	assert(headlessif != NULL);
537 	return headlessif;
538 }
539 
540 static errno_t
headless_nx_ring_init(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_t channel,kern_channel_ring_t ring,boolean_t is_tx_ring,void ** ring_ctx)541 headless_nx_ring_init(kern_nexus_provider_t nxprov, kern_nexus_t nexus,
542     kern_channel_t channel, kern_channel_ring_t ring, boolean_t is_tx_ring,
543     void **ring_ctx)
544 {
545 	if_headless_ref     headlessif;
546 #pragma unused(nxprov, channel, ring_ctx)
547 	headless_lock();
548 	headlessif = headless_nexus_context(nexus);
549 	if (headless_is_detaching(headlessif)) {
550 		headless_unlock();
551 		return 0;
552 	}
553 	if (is_tx_ring) {
554 		assert(headlessif->iff_tx_ring[0] == NULL);
555 		headlessif->iff_tx_ring[0] = ring;
556 	} else {
557 		assert(headlessif->iff_rx_ring[0] == NULL);
558 		headlessif->iff_rx_ring[0] = ring;
559 	}
560 	headless_unlock();
561 	HEADLESS_DPRINTF("%s: %s ring init\n",
562 	    headlessif->iff_name, is_tx_ring ? "TX" : "RX");
563 	return 0;
564 }
565 
566 static void
headless_nx_ring_fini(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t ring)567 headless_nx_ring_fini(kern_nexus_provider_t nxprov, kern_nexus_t nexus,
568     kern_channel_ring_t ring)
569 {
570 #pragma unused(nxprov, ring)
571 	if_headless_ref     headlessif;
572 	thread_call_t   tcall __single = NULL;
573 
574 	headless_lock();
575 	headlessif = headless_nexus_context(nexus);
576 	if (headlessif->iff_rx_ring[0] == ring) {
577 		headlessif->iff_rx_ring[0] = NULL;
578 		HEADLESS_DPRINTF("%s: RX ring fini\n", headlessif->iff_name);
579 	} else if (headlessif->iff_tx_ring[0] == ring) {
580 		tcall = headlessif->iff_doorbell_tcall;
581 		headlessif->iff_doorbell_tcall = NULL;
582 		headlessif->iff_tx_ring[0] = NULL;
583 	}
584 	headless_unlock();
585 	if (tcall != NULL) {
586 		boolean_t       success;
587 
588 		success = thread_call_cancel_wait(tcall);
589 		HEADLESS_DPRINTF("%s: thread_call_cancel %s\n",
590 		    headlessif->iff_name,
591 		    success ? "SUCCESS" : "FAILURE");
592 		if (!success) {
593 			headless_lock();
594 			if (headlessif->iff_tcall_active) {
595 				headlessif->iff_waiting_for_tcall = TRUE;
596 				HEADLESS_DPRINTF("%s: *waiting for threadcall\n",
597 				    headlessif->iff_name);
598 				do {
599 					msleep(headlessif, &headless_lck_mtx,
600 					    PZERO, "headless threadcall", 0);
601 				} while (headlessif->iff_tcall_active);
602 				HEADLESS_DPRINTF("%s: ^threadcall done\n",
603 				    headlessif->iff_name);
604 				headlessif->iff_waiting_for_tcall = FALSE;
605 			}
606 			headless_unlock();
607 		}
608 		success = thread_call_free(tcall);
609 		HEADLESS_DPRINTF("%s: thread_call_free %s\n",
610 		    headlessif->iff_name,
611 		    success ? "SUCCESS" : "FAILURE");
612 		headless_release(headlessif);
613 		assert(success == TRUE);
614 	}
615 }
616 
617 static errno_t
headless_nx_pre_connect(kern_nexus_provider_t nxprov,proc_t proc,kern_nexus_t nexus,nexus_port_t port,kern_channel_t channel,void ** channel_context)618 headless_nx_pre_connect(kern_nexus_provider_t nxprov,
619     proc_t proc, kern_nexus_t nexus, nexus_port_t port, kern_channel_t channel,
620     void **channel_context)
621 {
622 #pragma unused(nxprov, proc, nexus, port, channel, channel_context)
623 	return 0;
624 }
625 
626 static errno_t
headless_nx_connected(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_t channel)627 headless_nx_connected(kern_nexus_provider_t nxprov,
628     kern_nexus_t nexus, kern_channel_t channel)
629 {
630 #pragma unused(nxprov, channel)
631 	if_headless_ref headlessif;
632 
633 	headlessif = headless_nexus_context(nexus);
634 	headless_lock();
635 	if (headless_is_detaching(headlessif)) {
636 		headless_unlock();
637 		return EBUSY;
638 	}
639 	headless_retain(headlessif);
640 	headlessif->iff_channel_connected = TRUE;
641 	headless_unlock();
642 	HEADLESS_DPRINTF("%s: connected channel %p\n",
643 	    headlessif->iff_name, channel);
644 	return 0;
645 }
646 
647 static void
headless_nx_pre_disconnect(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_t channel)648 headless_nx_pre_disconnect(kern_nexus_provider_t nxprov,
649     kern_nexus_t nexus, kern_channel_t channel)
650 {
651 #pragma unused(nxprov, channel)
652 	if_headless_ref headlessif;
653 
654 	headlessif = headless_nexus_context(nexus);
655 	HEADLESS_DPRINTF("%s: pre-disconnect channel %p\n",
656 	    headlessif->iff_name, channel);
657 	/* Quiesce the interface and flush any pending outbound packets. */
658 	if_down(headlessif->iff_ifp);
659 	headless_lock();
660 	headlessif->iff_channel_connected = FALSE;
661 	headless_unlock();
662 }
663 
664 static void
headless_nx_disconnected(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_t channel)665 headless_nx_disconnected(kern_nexus_provider_t nxprov,
666     kern_nexus_t nexus, kern_channel_t channel)
667 {
668 #pragma unused(nxprov, channel)
669 	if_headless_ref headlessif;
670 
671 	headlessif = headless_nexus_context(nexus);
672 	HEADLESS_DPRINTF("%s: disconnected channel %p\n",
673 	    headlessif->iff_name, channel);
674 	headless_release(headlessif);
675 }
676 
677 static errno_t
headless_nx_slot_init(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t ring,kern_channel_slot_t slot,uint32_t slot_index,struct kern_slot_prop ** slot_prop_addr,void ** slot_context)678 headless_nx_slot_init(kern_nexus_provider_t nxprov,
679     kern_nexus_t nexus, kern_channel_ring_t ring, kern_channel_slot_t slot,
680     uint32_t slot_index, struct kern_slot_prop **slot_prop_addr,
681     void **slot_context)
682 {
683 #pragma unused(nxprov, nexus, ring, slot, slot_index, slot_prop_addr, slot_context)
684 	return 0;
685 }
686 
687 static void
headless_nx_slot_fini(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t ring,kern_channel_slot_t slot,uint32_t slot_index)688 headless_nx_slot_fini(kern_nexus_provider_t nxprov,
689     kern_nexus_t nexus, kern_channel_ring_t ring, kern_channel_slot_t slot,
690     uint32_t slot_index)
691 {
692 #pragma unused(nxprov, nexus, ring, slot, slot_index)
693 }
694 
695 static errno_t
headless_nx_sync_tx(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t tx_ring,uint32_t flags)696 headless_nx_sync_tx(kern_nexus_provider_t nxprov,
697     kern_nexus_t nexus, kern_channel_ring_t tx_ring, uint32_t flags)
698 {
699 #pragma unused(nxprov)
700 	if_headless_ref         headlessif;
701 	ifnet_t                 ifp;
702 	kern_channel_slot_t     last_tx_slot = NULL;
703 	struct kern_channel_ring_stat_increment stats = {
704 		.kcrsi_slots_transferred = 0, .kcrsi_bytes_transferred = 0
705 	};
706 	kern_channel_slot_t     tx_slot;
707 	struct netif_stats *nifs = &NX_NETIF_PRIVATE(nexus)->nif_stats;
708 
709 	STATS_INC(nifs, NETIF_STATS_TX_SYNC);
710 	headlessif = headless_nexus_context(nexus);
711 	HEADLESS_DPRINTF("%s ring %d flags 0x%x\n", headlessif->iff_name,
712 	    tx_ring->ckr_ring_id, flags);
713 
714 	headless_lock();
715 	if (headless_is_detaching(headlessif) ||
716 	    !headlessif->iff_channel_connected) {
717 		headless_unlock();
718 		return 0;
719 	}
720 	headless_unlock();
721 	ifp = headlessif->iff_ifp;
722 	tx_slot = kern_channel_get_next_slot(tx_ring, NULL, NULL);
723 	while (tx_slot != NULL) {
724 		kern_packet_t   ph;
725 
726 		/* detach the packet from the TX ring */
727 		ph = kern_channel_slot_get_packet(tx_ring, tx_slot);
728 		assert(ph != 0);
729 		kern_channel_slot_detach_packet(tx_ring, tx_slot, ph);
730 
731 		kern_pbufpool_free(headlessif->iff_fpp->fpp_pp, ph);
732 		last_tx_slot = tx_slot;
733 		tx_slot = kern_channel_get_next_slot(tx_ring, tx_slot, NULL);
734 		STATS_INC(nifs, NETIF_STATS_TX_PACKETS);
735 	}
736 
737 	if (last_tx_slot != NULL) {
738 		kern_channel_advance_slot(tx_ring, last_tx_slot);
739 		kern_channel_increment_ring_net_stats(tx_ring, ifp, &stats);
740 	}
741 	return 0;
742 }
743 
744 static errno_t
headless_nx_sync_rx_null(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t rx_ring,uint32_t flags)745 headless_nx_sync_rx_null(kern_nexus_provider_t nxprov,
746     kern_nexus_t nexus, kern_channel_ring_t rx_ring, uint32_t flags)
747 {
748 #pragma unused(nxprov, rx_ring, flags)
749 	if_headless_ref headlessif;
750 	struct netif_stats *nifs = &NX_NETIF_PRIVATE(nexus)->nif_stats;
751 
752 	headlessif = headless_nexus_context(nexus);
753 	HEADLESS_DPRINTF("%s:\n", headlessif->iff_name);
754 	STATS_INC(nifs, NETIF_STATS_RX_SYNC);
755 	return 0;
756 }
757 
758 static errno_t
headless_nx_sync_rx(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t rx_ring,uint32_t flags)759 headless_nx_sync_rx(kern_nexus_provider_t nxprov,
760     kern_nexus_t nexus, kern_channel_ring_t rx_ring, uint32_t flags)
761 {
762 #pragma unused(nxprov)
763 	if_headless_ref         headlessif;
764 	ifnet_t                 ifp;
765 	kern_channel_slot_t     last_rx_slot = NULL;
766 	struct kern_channel_ring_stat_increment stats = {
767 		.kcrsi_slots_transferred = 0, .kcrsi_bytes_transferred = 0
768 	};
769 	kern_channel_slot_t     rx_slot;
770 	struct netif_stats *nifs = &NX_NETIF_PRIVATE(nexus)->nif_stats;
771 
772 	kern_channel_reclaim(rx_ring);
773 	STATS_INC(nifs, NETIF_STATS_RX_SYNC);
774 	headlessif = headless_nexus_context(nexus);
775 	HEADLESS_DPRINTF("%s ring %d flags 0x%x\n", headlessif->iff_name,
776 	    rx_ring->ckr_ring_id, flags);
777 
778 	headless_lock();
779 	if (headless_is_detaching(headlessif) ||
780 	    !headlessif->iff_channel_connected) {
781 		headless_unlock();
782 		return 0;
783 	}
784 	headless_unlock();
785 	ifp = headlessif->iff_ifp;
786 	rx_slot = kern_channel_get_next_slot(rx_ring, NULL, NULL);
787 	kern_pbufpool_t pp = headlessif->iff_fpp->fpp_pp;
788 	while (rx_slot != NULL) {
789 		kern_packet_t ph;
790 		kern_buflet_t buf = NULL;
791 		int err;
792 		err = kern_pbufpool_alloc(pp, 1, &ph);
793 		buf = kern_packet_get_next_buflet(ph, buf);
794 		kern_buflet_set_data_offset(buf, 0);
795 		if (if_headless_create_payload) {
796 			// This is a plain TCP SYN packet
797 			uint64_t * addr = __unsafe_forge_bidi_indexable(uint64_t *,
798 			    kern_buflet_get_data_address(buf),
799 			    kern_buflet_get_data_limit(buf));
800 			uint64_t *u64 = addr;
801 			*(u64 + 0) = 0xc100d51dc3355b68ULL;
802 			*(u64 + 1) = 0x004500084019c564ULL;
803 			*(u64 + 2) = 0x0634004000004000ULL;
804 			*(u64 + 3) = 0x716111e3068d11c0ULL;
805 			*(u64 + 4) = 0xc0118d06e3116171ULL;
806 			*(u64 + 5) = 0x8a3700000000b002ULL;
807 			*(u64 + 6) = 0x02b000000000378aULL;
808 			*(u64 + 7) = 0x010106030301b405ULL;
809 			*(u64 + 8) = 0x000022cc5c940a08ULL;
810 			*(u64 + 9) = 0x0000040200000000ULL;
811 		}
812 		kern_buflet_set_data_length(buf, (uint16_t)if_headless_packet_length);
813 		err = kern_packet_set_headroom(ph, 0);
814 		ASSERT(err == 0);
815 		err = kern_packet_set_link_header_length(ph, 14);
816 		ASSERT(err == 0);
817 		kern_packet_finalize(ph);
818 
819 		kern_channel_slot_attach_packet(rx_ring, rx_slot, ph);
820 
821 		STATS_INC(nifs, NETIF_STATS_RX_PACKETS);
822 		last_rx_slot = rx_slot;
823 		rx_slot = kern_channel_get_next_slot(rx_ring, rx_slot, NULL);
824 	}
825 
826 	if (last_rx_slot != NULL) {
827 		kern_channel_advance_slot(rx_ring, last_rx_slot);
828 		kern_channel_increment_ring_net_stats(rx_ring, ifp, &stats);
829 	}
830 	return 0;
831 }
832 
833 static void
headless_async_doorbell(thread_call_param_t arg0,thread_call_param_t arg1)834 headless_async_doorbell(thread_call_param_t arg0, thread_call_param_t arg1)
835 {
836 #pragma unused(arg1)
837 	errno_t                 error;
838 	if_headless_ref         headlessif = (if_headless_ref)arg0;
839 	kern_channel_ring_t     ring;
840 	boolean_t               more;
841 
842 	headless_lock();
843 	ring = headlessif->iff_tx_ring[0];
844 	if (headless_is_detaching(headlessif) ||
845 	    !headlessif->iff_channel_connected ||
846 	    ring == NULL) {
847 		goto done;
848 	}
849 	headlessif->iff_tcall_active = TRUE;
850 	headless_unlock();
851 	error = kern_channel_tx_refill(ring, UINT32_MAX,
852 	    UINT32_MAX, FALSE, &more);
853 	if (error != 0) {
854 		HEADLESS_DPRINTF("%s: TX refill failed %d\n",
855 		    headlessif->iff_name, error);
856 	} else {
857 		HEADLESS_DPRINTF("%s: TX refilled\n", headlessif->iff_name);
858 	}
859 
860 	headless_lock();
861 done:
862 	headlessif->iff_tcall_active = FALSE;
863 	if (headlessif->iff_waiting_for_tcall) {
864 		HEADLESS_DPRINTF("%s: threadcall waking up waiter\n",
865 		    headlessif->iff_name);
866 		wakeup((caddr_t)headlessif);
867 	}
868 	headless_unlock();
869 }
870 
871 static void
headless_schedule_async_doorbell(if_headless_ref headlessif)872 headless_schedule_async_doorbell(if_headless_ref headlessif)
873 {
874 	thread_call_t   __single tcall;
875 
876 	headless_lock();
877 	if (headless_is_detaching(headlessif) ||
878 	    !headlessif->iff_channel_connected) {
879 		headless_unlock();
880 		return;
881 	}
882 	tcall = headlessif->iff_doorbell_tcall;
883 	if (tcall != NULL) {
884 		thread_call_enter(tcall);
885 	} else {
886 		tcall = thread_call_allocate_with_options(headless_async_doorbell,
887 		    (thread_call_param_t)headlessif,
888 		    THREAD_CALL_PRIORITY_KERNEL,
889 		    THREAD_CALL_OPTIONS_ONCE);
890 		if (tcall == NULL) {
891 			printf("%s: %s tcall alloc failed\n",
892 			    __func__, headlessif->iff_name);
893 		} else {
894 			headlessif->iff_doorbell_tcall = tcall;
895 			headless_retain(headlessif);
896 			thread_call_enter(tcall);
897 		}
898 	}
899 	headless_unlock();
900 }
901 
902 static errno_t
headless_nx_tx_doorbell(kern_nexus_provider_t nxprov,kern_nexus_t nexus,kern_channel_ring_t ring,uint32_t flags)903 headless_nx_tx_doorbell(kern_nexus_provider_t nxprov,
904     kern_nexus_t nexus, kern_channel_ring_t ring, uint32_t flags)
905 {
906 #pragma unused(nxprov, ring, flags)
907 	errno_t         error;
908 	if_headless_ref     headlessif;
909 
910 	headlessif = headless_nexus_context(nexus);
911 	HEADLESS_DPRINTF("%s\n", headlessif->iff_name);
912 
913 	if ((flags & KERN_NEXUS_TXDOORBELLF_ASYNC_REFILL) == 0) {
914 		boolean_t       more;
915 		/* synchronous tx refill */
916 		error = kern_channel_tx_refill(ring, UINT32_MAX,
917 		    UINT32_MAX, TRUE, &more);
918 		if (error != 0) {
919 			HEADLESS_DPRINTF("%s: TX refill (sync) %d\n",
920 			    headlessif->iff_name, error);
921 		} else {
922 			HEADLESS_DPRINTF("%s: TX refilled (sync)\n",
923 			    headlessif->iff_name);
924 		}
925 	} else {
926 		HEADLESS_DPRINTF("%s: schedule async refill\n",
927 		    headlessif->iff_name);
928 		headless_schedule_async_doorbell(headlessif);
929 	}
930 	return 0;
931 }
932 
933 static errno_t
headless_netif_prepare(kern_nexus_t nexus,ifnet_t ifp)934 headless_netif_prepare(kern_nexus_t nexus, ifnet_t ifp)
935 {
936 	if_headless_ref headlessif;
937 
938 	headlessif = (if_headless_ref)kern_nexus_get_context(nexus);
939 	headless_ifnet_set_attrs(headlessif, ifp);
940 	return 0;
941 }
942 
943 static errno_t
create_netif_provider_and_instance(if_headless_ref headlessif,struct ifnet_init_eparams * init_params,ifnet_t * ifp,uuid_t * provider,uuid_t * instance)944 create_netif_provider_and_instance(if_headless_ref headlessif,
945     struct ifnet_init_eparams * init_params, ifnet_t *ifp,
946     uuid_t * provider, uuid_t * instance)
947 {
948 	errno_t                 err;
949 	nexus_controller_t      controller = kern_nexus_shared_controller();
950 	struct kern_nexus_net_init net_init;
951 	nexus_name_t            provider_name;
952 	nexus_attr_t            nexus_attr = NULL;
953 	struct kern_nexus_provider_init prov_init = {
954 		.nxpi_version = KERN_NEXUS_DOMAIN_PROVIDER_CURRENT_VERSION,
955 		.nxpi_flags = NXPIF_VIRTUAL_DEVICE,
956 		.nxpi_pre_connect = headless_nx_pre_connect,
957 		.nxpi_connected = headless_nx_connected,
958 		.nxpi_pre_disconnect = headless_nx_pre_disconnect,
959 		.nxpi_disconnected = headless_nx_disconnected,
960 		.nxpi_ring_init = headless_nx_ring_init,
961 		.nxpi_ring_fini = headless_nx_ring_fini,
962 		.nxpi_slot_init = headless_nx_slot_init,
963 		.nxpi_slot_fini = headless_nx_slot_fini,
964 		.nxpi_sync_tx = headless_nx_sync_tx,
965 		.nxpi_sync_rx = headless_nx_sync_rx,
966 		.nxpi_tx_doorbell = headless_nx_tx_doorbell,
967 	};
968 
969 	if (headlessif->iff_cloner == &headless_zero_cloner) {
970 		prov_init.nxpi_sync_rx = headless_nx_sync_rx;
971 		prov_init.nxpi_sync_tx = headless_nx_sync_tx;
972 	} else if (headlessif->iff_cloner == &headless_null_cloner) {
973 		prov_init.nxpi_sync_rx = headless_nx_sync_rx_null;
974 		prov_init.nxpi_sync_tx = headless_nx_sync_tx;
975 	}
976 
977 	static_assert(IFF_MAX_RX_RINGS == 1);
978 
979 	snprintf((char *)provider_name, sizeof(provider_name),
980 	    "com.apple.netif.%s", headlessif->iff_name);
981 	err = kern_nexus_controller_register_provider(controller,
982 	    headless_nx_dom_prov,
983 	    provider_name,
984 	    &prov_init,
985 	    sizeof(prov_init),
986 	    nexus_attr,
987 	    provider);
988 	if (err != 0) {
989 		printf("%s register provider failed, error %d\n",
990 		    __func__, err);
991 		goto failed;
992 	}
993 	bzero(&net_init, sizeof(net_init));
994 	net_init.nxneti_version = KERN_NEXUS_NET_CURRENT_VERSION;
995 	net_init.nxneti_flags = 0;
996 	net_init.nxneti_eparams = init_params;
997 	net_init.nxneti_lladdr = NULL;
998 	net_init.nxneti_prepare = headless_netif_prepare;
999 	net_init.nxneti_rx_pbufpool = headlessif->iff_fpp->fpp_pp;
1000 	net_init.nxneti_tx_pbufpool = headlessif->iff_fpp->fpp_pp;
1001 	err = kern_nexus_controller_alloc_net_provider_instance(controller,
1002 	    *provider,
1003 	    headlessif,
1004 	    NULL,
1005 	    instance,
1006 	    &net_init,
1007 	    ifp);
1008 	if (err != 0) {
1009 		printf("%s alloc_net_provider_instance failed, %d\n",
1010 		    __func__, err);
1011 		kern_nexus_controller_deregister_provider(controller,
1012 		    *provider);
1013 		uuid_clear(*provider);
1014 		goto failed;
1015 	}
1016 
1017 failed:
1018 	if (nexus_attr != NULL) {
1019 		kern_nexus_attr_destroy(nexus_attr);
1020 	}
1021 	return err;
1022 }
1023 
1024 
1025 static errno_t
headless_attach_netif_nexus(if_headless_ref headlessif,struct ifnet_init_eparams * init_params,ifnet_t * ifp)1026 headless_attach_netif_nexus(if_headless_ref headlessif,
1027     struct ifnet_init_eparams * init_params, ifnet_t *ifp)
1028 {
1029 	headless_packet_pool_t      fpp;
1030 	headless_nx_t               nx = &headlessif->iff_nx;
1031 	boolean_t               multi_buflet;
1032 
1033 	multi_buflet = headless_using_multibuflets(headlessif);
1034 	fpp = headless_packet_pool_alloc(multi_buflet, headlessif->iff_max_mtu);
1035 	if (fpp == NULL) {
1036 		return ENOMEM;
1037 	}
1038 	headlessif->iff_fpp = fpp;
1039 	return create_netif_provider_and_instance(headlessif, init_params, ifp,
1040 	           &nx->fnx_provider,
1041 	           &nx->fnx_instance);
1042 }
1043 
1044 static void
detach_provider_and_instance(uuid_t provider,uuid_t instance)1045 detach_provider_and_instance(uuid_t provider, uuid_t instance)
1046 {
1047 	nexus_controller_t controller = kern_nexus_shared_controller();
1048 	errno_t err;
1049 
1050 	if (!uuid_is_null(instance)) {
1051 		err = kern_nexus_controller_free_provider_instance(controller,
1052 		    instance);
1053 		if (err != 0) {
1054 			printf("%s free_provider_instance failed %d\n",
1055 			    __func__, err);
1056 		}
1057 		uuid_clear(instance);
1058 	}
1059 	if (!uuid_is_null(provider)) {
1060 		err = kern_nexus_controller_deregister_provider(controller,
1061 		    provider);
1062 		if (err != 0) {
1063 			printf("%s deregister_provider %d\n", __func__, err);
1064 		}
1065 		uuid_clear(provider);
1066 	}
1067 	return;
1068 }
1069 
1070 static void
headless_detach_netif_nexus(headless_nx_t nx)1071 headless_detach_netif_nexus(headless_nx_t nx)
1072 {
1073 	detach_provider_and_instance(nx->fnx_provider, nx->fnx_instance);
1074 }
1075 
1076 /**
1077 ** headless interface routines
1078 **/
1079 static void
headless_ifnet_set_attrs(if_headless_ref headlessif,ifnet_t ifp)1080 headless_ifnet_set_attrs(if_headless_ref headlessif, ifnet_t ifp)
1081 {
1082 	(void)ifnet_set_capabilities_enabled(ifp, 0, -1);
1083 	ifnet_set_addrlen(ifp, ETHER_ADDR_LEN);
1084 	ifnet_set_baudrate(ifp, 0);
1085 	ifnet_set_mtu(ifp, ETHERMTU);
1086 	ifnet_set_flags(ifp,
1087 	    IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX,
1088 	    0xffff);
1089 	ifnet_set_hdrlen(ifp, sizeof(struct ether_header));
1090 	if ((headlessif->iff_flags & IFF_FLAGS_HWCSUM) != 0) {
1091 		ifnet_set_offload(ifp,
1092 		    IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
1093 		    IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6);
1094 	} else {
1095 		ifnet_set_offload(ifp, 0);
1096 	}
1097 }
1098 
1099 static void
interface_link_event(ifnet_t ifp,u_int32_t event_code)1100 interface_link_event(ifnet_t ifp, u_int32_t event_code)
1101 {
1102 	struct event {
1103 		u_int32_t ifnet_family;
1104 		u_int32_t unit;
1105 		char if_name[IFNAMSIZ];
1106 	};
1107 	_Alignas(struct kern_event_msg) char message[sizeof(struct kern_event_msg) + sizeof(struct event)] = { 0 };
1108 	struct kern_event_msg *header = (struct kern_event_msg*)message;
1109 	struct event *data = (struct event *)(message + KEV_MSG_HEADER_SIZE);
1110 
1111 	header->total_size   = sizeof(message);
1112 	header->vendor_code  = KEV_VENDOR_APPLE;
1113 	header->kev_class    = KEV_NETWORK_CLASS;
1114 	header->kev_subclass = KEV_DL_SUBCLASS;
1115 	header->event_code   = event_code;
1116 	data->ifnet_family   = ifnet_family(ifp);
1117 	data->unit           = (u_int32_t)ifnet_unit(ifp);
1118 	strlcpy(data->if_name, ifnet_name(ifp), IFNAMSIZ);
1119 	ifnet_event(ifp, header);
1120 }
1121 
1122 static if_headless_ref
ifnet_get_if_headless(ifnet_t ifp)1123 ifnet_get_if_headless(ifnet_t ifp)
1124 {
1125 	return (if_headless_ref)ifnet_softc(ifp);
1126 }
1127 
1128 static int
headless_clone_create(struct if_clone * ifc,u_int32_t unit,void * params)1129 headless_clone_create(struct if_clone *ifc, u_int32_t unit, void *params)
1130 {
1131 #pragma unused(params)
1132 	int                             error;
1133 	if_headless_ref               headlessif;
1134 	struct ifnet_init_eparams       headless_init;
1135 	ifnet_ref_t                     ifp;
1136 	uint8_t                         mac_address[ETHER_ADDR_LEN];
1137 
1138 	headlessif = kalloc_type(struct if_headless, Z_WAITOK_ZERO_NOFAIL);
1139 	headlessif->iff_retain_count = 1;
1140 	if (strbufcmp(ifc->ifc_name, HEADLESS_ZERO_IFNAME) == 0) {
1141 		headlessif->iff_cloner = &headless_zero_cloner;
1142 		ASSERT(strlen(HEADLESS_ZERO_IFNAME) == 4);
1143 		bcopy(HEADLESS_ZERO_IFNAME, mac_address, 4);
1144 	} else {
1145 		headlessif->iff_cloner = &headless_null_cloner;
1146 		ASSERT(strlen(HEADLESS_NULL_IFNAME) == 4);
1147 		bcopy(HEADLESS_NULL_IFNAME, mac_address, 4);
1148 	}
1149 	mac_address[ETHER_ADDR_LEN - 2] = (unit & 0xff00) >> 8;
1150 	mac_address[ETHER_ADDR_LEN - 1] = unit & 0xff;
1151 	headlessif->iff_max_mtu = if_headless_max_mtu;
1152 
1153 	/* use the interface name as the unique id for ifp recycle */
1154 	if ((unsigned int)
1155 	    snprintf(headlessif->iff_name, sizeof(headlessif->iff_name), "%s%d",
1156 	    ifc->ifc_name, unit) >= sizeof(headlessif->iff_name)) {
1157 		headless_release(headlessif);
1158 		return EINVAL;
1159 	}
1160 	bzero(&headless_init, sizeof(headless_init));
1161 	headless_init.ver = IFNET_INIT_CURRENT_VERSION;
1162 	headless_init.len = sizeof(headless_init);
1163 	headless_init.flags |= IFNET_INIT_SKYWALK_NATIVE;
1164 	if (if_headless_multibuflet != 0) {
1165 		headlessif->iff_flags |= IFF_FLAGS_MULTIBUFLETS;
1166 	}
1167 
1168 	headlessif->iff_tx_headroom = if_headless_tx_headroom;
1169 	headless_init.tx_headroom = headlessif->iff_tx_headroom;
1170 	if (if_headless_nxattach == 0) {
1171 		headless_init.flags |= IFNET_INIT_NX_NOAUTO;
1172 	}
1173 	headless_init.uniqueid_len = (uint32_t)strbuflen(headlessif->iff_name);
1174 	headless_init.uniqueid = headlessif->iff_name;
1175 	headless_init.name = __unsafe_null_terminated_from_indexable(ifc->ifc_name);
1176 	headless_init.unit = unit;
1177 	headless_init.family = IFNET_FAMILY_ETHERNET;
1178 	headless_init.type = IFT_ETHER;
1179 	headless_init.demux = ether_demux;
1180 	headless_init.add_proto = ether_add_proto;
1181 	headless_init.del_proto = ether_del_proto;
1182 	headless_init.check_multi = ether_check_multi;
1183 	headless_init.framer_extended = ether_frameout_extended;
1184 	headless_init.softc = headlessif;
1185 	headless_init.ioctl = headless_ioctl;
1186 	headless_init.set_bpf_tap = NULL;
1187 	headless_init.detach = headless_if_free;
1188 	headless_init.broadcast_addr = etherbroadcastaddr;
1189 	headless_init.broadcast_len = ETHER_ADDR_LEN;
1190 	error = headless_attach_netif_nexus(headlessif, &headless_init, &ifp);
1191 	if (error != 0) {
1192 		headless_release(headlessif);
1193 		return error;
1194 	}
1195 	/* take an additional reference to ensure that it doesn't go away */
1196 	headless_retain(headlessif);
1197 	headlessif->iff_ifp = ifp;
1198 	headlessif->iff_media_count = default_media_words_count;
1199 	bcopy(default_media_words, headlessif->iff_media_list,
1200 	    sizeof(default_media_words));
1201 	ifnet_set_lladdr(ifp, mac_address, sizeof(mac_address));
1202 
1203 	/* attach as ethernet */
1204 	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
1205 
1206 	interface_link_event(ifp, KEV_DL_LINK_ON);
1207 
1208 	return 0;
1209 }
1210 
1211 static int
headless_clone_destroy(ifnet_t ifp)1212 headless_clone_destroy(ifnet_t ifp)
1213 {
1214 	if_headless_ref     headlessif;
1215 	headless_nx         nx;
1216 	boolean_t       nx_attached = FALSE;
1217 
1218 	interface_link_event(ifp, KEV_DL_LINK_OFF);
1219 	headless_lock();
1220 	headlessif = ifnet_get_if_headless(ifp);
1221 	if (headlessif == NULL || headless_is_detaching(headlessif)) {
1222 		headless_unlock();
1223 		return 0;
1224 	}
1225 	headless_set_detaching(headlessif);
1226 	nx_attached = TRUE;
1227 	nx = headlessif->iff_nx;
1228 	bzero(&headlessif->iff_nx, sizeof(headlessif->iff_nx));
1229 	headless_unlock();
1230 
1231 	if (nx_attached) {
1232 		headless_detach_netif_nexus(&nx);
1233 		headless_release(headlessif);
1234 	}
1235 	ifnet_detach(ifp);
1236 	return 0;
1237 }
1238 
1239 static int
headless_set_media(ifnet_t ifp,struct if_headless_request * iffr)1240 headless_set_media(ifnet_t ifp, struct if_headless_request * iffr)
1241 {
1242 	if_headless_ref     headlessif;
1243 	int             error;
1244 
1245 	if (iffr->iffr_media.iffm_count > IF_HEADLESS_MEDIA_LIST_MAX) {
1246 		/* list is too long */
1247 		return EINVAL;
1248 	}
1249 	headless_lock();
1250 	headlessif = ifnet_get_if_headless(ifp);
1251 	if (headlessif == NULL) {
1252 		error = EINVAL;
1253 		goto done;
1254 	}
1255 	headlessif->iff_media_count = iffr->iffr_media.iffm_count;
1256 	bcopy(iffr->iffr_media.iffm_list, headlessif->iff_media_list,
1257 	    iffr->iffr_media.iffm_count * sizeof(headlessif->iff_media_list[0]));
1258 #if 0
1259 	/* XXX: "auto-negotiate" active with peer? */
1260 	/* generate link status event? */
1261 	headlessif->iff_media_current = iffr->iffr_media.iffm_current;
1262 #endif
1263 	error = 0;
1264 done:
1265 	headless_unlock();
1266 	return error;
1267 }
1268 
1269 static int
if_headless_request_copyin(user_addr_t user_addr,struct if_headless_request * iffr,size_t len)1270 if_headless_request_copyin(user_addr_t user_addr,
1271     struct if_headless_request *iffr, size_t len)
1272 {
1273 	int     error;
1274 
1275 	if (user_addr == USER_ADDR_NULL || len < sizeof(*iffr)) {
1276 		error = EINVAL;
1277 		goto done;
1278 	}
1279 	error = copyin(user_addr, iffr, sizeof(*iffr));
1280 	if (error != 0) {
1281 		goto done;
1282 	}
1283 	if (iffr->iffr_reserved[0] != 0 || iffr->iffr_reserved[1] != 0 ||
1284 	    iffr->iffr_reserved[2] != 0 || iffr->iffr_reserved[3] != 0) {
1285 		error = EINVAL;
1286 		goto done;
1287 	}
1288 done:
1289 	return error;
1290 }
1291 
1292 static int
headless_set_drvspec(ifnet_t ifp,uint64_t cmd,size_t len,user_addr_t user_addr)1293 headless_set_drvspec(ifnet_t ifp, uint64_t cmd, size_t len,
1294     user_addr_t user_addr)
1295 {
1296 	int                     error;
1297 	struct if_headless_request  iffr;
1298 
1299 	switch (cmd) {
1300 	case IF_HEADLESS_S_CMD_SET_MEDIA:
1301 		error = if_headless_request_copyin(user_addr, &iffr, len);
1302 		if (error != 0) {
1303 			break;
1304 		}
1305 		error = headless_set_media(ifp, &iffr);
1306 		break;
1307 	default:
1308 		error = EOPNOTSUPP;
1309 		break;
1310 	}
1311 	return error;
1312 }
1313 
1314 static int
headless_get_drvspec(ifnet_t ifp,uint64_t cmd,size_t len,user_addr_t user_addr)1315 headless_get_drvspec(ifnet_t ifp, uint64_t cmd, size_t len,
1316     user_addr_t user_addr)
1317 {
1318 #pragma unused(ifp, len, user_addr)
1319 	int                     error = EOPNOTSUPP;
1320 
1321 	switch (cmd) {
1322 	default:
1323 		break;
1324 	}
1325 	return error;
1326 }
1327 
1328 union ifdrvu {
1329 	struct ifdrv32  *ifdrvu_32;
1330 	struct ifdrv64  *ifdrvu_64;
1331 	void            *ifdrvu_p;
1332 };
1333 
1334 static int
headless_ioctl(ifnet_t ifp,u_long cmd,void * data)1335 headless_ioctl(ifnet_t ifp, u_long cmd, void * data)
1336 {
1337 	unsigned int            count;
1338 	struct ifdevmtu *       devmtu_p;
1339 	union ifdrvu            drv;
1340 	uint64_t                drv_cmd;
1341 	uint64_t                drv_len;
1342 	boolean_t               drv_set_command = FALSE;
1343 	int                     error = 0;
1344 	struct ifmediareq32 *   ifmr;
1345 	struct ifreq *          ifr;
1346 	if_headless_ref         headlessif;
1347 	int                     status;
1348 	user_addr_t             user_addr;
1349 
1350 	ifr = (struct ifreq *)data;
1351 	switch (cmd) {
1352 	case SIOCSIFADDR:
1353 		ifnet_set_flags(ifp, IFF_UP, IFF_UP);
1354 		break;
1355 
1356 	case SIOCGIFMEDIA32:
1357 	case SIOCGIFMEDIA64:
1358 		headless_lock();
1359 		headlessif = ifnet_get_if_headless(ifp);
1360 		if (headlessif == NULL) {
1361 			headless_unlock();
1362 			return EOPNOTSUPP;
1363 		}
1364 		status = (headlessif->iff_peer != NULL)
1365 		    ? (IFM_AVALID | IFM_ACTIVE) : IFM_AVALID;
1366 		ifmr = (struct ifmediareq32 *)data;
1367 		user_addr = (cmd == SIOCGIFMEDIA64) ?
1368 		    CAST_USER_ADDR_T(((struct ifmediareq64 *)data)->ifmu_ulist) :
1369 		    CAST_USER_ADDR_T(((struct ifmediareq32 *)data)->ifmu_ulist);
1370 		count = ifmr->ifm_count;
1371 		ifmr->ifm_active = IFM_ETHER;
1372 		ifmr->ifm_current = IFM_ETHER;
1373 		ifmr->ifm_mask = 0;
1374 		ifmr->ifm_status = status;
1375 		if (user_addr == USER_ADDR_NULL) {
1376 			ifmr->ifm_count = headlessif->iff_media_count;
1377 		} else if (count > 0) {
1378 			if (count > headlessif->iff_media_count) {
1379 				count = headlessif->iff_media_count;
1380 			}
1381 			ifmr->ifm_count = count;
1382 			error = copyout(&headlessif->iff_media_list, user_addr,
1383 			    count * sizeof(int));
1384 		}
1385 		headless_unlock();
1386 		break;
1387 
1388 	case SIOCGIFDEVMTU:
1389 		devmtu_p = &ifr->ifr_devmtu;
1390 		devmtu_p->ifdm_current = ifnet_mtu(ifp);
1391 		devmtu_p->ifdm_max = headless_max_mtu(ifp);
1392 		devmtu_p->ifdm_min = IF_MINMTU;
1393 		break;
1394 
1395 	case SIOCSIFMTU:
1396 		if ((unsigned int)ifr->ifr_mtu > headless_max_mtu(ifp) ||
1397 		    ifr->ifr_mtu < IF_MINMTU) {
1398 			error = EINVAL;
1399 		} else {
1400 			error = ifnet_set_mtu(ifp, ifr->ifr_mtu);
1401 		}
1402 		break;
1403 
1404 	case SIOCSDRVSPEC32:
1405 	case SIOCSDRVSPEC64:
1406 		error = proc_suser(current_proc());
1407 		if (error != 0) {
1408 			break;
1409 		}
1410 		drv_set_command = TRUE;
1411 		OS_FALLTHROUGH;
1412 	case SIOCGDRVSPEC32:
1413 	case SIOCGDRVSPEC64:
1414 		drv.ifdrvu_p = data;
1415 		if (cmd == SIOCGDRVSPEC32 || cmd == SIOCSDRVSPEC32) {
1416 			drv_cmd = drv.ifdrvu_32->ifd_cmd;
1417 			drv_len = drv.ifdrvu_32->ifd_len;
1418 			user_addr = CAST_USER_ADDR_T(drv.ifdrvu_32->ifd_data);
1419 		} else {
1420 			drv_cmd = drv.ifdrvu_64->ifd_cmd;
1421 			drv_len = drv.ifdrvu_64->ifd_len;
1422 			user_addr = CAST_USER_ADDR_T(drv.ifdrvu_64->ifd_data);
1423 		}
1424 		if (drv_set_command) {
1425 			error = headless_set_drvspec(ifp, drv_cmd,
1426 			    (size_t)drv_len, user_addr);
1427 		} else {
1428 			error = headless_get_drvspec(ifp, drv_cmd,
1429 			    (size_t)drv_len, user_addr);
1430 		}
1431 		break;
1432 
1433 	case SIOCSIFLLADDR:
1434 		error = ifnet_set_lladdr(ifp, ifr->ifr_addr.sa_data,
1435 		    ifr->ifr_addr.sa_len);
1436 		break;
1437 
1438 	case SIOCSIFFLAGS:
1439 		if ((ifp->if_flags & IFF_UP) != 0) {
1440 			/* marked up, set running if not already set */
1441 			if ((ifp->if_flags & IFF_RUNNING) == 0) {
1442 				/* set running */
1443 				error = ifnet_set_flags(ifp, IFF_RUNNING,
1444 				    IFF_RUNNING);
1445 			}
1446 		} else if ((ifp->if_flags & IFF_RUNNING) != 0) {
1447 			/* marked down, clear running */
1448 			error = ifnet_set_flags(ifp, 0, IFF_RUNNING);
1449 		}
1450 		break;
1451 
1452 	case SIOCADDMULTI:
1453 	case SIOCDELMULTI:
1454 		error = 0;
1455 		break;
1456 	default:
1457 		error = EOPNOTSUPP;
1458 		break;
1459 	}
1460 	return error;
1461 }
1462 
1463 static void
headless_if_free(ifnet_t ifp)1464 headless_if_free(ifnet_t ifp)
1465 {
1466 	if_headless_ref             headlessif;
1467 
1468 	if (ifp == NULL) {
1469 		return;
1470 	}
1471 	headless_lock();
1472 	headlessif = ifnet_get_if_headless(ifp);
1473 	if (headlessif == NULL) {
1474 		headless_unlock();
1475 		return;
1476 	}
1477 	ifp->if_softc = NULL;
1478 	assert(headlessif->iff_doorbell_tcall == NULL);
1479 	headless_unlock();
1480 	headless_release(headlessif);
1481 	ifnet_release(ifp);
1482 	return;
1483 }
1484 
1485 void
if_headless_init(void)1486 if_headless_init(void)
1487 {
1488 	int error;
1489 
1490 	(void)headless_register_nexus_domain_provider();
1491 	error = if_clone_attach(&headless_zero_cloner);
1492 	if (error != 0) {
1493 		return;
1494 	}
1495 	error = if_clone_attach(&headless_null_cloner);
1496 	if (error != 0) {
1497 		if_clone_detach(&headless_zero_cloner);
1498 		return;
1499 	}
1500 	return;
1501 }
1502 #else /* !SKYWALK */
1503 extern void if_headless_init(void);
1504 
1505 void
if_headless_init(void)1506 if_headless_init(void)
1507 {
1508 	/* nothing here */
1509 }
1510 #endif /* SKYWALK */
1511