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