2 * Copyright (c) 2015-2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 * - fake network interface used for testing
32 * - "feth" (e.g. "feth0", "feth1") is a virtual ethernet interface that allows
33 * two instances to have their output/input paths "crossed-over" so that
34 * output on one is input on the other
38 * Modification History:
40 * September 9, 2015 Dieter Siegmund (dieter@apple.com)
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
48 #include <sys/queue.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/sysctl.h>
52 #include <sys/systm.h>
53 #include <sys/kern_event.h>
54 #include <sys/mcache.h>
55 #include <sys/syslog.h>
58 #include <net/ethernet.h>
60 #include <net/if_vlan_var.h>
61 #include <net/if_fake_var.h>
62 #include <net/if_arp.h>
63 #include <net/if_dl.h>
64 #include <net/if_ether.h>
65 #include <net/if_types.h>
66 #include <libkern/OSAtomic.h>
70 #include <net/kpi_interface.h>
71 #include <net/kpi_protocol.h>
73 #include <kern/locks.h>
74 #include <kern/zalloc.h>
77 #include <netinet/in.h>
78 #include <netinet/if_ether.h>
81 #include <net/if_media.h>
82 #include <net/ether_if_module.h>
84 #define FAKE_ETHER_NAME "feth"
86 SYSCTL_DECL(_net_link
);
87 SYSCTL_NODE(_net_link
, OID_AUTO
, fake
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
90 static int if_fake_txstart
= 1;
91 SYSCTL_INT(_net_link_fake
, OID_AUTO
, txstart
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
92 &if_fake_txstart
, 0, "Fake interface TXSTART mode");
94 static int if_fake_hwcsum
= 0;
95 SYSCTL_INT(_net_link_fake
, OID_AUTO
, hwcsum
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
96 &if_fake_hwcsum
, 0, "Fake interface simulate hardware checksum");
98 static int if_fake_nxattach
= 0;
99 SYSCTL_INT(_net_link_fake
, OID_AUTO
, nxattach
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
100 &if_fake_nxattach
, 0, "Fake interface auto-attach nexus");
102 static int if_fake_bsd_mode
= 1;
103 SYSCTL_INT(_net_link_fake
, OID_AUTO
, bsd_mode
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
104 &if_fake_bsd_mode
, 0, "Fake interface attach as BSD interface");
106 static int if_fake_debug
= 0;
107 SYSCTL_INT(_net_link_fake
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
108 &if_fake_debug
, 0, "Fake interface debug logs");
110 static int if_fake_wmm_mode
= 0;
111 SYSCTL_INT(_net_link_fake
, OID_AUTO
, wmm_mode
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
112 &if_fake_wmm_mode
, 0, "Fake interface in 802.11 WMM mode");
115 ** virtual ethernet structures, types
118 #define IFF_NUM_TX_RINGS_WMM_MODE 4
119 #define IFF_NUM_RX_RINGS_WMM_MODE 1
120 #define IFF_MAX_TX_RINGS IFF_NUM_TX_RINGS_WMM_MODE
121 #define IFF_MAX_RX_RINGS IFF_NUM_RX_RINGS_WMM_MODE
123 typedef uint16_t iff_flags_t
;
124 #define IFF_FLAGS_HWCSUM 0x0001
125 #define IFF_FLAGS_BSD_MODE 0x0002
126 #define IFF_FLAGS_DETACHING 0x0004
127 #define IFF_FLAGS_WMM_MODE 0x0008
131 char iff_name
[IFNAMSIZ
]; /* our unique id */
133 iff_flags_t iff_flags
;
134 uint32_t iff_retain_count
;
135 ifnet_t iff_peer
; /* the other end */
136 int iff_media_current
;
137 int iff_media_active
;
138 uint32_t iff_media_count
;
139 int iff_media_list
[IF_FAKE_MEDIA_LIST_MAX
];
140 struct mbuf
* iff_pending_tx_packet
;
141 boolean_t iff_start_busy
;
144 typedef struct if_fake
* if_fake_ref
;
147 ifnet_get_if_fake(ifnet_t ifp
);
149 #define FETH_DPRINTF(fmt, ...) \
150 { if (if_fake_debug != 0) printf("%s " fmt, __func__, ## __VA_ARGS__); }
152 static inline boolean_t
153 feth_in_bsd_mode(if_fake_ref fakeif
)
155 return ((fakeif
->iff_flags
& IFF_FLAGS_BSD_MODE
) != 0);
159 feth_set_detaching(if_fake_ref fakeif
)
161 fakeif
->iff_flags
|= IFF_FLAGS_DETACHING
;
164 static inline boolean_t
165 feth_is_detaching(if_fake_ref fakeif
)
167 return ((fakeif
->iff_flags
& IFF_FLAGS_DETACHING
) != 0);
171 feth_enable_dequeue_stall(ifnet_t ifp
, uint32_t enable
)
176 error
= ifnet_disable_output(ifp
);
178 error
= ifnet_enable_output(ifp
);
184 #define FETH_MAXUNIT IF_MAXUNIT
185 #define FETH_ZONE_MAX_ELEM MIN(IFNETS_MAX, FETH_MAXUNIT)
186 #define M_FAKE M_DEVBUF
188 static int feth_clone_create(struct if_clone
*, u_int32_t
, void *);
189 static int feth_clone_destroy(ifnet_t
);
190 static int feth_output(ifnet_t ifp
, struct mbuf
*m
);
191 static void feth_start(ifnet_t ifp
);
192 static int feth_ioctl(ifnet_t ifp
, u_long cmd
, void * addr
);
193 static int feth_config(ifnet_t ifp
, ifnet_t peer
);
194 static void feth_if_free(ifnet_t ifp
);
195 static void feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
);
196 static void feth_free(if_fake_ref fakeif
);
198 static struct if_clone
199 feth_cloner
= IF_CLONE_INITIALIZER(FAKE_ETHER_NAME
,
205 sizeof(struct if_fake
));
206 static void interface_link_event(ifnet_t ifp
, u_int32_t event_code
);
208 /* some media words to pretend to be ethernet */
209 static int default_media_words
[] = {
210 IFM_MAKEWORD(IFM_ETHER
, 0, 0, 0),
211 IFM_MAKEWORD(IFM_ETHER
, IFM_10G_T
, IFM_FDX
, 0),
212 IFM_MAKEWORD(IFM_ETHER
, IFM_2500_T
, IFM_FDX
, 0),
213 IFM_MAKEWORD(IFM_ETHER
, IFM_5000_T
, IFM_FDX
, 0),
215 #define default_media_words_count (sizeof(default_media_words) \
216 / sizeof (default_media_words[0]))
221 static inline lck_grp_t
*
222 my_lck_grp_alloc_init(const char * grp_name
)
225 lck_grp_attr_t
* grp_attrs
;
227 grp_attrs
= lck_grp_attr_alloc_init();
228 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
229 lck_grp_attr_free(grp_attrs
);
233 static inline lck_mtx_t
*
234 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
236 lck_attr_t
* lck_attrs
;
239 lck_attrs
= lck_attr_alloc_init();
240 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
241 lck_attr_free(lck_attrs
);
245 static lck_mtx_t
* feth_lck_mtx
;
250 lck_grp_t
* feth_lck_grp
;
252 feth_lck_grp
= my_lck_grp_alloc_init("fake");
253 feth_lck_mtx
= my_lck_mtx_alloc_init(feth_lck_grp
);
258 feth_assert_lock_not_held(void)
260 LCK_MTX_ASSERT(feth_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
268 lck_mtx_lock(feth_lck_mtx
);
275 lck_mtx_unlock(feth_lck_mtx
);
283 return (M16KCLBYTES
- ETHER_HDR_LEN
);
285 return (MBIGCLBYTES
- ETHER_HDR_LEN
);
289 feth_free(if_fake_ref fakeif
)
291 assert(fakeif
->iff_retain_count
== 0);
292 if (feth_in_bsd_mode(fakeif
)) {
293 if (fakeif
->iff_pending_tx_packet
) {
294 m_freem(fakeif
->iff_pending_tx_packet
);
298 FETH_DPRINTF("%s\n", fakeif
->iff_name
);
299 if_clone_softc_deallocate(&feth_cloner
, fakeif
);
303 feth_release(if_fake_ref fakeif
)
305 u_int32_t old_retain_count
;
307 old_retain_count
= OSDecrementAtomic(&fakeif
->iff_retain_count
);
308 switch (old_retain_count
) {
310 assert(old_retain_count
!= 0);
323 ** feth interface routines
326 feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
)
328 (void)ifnet_set_capabilities_enabled(ifp
, 0, -1);
329 ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
);
330 ifnet_set_baudrate(ifp
, 0);
331 ifnet_set_mtu(ifp
, ETHERMTU
);
333 IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
,
335 ifnet_set_hdrlen(ifp
, sizeof(struct ether_header
));
336 if ((fakeif
->iff_flags
& IFF_FLAGS_HWCSUM
) != 0) {
337 ifnet_set_offload(ifp
,
338 IFNET_CSUM_IP
| IFNET_CSUM_TCP
| IFNET_CSUM_UDP
|
339 IFNET_CSUM_TCPIPV6
| IFNET_CSUM_UDPIPV6
);
341 ifnet_set_offload(ifp
, 0);
346 interface_link_event(ifnet_t ifp
, u_int32_t event_code
)
349 struct kern_event_msg header
;
351 char if_name
[IFNAMSIZ
];
354 bzero(&event
, sizeof(event
));
355 event
.header
.total_size
= sizeof(event
);
356 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
357 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
358 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
359 event
.header
.event_code
= event_code
;
360 event
.header
.event_data
[0] = ifnet_family(ifp
);
361 event
.unit
= (u_int32_t
) ifnet_unit(ifp
);
362 strlcpy(event
.if_name
, ifnet_name(ifp
), IFNAMSIZ
);
363 ifnet_event(ifp
, &event
.header
);
368 ifnet_get_if_fake(ifnet_t ifp
)
370 return ((if_fake_ref
)ifnet_softc(ifp
));
374 feth_clone_create(struct if_clone
*ifc
, u_int32_t unit
, __unused
void *params
)
378 struct ifnet_init_eparams feth_init
;
380 uint8_t mac_address
[ETHER_ADDR_LEN
];
382 fakeif
= if_clone_softc_allocate(&feth_cloner
);
383 if (fakeif
== NULL
) {
386 fakeif
->iff_retain_count
= 1;
387 #define FAKE_ETHER_NAME_LEN (sizeof(FAKE_ETHER_NAME) - 1)
388 _CASSERT(FAKE_ETHER_NAME_LEN
== 4);
389 bcopy(FAKE_ETHER_NAME
, mac_address
, FAKE_ETHER_NAME_LEN
);
390 mac_address
[ETHER_ADDR_LEN
- 2] = (unit
& 0xff00) >> 8;
391 mac_address
[ETHER_ADDR_LEN
- 1] = unit
& 0xff;
392 if (if_fake_bsd_mode
!= 0) {
393 fakeif
->iff_flags
|= IFF_FLAGS_BSD_MODE
;
395 if (if_fake_hwcsum
!= 0) {
396 fakeif
->iff_flags
|= IFF_FLAGS_HWCSUM
;
399 /* use the interface name as the unique id for ifp recycle */
401 snprintf(fakeif
->iff_name
, sizeof(fakeif
->iff_name
), "%s%d",
402 ifc
->ifc_name
, unit
) >= sizeof(fakeif
->iff_name
)) {
403 feth_release(fakeif
);
406 bzero(&feth_init
, sizeof(feth_init
));
407 feth_init
.ver
= IFNET_INIT_CURRENT_VERSION
;
408 feth_init
.len
= sizeof (feth_init
);
409 if (feth_in_bsd_mode(fakeif
)) {
410 if (if_fake_txstart
!= 0) {
411 feth_init
.start
= feth_start
;
413 feth_init
.flags
|= IFNET_INIT_LEGACY
;
414 feth_init
.output
= feth_output
;
417 if (if_fake_nxattach
== 0) {
418 feth_init
.flags
|= IFNET_INIT_NX_NOAUTO
;
420 feth_init
.uniqueid
= fakeif
->iff_name
;
421 feth_init
.uniqueid_len
= strlen(fakeif
->iff_name
);
422 feth_init
.name
= ifc
->ifc_name
;
423 feth_init
.unit
= unit
;
424 feth_init
.family
= IFNET_FAMILY_ETHERNET
;
425 feth_init
.type
= IFT_ETHER
;
426 feth_init
.demux
= ether_demux
;
427 feth_init
.add_proto
= ether_add_proto
;
428 feth_init
.del_proto
= ether_del_proto
;
429 feth_init
.check_multi
= ether_check_multi
;
430 feth_init
.framer_extended
= ether_frameout_extended
;
431 feth_init
.softc
= fakeif
;
432 feth_init
.ioctl
= feth_ioctl
;
433 feth_init
.set_bpf_tap
= NULL
;
434 feth_init
.detach
= feth_if_free
;
435 feth_init
.broadcast_addr
= etherbroadcastaddr
;
436 feth_init
.broadcast_len
= ETHER_ADDR_LEN
;
437 if (feth_in_bsd_mode(fakeif
)) {
438 error
= ifnet_allocate_extended(&feth_init
, &ifp
);
440 feth_release(fakeif
);
443 feth_ifnet_set_attrs(fakeif
, ifp
);
445 fakeif
->iff_media_count
= default_media_words_count
;
446 bcopy(default_media_words
, fakeif
->iff_media_list
,
447 sizeof(default_media_words
));
448 if (feth_in_bsd_mode(fakeif
)) {
449 error
= ifnet_attach(ifp
, NULL
);
452 feth_release(fakeif
);
455 fakeif
->iff_ifp
= ifp
;
458 ifnet_set_lladdr(ifp
, mac_address
, sizeof(mac_address
));
460 /* attach as ethernet */
461 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
466 feth_clone_destroy(ifnet_t ifp
)
471 fakeif
= ifnet_get_if_fake(ifp
);
472 if (fakeif
== NULL
|| feth_is_detaching(fakeif
)) {
476 feth_set_detaching(fakeif
);
479 feth_config(ifp
, NULL
);
485 feth_enqueue_input(ifnet_t ifp
, struct mbuf
* m
)
487 struct ifnet_stat_increment_param stats
= {};
489 stats
.packets_in
= 1;
490 stats
.bytes_in
= (uint32_t)mbuf_pkthdr_len(m
) + ETHER_HDR_LEN
;
491 ifnet_input(ifp
, m
, &stats
);
495 copy_mbuf(struct mbuf
*m
)
497 struct mbuf
* copy_m
;
501 if ((m
->m_flags
& M_PKTHDR
) == 0) {
504 pkt_len
= m
->m_pkthdr
.len
;
505 MGETHDR(copy_m
, M_DONTWAIT
, MT_DATA
);
506 if (copy_m
== NULL
) {
509 if (pkt_len
> MHLEN
) {
510 if (pkt_len
<= MCLBYTES
) {
511 MCLGET(copy_m
, M_DONTWAIT
);
512 } else if (pkt_len
<= MBIGCLBYTES
) {
513 copy_m
= m_mbigget(copy_m
, M_DONTWAIT
);
514 } else if (pkt_len
<= M16KCLBYTES
&& njcl
> 0) {
515 copy_m
= m_m16kget(copy_m
, M_DONTWAIT
);
517 printf("if_fake: copy_mbuf(): packet too large %d\n",
521 if (copy_m
== NULL
|| (copy_m
->m_flags
& M_EXT
) == 0) {
525 mbuf_setlen(copy_m
, pkt_len
);
526 copy_m
->m_pkthdr
.len
= pkt_len
;
527 copy_m
->m_pkthdr
.pkt_svc
= m
->m_pkthdr
.pkt_svc
;
529 while (m
!= NULL
&& offset
< pkt_len
) {
533 if (frag_len
> (pkt_len
- offset
)) {
534 printf("if_fake_: Large mbuf fragment %d > %d\n",
535 frag_len
, (pkt_len
- offset
));
538 m_copydata(m
, 0, frag_len
, mtod(copy_m
, void *) + offset
);
545 if (copy_m
!= NULL
) {
552 feth_output_common(ifnet_t ifp
, struct mbuf
* m
, ifnet_t peer
,
557 frame_header
= mbuf_data(m
);
558 if ((flags
& IFF_FLAGS_HWCSUM
) != 0) {
559 m
->m_pkthdr
.csum_data
= 0xffff;
560 m
->m_pkthdr
.csum_flags
=
561 CSUM_DATA_VALID
| CSUM_PSEUDO_HDR
|
562 CSUM_IP_CHECKED
| CSUM_IP_VALID
;
565 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
566 bpf_tap_out(ifp
, DLT_EN10MB
, m
, NULL
, 0);
568 (void)mbuf_pkthdr_setrcvif(m
, peer
);
569 mbuf_pkthdr_setheader(m
, frame_header
);
570 mbuf_pkthdr_adjustlen(m
, - ETHER_HDR_LEN
);
571 (void)mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
572 mbuf_len(m
) - ETHER_HDR_LEN
);
573 bpf_tap_in(peer
, DLT_EN10MB
, m
, frame_header
,
574 sizeof(struct ether_header
));
575 feth_enqueue_input(peer
, m
);
579 feth_start(ifnet_t ifp
)
581 struct mbuf
* copy_m
= NULL
;
583 iff_flags_t flags
= 0;
586 struct mbuf
* save_m
;
589 fakeif
= ifnet_get_if_fake(ifp
);
590 if (fakeif
->iff_start_busy
) {
592 printf("if_fake: start is busy\n");
595 if (fakeif
!= NULL
) {
596 peer
= fakeif
->iff_peer
;
597 flags
= fakeif
->iff_flags
;
600 /* check for pending TX */
601 m
= fakeif
->iff_pending_tx_packet
;
604 copy_m
= copy_mbuf(m
);
605 if (copy_m
== NULL
) {
610 fakeif
->iff_pending_tx_packet
= NULL
;
614 fakeif
->iff_start_busy
= TRUE
;
618 if (copy_m
!= NULL
) {
619 assert(peer
!= NULL
);
620 feth_output_common(ifp
, copy_m
, peer
, flags
);
623 if (ifnet_dequeue(ifp
, &m
) != 0) {
629 copy_m
= copy_mbuf(m
);
630 if (copy_m
== NULL
) {
639 fakeif
= ifnet_get_if_fake(ifp
);
640 if (fakeif
!= NULL
) {
641 fakeif
->iff_start_busy
= FALSE
;
642 if (save_m
!= NULL
&& fakeif
->iff_peer
!= NULL
) {
643 /* save it for next time */
644 fakeif
->iff_pending_tx_packet
= save_m
;
649 if (save_m
!= NULL
) {
650 /* didn't save packet, so free it */
656 feth_output(ifnet_t ifp
, struct mbuf
* m
)
658 struct mbuf
* copy_m
;
666 copy_m
= copy_mbuf(m
);
669 if (copy_m
== NULL
) {
670 /* count this as an output error */
671 ifnet_stat_increment_out(ifp
, 0, 0, 1);
675 fakeif
= ifnet_get_if_fake(ifp
);
676 if (fakeif
!= NULL
) {
677 peer
= fakeif
->iff_peer
;
678 flags
= fakeif
->iff_flags
;
683 ifnet_stat_increment_out(ifp
, 0, 0, 1);
686 feth_output_common(ifp
, copy_m
, peer
, flags
);
691 feth_config(ifnet_t ifp
, ifnet_t peer
)
693 int connected
= FALSE
;
694 int disconnected
= FALSE
;
696 if_fake_ref fakeif
= NULL
;
699 fakeif
= ifnet_get_if_fake(ifp
);
700 if (fakeif
== NULL
) {
705 /* connect to peer */
706 if_fake_ref peer_fakeif
;
708 peer_fakeif
= ifnet_get_if_fake(peer
);
709 if (peer_fakeif
== NULL
) {
713 if (feth_is_detaching(fakeif
) ||
714 feth_is_detaching(peer_fakeif
) ||
715 peer_fakeif
->iff_peer
!= NULL
||
716 fakeif
->iff_peer
!= NULL
) {
720 fakeif
->iff_peer
= peer
;
721 peer_fakeif
->iff_peer
= ifp
;
724 else if (fakeif
->iff_peer
!= NULL
) {
725 /* disconnect from peer */
726 if_fake_ref peer_fakeif
;
728 peer
= fakeif
->iff_peer
;
729 peer_fakeif
= ifnet_get_if_fake(peer
);
730 if (peer_fakeif
== NULL
) {
731 /* should not happen */
735 fakeif
->iff_peer
= NULL
;
736 peer_fakeif
->iff_peer
= NULL
;
743 /* generate link status event if we connect or disconnect */
745 interface_link_event(ifp
, KEV_DL_LINK_ON
);
746 interface_link_event(peer
, KEV_DL_LINK_ON
);
748 else if (disconnected
) {
749 interface_link_event(ifp
, KEV_DL_LINK_OFF
);
750 interface_link_event(peer
, KEV_DL_LINK_OFF
);
756 feth_set_media(ifnet_t ifp
, struct if_fake_request
* iffr
)
761 if (iffr
->iffr_media
.iffm_count
> IF_FAKE_MEDIA_LIST_MAX
) {
762 /* list is too long */
766 fakeif
= ifnet_get_if_fake(ifp
);
767 if (fakeif
== NULL
) {
771 fakeif
->iff_media_count
= iffr
->iffr_media
.iffm_count
;
772 bcopy(iffr
->iffr_media
.iffm_list
, fakeif
->iff_media_list
,
773 iffr
->iffr_media
.iffm_count
* sizeof(fakeif
->iff_media_list
[0]));
775 /* XXX: "auto-negotiate" active with peer? */
776 /* generate link status event? */
777 fakeif
->iff_media_current
= iffr
->iffr_media
.iffm_current
;
786 if_fake_request_copyin(user_addr_t user_addr
,
787 struct if_fake_request
*iffr
, u_int32_t len
)
791 if (user_addr
== USER_ADDR_NULL
|| len
< sizeof(*iffr
)) {
795 error
= copyin(user_addr
, iffr
, sizeof(*iffr
));
799 if (iffr
->iffr_reserved
[0] != 0 || iffr
->iffr_reserved
[1] != 0 ||
800 iffr
->iffr_reserved
[2] != 0 || iffr
->iffr_reserved
[3] != 0) {
809 feth_set_drvspec(ifnet_t ifp
, uint32_t cmd
, u_int32_t len
,
810 user_addr_t user_addr
)
813 struct if_fake_request iffr
;
817 case IF_FAKE_S_CMD_SET_PEER
:
818 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
822 if (iffr
.iffr_peer_name
[0] == '\0') {
823 error
= feth_config(ifp
, NULL
);
827 /* ensure nul termination */
828 iffr
.iffr_peer_name
[IFNAMSIZ
- 1] = '\0';
829 peer
= ifunit(iffr
.iffr_peer_name
);
834 if (ifnet_type(peer
) != IFT_ETHER
) {
838 if (strcmp(ifnet_name(peer
), FAKE_ETHER_NAME
) != 0) {
842 error
= feth_config(ifp
, peer
);
844 case IF_FAKE_S_CMD_SET_MEDIA
:
845 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
849 error
= feth_set_media(ifp
, &iffr
);
851 case IF_FAKE_S_CMD_SET_DEQUEUE_STALL
:
852 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
856 error
= feth_enable_dequeue_stall(ifp
,
857 iffr
.iffr_dequeue_stall
);
867 feth_get_drvspec(ifnet_t ifp
, u_int32_t cmd
, u_int32_t len
,
868 user_addr_t user_addr
)
870 int error
= EOPNOTSUPP
;
872 struct if_fake_request iffr
;
876 case IF_FAKE_G_CMD_GET_PEER
:
877 if (len
< sizeof(iffr
)) {
882 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
883 if (fakeif
== NULL
) {
888 peer
= fakeif
->iff_peer
;
890 bzero(&iffr
, sizeof(iffr
));
892 strlcpy(iffr
.iffr_peer_name
,
894 sizeof(iffr
.iffr_peer_name
));
896 error
= copyout(&iffr
, user_addr
, sizeof(iffr
));
905 struct ifdrv32
*ifdrvu_32
;
906 struct ifdrv64
*ifdrvu_64
;
911 feth_ioctl(ifnet_t ifp
, u_long cmd
, void * data
)
914 struct ifdevmtu
* devmtu_p
;
918 boolean_t drv_set_command
= FALSE
;
920 struct ifmediareq
* ifmr
;
924 user_addr_t user_addr
;
926 ifr
= (struct ifreq
*)data
;
929 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
935 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
936 if (fakeif
== NULL
) {
940 status
= (fakeif
->iff_peer
!= NULL
)
941 ? (IFM_AVALID
| IFM_ACTIVE
) : IFM_AVALID
;
942 ifmr
= (struct ifmediareq
*)data
;
943 user_addr
= (cmd
== SIOCGIFMEDIA64
) ?
944 ((struct ifmediareq64
*)ifmr
)->ifmu_ulist
:
945 CAST_USER_ADDR_T(((struct ifmediareq32
*)ifmr
)->ifmu_ulist
);
946 count
= ifmr
->ifm_count
;
947 ifmr
->ifm_active
= IFM_ETHER
;
948 ifmr
->ifm_current
= IFM_ETHER
;
950 ifmr
->ifm_status
= status
;
951 if (user_addr
== USER_ADDR_NULL
) {
952 ifmr
->ifm_count
= fakeif
->iff_media_count
;
954 else if (count
> 0) {
955 if (count
> fakeif
->iff_media_count
) {
956 count
= fakeif
->iff_media_count
;
958 ifmr
->ifm_count
= count
;
959 error
= copyout(&fakeif
->iff_media_list
, user_addr
,
960 count
* sizeof(int));
966 devmtu_p
= &ifr
->ifr_devmtu
;
967 devmtu_p
->ifdm_current
= ifnet_mtu(ifp
);
968 devmtu_p
->ifdm_max
= feth_max_mtu();
969 devmtu_p
->ifdm_min
= IF_MINMTU
;
973 if (ifr
->ifr_mtu
> feth_max_mtu() || ifr
->ifr_mtu
< IF_MINMTU
) {
976 error
= ifnet_set_mtu(ifp
, ifr
->ifr_mtu
);
982 error
= proc_suser(current_proc());
986 drv_set_command
= TRUE
;
991 if (cmd
== SIOCGDRVSPEC32
|| cmd
== SIOCSDRVSPEC32
) {
992 drv_cmd
= drv
.ifdrvu_32
->ifd_cmd
;
993 drv_len
= drv
.ifdrvu_32
->ifd_len
;
994 user_addr
= CAST_USER_ADDR_T(drv
.ifdrvu_32
->ifd_data
);
997 drv_cmd
= drv
.ifdrvu_64
->ifd_cmd
;
998 drv_len
= drv
.ifdrvu_64
->ifd_len
;
999 user_addr
= drv
.ifdrvu_64
->ifd_data
;
1001 if (drv_set_command
) {
1002 error
= feth_set_drvspec(ifp
, drv_cmd
, drv_len
,
1005 error
= feth_get_drvspec(ifp
, drv_cmd
, drv_len
,
1011 error
= ifnet_set_lladdr(ifp
, ifr
->ifr_addr
.sa_data
,
1012 ifr
->ifr_addr
.sa_len
);
1016 if ((ifp
->if_flags
& IFF_UP
) != 0) {
1017 /* marked up, set running if not already set */
1018 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
1020 error
= ifnet_set_flags(ifp
, IFF_RUNNING
,
1023 } else if ((ifp
->if_flags
& IFF_RUNNING
) != 0) {
1024 /* marked down, clear running */
1025 error
= ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
1041 feth_if_free(ifnet_t ifp
)
1049 fakeif
= ifnet_get_if_fake(ifp
);
1050 if (fakeif
== NULL
) {
1054 ifp
->if_softc
= NULL
;
1056 feth_release(fakeif
);
1061 __private_extern__
void
1067 error
= if_clone_attach(&feth_cloner
);