2 * Copyright (c) 2015-2017 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>
76 #include <netinet/in.h>
77 #include <netinet/if_ether.h>
80 #include <net/if_media.h>
81 #include <net/ether_if_module.h>
83 #define FAKE_ETHER_NAME "feth"
85 SYSCTL_DECL(_net_link
);
86 SYSCTL_NODE(_net_link
, OID_AUTO
, fake
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
89 static int if_fake_txstart
= 1;
90 SYSCTL_INT(_net_link_fake
, OID_AUTO
, txstart
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
91 &if_fake_txstart
, 0, "Fake interface TXSTART mode");
93 static int if_fake_hwcsum
= 0;
94 SYSCTL_INT(_net_link_fake
, OID_AUTO
, hwcsum
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
95 &if_fake_hwcsum
, 0, "Fake interface simulate hardware checksum");
97 static int if_fake_nxattach
= 0;
98 SYSCTL_INT(_net_link_fake
, OID_AUTO
, nxattach
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
99 &if_fake_nxattach
, 0, "Fake interface auto-attach nexus");
101 static int if_fake_bsd_mode
= 1;
102 SYSCTL_INT(_net_link_fake
, OID_AUTO
, bsd_mode
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
103 &if_fake_bsd_mode
, 0, "Fake interface attach as BSD interface");
105 static int if_fake_debug
= 0;
106 SYSCTL_INT(_net_link_fake
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
107 &if_fake_debug
, 0, "Fake interface debug logs");
110 ** virtual ethernet structures, types
113 typedef uint16_t iff_flags_t
;
114 #define IFF_FLAGS_HWCSUM 0x0001
115 #define IFF_FLAGS_BSD_MODE 0x0002
116 #define IFF_FLAGS_DETACHING 0x0004
120 char iff_name
[IFNAMSIZ
]; /* our unique id */
122 iff_flags_t iff_flags
;
123 uint32_t iff_retain_count
;
124 ifnet_t iff_peer
; /* the other end */
125 int iff_media_current
;
126 int iff_media_active
;
127 uint32_t iff_media_count
;
128 int iff_media_list
[IF_FAKE_MEDIA_LIST_MAX
];
129 struct mbuf
* iff_pending_tx_packet
;
130 boolean_t iff_start_busy
;
133 typedef struct if_fake
* if_fake_ref
;
136 ifnet_get_if_fake(ifnet_t ifp
);
138 #define FETH_DPRINTF(fmt, ...) \
139 { if (if_fake_debug != 0) printf("%s " fmt, __func__, ## __VA_ARGS__); }
141 static inline boolean_t
142 feth_in_bsd_mode(if_fake_ref fakeif
)
144 return ((fakeif
->iff_flags
& IFF_FLAGS_BSD_MODE
) != 0);
148 feth_set_detaching(if_fake_ref fakeif
)
150 fakeif
->iff_flags
|= IFF_FLAGS_DETACHING
;
153 static inline boolean_t
154 feth_is_detaching(if_fake_ref fakeif
)
156 return ((fakeif
->iff_flags
& IFF_FLAGS_DETACHING
) != 0);
160 feth_enable_dequeue_stall(ifnet_t ifp
, uint32_t enable
)
165 error
= ifnet_disable_output(ifp
);
167 error
= ifnet_enable_output(ifp
);
172 #define M_FAKE M_DEVBUF
174 static int feth_clone_create(struct if_clone
*, u_int32_t
, void *);
175 static int feth_clone_destroy(ifnet_t
);
176 static int feth_output(ifnet_t ifp
, struct mbuf
*m
);
177 static void feth_start(ifnet_t ifp
);
178 static int feth_ioctl(ifnet_t ifp
, u_long cmd
, void * addr
);
179 static int feth_config(ifnet_t ifp
, ifnet_t peer
);
180 static void feth_if_free(ifnet_t ifp
);
181 static void feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
);
182 static void feth_free(if_fake_ref fakeif
);
184 static struct if_clone
185 feth_cloner
= IF_CLONE_INITIALIZER(FAKE_ETHER_NAME
,
190 static void interface_link_event(ifnet_t ifp
, u_int32_t event_code
);
192 /* some media words to pretend to be ethernet */
193 static int default_media_words
[] = {
194 IFM_MAKEWORD(IFM_ETHER
, 0, 0, 0),
195 IFM_MAKEWORD(IFM_ETHER
, IFM_10G_T
, IFM_FDX
, 0),
196 IFM_MAKEWORD(IFM_ETHER
, IFM_2500_T
, IFM_FDX
, 0),
197 IFM_MAKEWORD(IFM_ETHER
, IFM_5000_T
, IFM_FDX
, 0),
199 #define default_media_words_count (sizeof(default_media_words) \
200 / sizeof (default_media_words[0]))
205 static inline lck_grp_t
*
206 my_lck_grp_alloc_init(const char * grp_name
)
209 lck_grp_attr_t
* grp_attrs
;
211 grp_attrs
= lck_grp_attr_alloc_init();
212 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
213 lck_grp_attr_free(grp_attrs
);
217 static inline lck_mtx_t
*
218 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
220 lck_attr_t
* lck_attrs
;
223 lck_attrs
= lck_attr_alloc_init();
224 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
225 lck_attr_free(lck_attrs
);
229 static lck_mtx_t
* feth_lck_mtx
;
234 lck_grp_t
* feth_lck_grp
;
236 feth_lck_grp
= my_lck_grp_alloc_init("fake");
237 feth_lck_mtx
= my_lck_mtx_alloc_init(feth_lck_grp
);
242 feth_assert_lock_not_held(void)
244 LCK_MTX_ASSERT(feth_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
252 lck_mtx_lock(feth_lck_mtx
);
259 lck_mtx_unlock(feth_lck_mtx
);
267 return (M16KCLBYTES
- ETHER_HDR_LEN
);
269 return (MBIGCLBYTES
- ETHER_HDR_LEN
);
273 feth_free(if_fake_ref fakeif
)
275 assert(fakeif
->iff_retain_count
== 0);
276 if (feth_in_bsd_mode(fakeif
)) {
277 if (fakeif
->iff_pending_tx_packet
) {
278 m_freem(fakeif
->iff_pending_tx_packet
);
282 FETH_DPRINTF("%s\n", fakeif
->iff_name
);
283 FREE(fakeif
, M_FAKE
);
287 feth_release(if_fake_ref fakeif
)
289 u_int32_t old_retain_count
;
291 old_retain_count
= OSDecrementAtomic(&fakeif
->iff_retain_count
);
292 switch (old_retain_count
) {
294 assert(old_retain_count
!= 0);
307 ** feth interface routines
310 feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
)
312 (void)ifnet_set_capabilities_enabled(ifp
, 0, -1);
313 ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
);
314 ifnet_set_baudrate(ifp
, 0);
315 ifnet_set_mtu(ifp
, ETHERMTU
);
317 IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
,
319 ifnet_set_hdrlen(ifp
, sizeof(struct ether_header
));
320 if ((fakeif
->iff_flags
& IFF_FLAGS_HWCSUM
) != 0) {
321 ifnet_set_offload(ifp
,
322 IFNET_CSUM_IP
| IFNET_CSUM_TCP
| IFNET_CSUM_UDP
|
323 IFNET_CSUM_TCPIPV6
| IFNET_CSUM_UDPIPV6
);
325 ifnet_set_offload(ifp
, 0);
330 interface_link_event(ifnet_t ifp
, u_int32_t event_code
)
333 struct kern_event_msg header
;
335 char if_name
[IFNAMSIZ
];
338 bzero(&event
, sizeof(event
));
339 event
.header
.total_size
= sizeof(event
);
340 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
341 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
342 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
343 event
.header
.event_code
= event_code
;
344 event
.header
.event_data
[0] = ifnet_family(ifp
);
345 event
.unit
= (u_int32_t
) ifnet_unit(ifp
);
346 strlcpy(event
.if_name
, ifnet_name(ifp
), IFNAMSIZ
);
347 ifnet_event(ifp
, &event
.header
);
352 ifnet_get_if_fake(ifnet_t ifp
)
354 return ((if_fake_ref
)ifnet_softc(ifp
));
358 feth_clone_create(struct if_clone
*ifc
, u_int32_t unit
, __unused
void *params
)
362 struct ifnet_init_eparams feth_init
;
364 uint8_t mac_address
[ETHER_ADDR_LEN
];
366 fakeif
= _MALLOC(sizeof(struct if_fake
), M_FAKE
, M_WAITOK
| M_ZERO
);
367 if (fakeif
== NULL
) {
370 fakeif
->iff_retain_count
= 1;
371 #define FAKE_ETHER_NAME_LEN (sizeof(FAKE_ETHER_NAME) - 1)
372 _CASSERT(FAKE_ETHER_NAME_LEN
== 4);
373 bcopy(FAKE_ETHER_NAME
, mac_address
, FAKE_ETHER_NAME_LEN
);
374 mac_address
[ETHER_ADDR_LEN
- 2] = (unit
& 0xff00) >> 8;
375 mac_address
[ETHER_ADDR_LEN
- 1] = unit
& 0xff;
376 if (if_fake_bsd_mode
!= 0) {
377 fakeif
->iff_flags
|= IFF_FLAGS_BSD_MODE
;
379 if (if_fake_hwcsum
!= 0) {
380 fakeif
->iff_flags
|= IFF_FLAGS_HWCSUM
;
383 /* use the interface name as the unique id for ifp recycle */
385 snprintf(fakeif
->iff_name
, sizeof(fakeif
->iff_name
), "%s%d",
386 ifc
->ifc_name
, unit
) >= sizeof(fakeif
->iff_name
)) {
387 feth_release(fakeif
);
390 bzero(&feth_init
, sizeof(feth_init
));
391 feth_init
.ver
= IFNET_INIT_CURRENT_VERSION
;
392 feth_init
.len
= sizeof (feth_init
);
393 if (feth_in_bsd_mode(fakeif
)) {
394 if (if_fake_txstart
!= 0) {
395 feth_init
.start
= feth_start
;
397 feth_init
.flags
|= IFNET_INIT_LEGACY
;
398 feth_init
.output
= feth_output
;
401 if (if_fake_nxattach
== 0) {
402 feth_init
.flags
|= IFNET_INIT_NX_NOAUTO
;
404 feth_init
.uniqueid
= fakeif
->iff_name
;
405 feth_init
.uniqueid_len
= strlen(fakeif
->iff_name
);
406 feth_init
.name
= ifc
->ifc_name
;
407 feth_init
.unit
= unit
;
408 feth_init
.family
= IFNET_FAMILY_ETHERNET
;
409 feth_init
.type
= IFT_ETHER
;
410 feth_init
.demux
= ether_demux
;
411 feth_init
.add_proto
= ether_add_proto
;
412 feth_init
.del_proto
= ether_del_proto
;
413 feth_init
.check_multi
= ether_check_multi
;
414 feth_init
.framer_extended
= ether_frameout_extended
;
415 feth_init
.softc
= fakeif
;
416 feth_init
.ioctl
= feth_ioctl
;
417 feth_init
.set_bpf_tap
= NULL
;
418 feth_init
.detach
= feth_if_free
;
419 feth_init
.broadcast_addr
= etherbroadcastaddr
;
420 feth_init
.broadcast_len
= ETHER_ADDR_LEN
;
421 if (feth_in_bsd_mode(fakeif
)) {
422 error
= ifnet_allocate_extended(&feth_init
, &ifp
);
424 feth_release(fakeif
);
427 feth_ifnet_set_attrs(fakeif
, ifp
);
429 fakeif
->iff_media_count
= default_media_words_count
;
430 bcopy(default_media_words
, fakeif
->iff_media_list
,
431 sizeof(default_media_words
));
432 if (feth_in_bsd_mode(fakeif
)) {
433 error
= ifnet_attach(ifp
, NULL
);
436 feth_release(fakeif
);
439 fakeif
->iff_ifp
= ifp
;
442 ifnet_set_lladdr(ifp
, mac_address
, sizeof(mac_address
));
444 /* attach as ethernet */
445 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
450 feth_clone_destroy(ifnet_t ifp
)
455 fakeif
= ifnet_get_if_fake(ifp
);
456 if (fakeif
== NULL
|| feth_is_detaching(fakeif
)) {
460 feth_set_detaching(fakeif
);
463 feth_config(ifp
, NULL
);
469 feth_enqueue_input(ifnet_t ifp
, struct mbuf
* m
)
471 struct ifnet_stat_increment_param stats
= {};
473 stats
.packets_in
= 1;
474 stats
.bytes_in
= (uint32_t)mbuf_pkthdr_len(m
) + ETHER_HDR_LEN
;
475 ifnet_input(ifp
, m
, &stats
);
479 copy_mbuf(struct mbuf
*m
)
481 struct mbuf
* copy_m
;
485 if ((m
->m_flags
& M_PKTHDR
) == 0) {
488 pkt_len
= m
->m_pkthdr
.len
;
489 MGETHDR(copy_m
, M_DONTWAIT
, MT_DATA
);
490 if (copy_m
== NULL
) {
493 if (pkt_len
> MHLEN
) {
494 if (pkt_len
<= MCLBYTES
) {
495 MCLGET(copy_m
, M_DONTWAIT
);
496 } else if (pkt_len
<= MBIGCLBYTES
) {
497 copy_m
= m_mbigget(copy_m
, M_DONTWAIT
);
498 } else if (pkt_len
<= M16KCLBYTES
&& njcl
> 0) {
499 copy_m
= m_m16kget(copy_m
, M_DONTWAIT
);
501 printf("if_fake: copy_mbuf(): packet too large %d\n",
505 if (copy_m
== NULL
|| (copy_m
->m_flags
& M_EXT
) == 0) {
509 mbuf_setlen(copy_m
, pkt_len
);
510 copy_m
->m_pkthdr
.len
= pkt_len
;
512 while (m
!= NULL
&& offset
< pkt_len
) {
516 if (frag_len
> (pkt_len
- offset
)) {
517 printf("if_fake_: Large mbuf fragment %d > %d\n",
518 frag_len
, (pkt_len
- offset
));
521 m_copydata(m
, 0, frag_len
, mtod(copy_m
, void *) + offset
);
528 if (copy_m
!= NULL
) {
535 feth_output_common(ifnet_t ifp
, struct mbuf
* m
, ifnet_t peer
,
540 frame_header
= mbuf_data(m
);
541 if ((flags
& IFF_FLAGS_HWCSUM
) != 0) {
542 m
->m_pkthdr
.csum_data
= 0xffff;
543 m
->m_pkthdr
.csum_flags
=
544 CSUM_DATA_VALID
| CSUM_PSEUDO_HDR
|
545 CSUM_IP_CHECKED
| CSUM_IP_VALID
;
548 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
549 bpf_tap_out(ifp
, DLT_EN10MB
, m
, NULL
, 0);
551 (void)mbuf_pkthdr_setrcvif(m
, peer
);
552 mbuf_pkthdr_setheader(m
, frame_header
);
553 mbuf_pkthdr_adjustlen(m
, - ETHER_HDR_LEN
);
554 (void)mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
555 mbuf_len(m
) - ETHER_HDR_LEN
);
556 bpf_tap_in(peer
, DLT_EN10MB
, m
, frame_header
,
557 sizeof(struct ether_header
));
558 feth_enqueue_input(peer
, m
);
562 feth_start(ifnet_t ifp
)
564 struct mbuf
* copy_m
= NULL
;
566 iff_flags_t flags
= 0;
569 struct mbuf
* save_m
;
572 fakeif
= ifnet_get_if_fake(ifp
);
573 if (fakeif
->iff_start_busy
) {
575 printf("if_fake: start is busy\n");
578 if (fakeif
!= NULL
) {
579 peer
= fakeif
->iff_peer
;
580 flags
= fakeif
->iff_flags
;
583 /* check for pending TX */
584 m
= fakeif
->iff_pending_tx_packet
;
587 copy_m
= copy_mbuf(m
);
588 if (copy_m
== NULL
) {
593 fakeif
->iff_pending_tx_packet
= NULL
;
597 fakeif
->iff_start_busy
= TRUE
;
601 if (copy_m
!= NULL
) {
602 assert(peer
!= NULL
);
603 feth_output_common(ifp
, copy_m
, peer
, flags
);
606 if (ifnet_dequeue(ifp
, &m
) != 0) {
612 copy_m
= copy_mbuf(m
);
613 if (copy_m
== NULL
) {
622 fakeif
= ifnet_get_if_fake(ifp
);
623 if (fakeif
!= NULL
) {
624 fakeif
->iff_start_busy
= FALSE
;
625 if (save_m
!= NULL
&& fakeif
->iff_peer
!= NULL
) {
626 /* save it for next time */
627 fakeif
->iff_pending_tx_packet
= save_m
;
632 if (save_m
!= NULL
) {
633 /* didn't save packet, so free it */
639 feth_output(ifnet_t ifp
, struct mbuf
* m
)
641 struct mbuf
* copy_m
;
649 copy_m
= copy_mbuf(m
);
652 if (copy_m
== NULL
) {
653 /* count this as an output error */
654 ifnet_stat_increment_out(ifp
, 0, 0, 1);
658 fakeif
= ifnet_get_if_fake(ifp
);
659 if (fakeif
!= NULL
) {
660 peer
= fakeif
->iff_peer
;
661 flags
= fakeif
->iff_flags
;
666 ifnet_stat_increment_out(ifp
, 0, 0, 1);
669 feth_output_common(ifp
, copy_m
, peer
, flags
);
674 feth_config(ifnet_t ifp
, ifnet_t peer
)
676 int connected
= FALSE
;
677 int disconnected
= FALSE
;
679 if_fake_ref fakeif
= NULL
;
682 fakeif
= ifnet_get_if_fake(ifp
);
683 if (fakeif
== NULL
) {
688 /* connect to peer */
689 if_fake_ref peer_fakeif
;
691 peer_fakeif
= ifnet_get_if_fake(peer
);
692 if (peer_fakeif
== NULL
) {
696 if (feth_is_detaching(fakeif
) ||
697 feth_is_detaching(peer_fakeif
) ||
698 peer_fakeif
->iff_peer
!= NULL
||
699 fakeif
->iff_peer
!= NULL
) {
703 fakeif
->iff_peer
= peer
;
704 peer_fakeif
->iff_peer
= ifp
;
707 else if (fakeif
->iff_peer
!= NULL
) {
708 /* disconnect from peer */
709 if_fake_ref peer_fakeif
;
711 peer
= fakeif
->iff_peer
;
712 peer_fakeif
= ifnet_get_if_fake(peer
);
713 if (peer_fakeif
== NULL
) {
714 /* should not happen */
718 fakeif
->iff_peer
= NULL
;
719 peer_fakeif
->iff_peer
= NULL
;
726 /* generate link status event if we connect or disconnect */
728 interface_link_event(ifp
, KEV_DL_LINK_ON
);
729 interface_link_event(peer
, KEV_DL_LINK_ON
);
731 else if (disconnected
) {
732 interface_link_event(ifp
, KEV_DL_LINK_OFF
);
733 interface_link_event(peer
, KEV_DL_LINK_OFF
);
739 feth_set_media(ifnet_t ifp
, struct if_fake_request
* iffr
)
744 if (iffr
->iffr_media
.iffm_count
> IF_FAKE_MEDIA_LIST_MAX
) {
745 /* list is too long */
749 fakeif
= ifnet_get_if_fake(ifp
);
750 if (fakeif
== NULL
) {
754 fakeif
->iff_media_count
= iffr
->iffr_media
.iffm_count
;
755 bcopy(iffr
->iffr_media
.iffm_list
, fakeif
->iff_media_list
,
756 iffr
->iffr_media
.iffm_count
* sizeof(fakeif
->iff_media_list
[0]));
758 /* XXX: "auto-negotiate" active with peer? */
759 /* generate link status event? */
760 fakeif
->iff_media_current
= iffr
->iffr_media
.iffm_current
;
769 if_fake_request_copyin(user_addr_t user_addr
,
770 struct if_fake_request
*iffr
, u_int32_t len
)
774 if (user_addr
== USER_ADDR_NULL
|| len
< sizeof(*iffr
)) {
778 error
= copyin(user_addr
, iffr
, sizeof(*iffr
));
782 if (iffr
->iffr_reserved
[0] != 0 || iffr
->iffr_reserved
[1] != 0 ||
783 iffr
->iffr_reserved
[2] != 0 || iffr
->iffr_reserved
[3] != 0) {
792 feth_set_drvspec(ifnet_t ifp
, uint32_t cmd
, u_int32_t len
,
793 user_addr_t user_addr
)
796 struct if_fake_request iffr
;
800 case IF_FAKE_S_CMD_SET_PEER
:
801 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
805 if (iffr
.iffr_peer_name
[0] == '\0') {
806 error
= feth_config(ifp
, NULL
);
810 /* ensure nul termination */
811 iffr
.iffr_peer_name
[IFNAMSIZ
- 1] = '\0';
812 peer
= ifunit(iffr
.iffr_peer_name
);
817 if (ifnet_type(peer
) != IFT_ETHER
) {
821 if (strcmp(ifnet_name(peer
), FAKE_ETHER_NAME
) != 0) {
825 error
= feth_config(ifp
, peer
);
827 case IF_FAKE_S_CMD_SET_MEDIA
:
828 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
832 error
= feth_set_media(ifp
, &iffr
);
834 case IF_FAKE_S_CMD_SET_DEQUEUE_STALL
:
835 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
839 error
= feth_enable_dequeue_stall(ifp
,
840 iffr
.iffr_dequeue_stall
);
850 feth_get_drvspec(ifnet_t ifp
, u_int32_t cmd
, u_int32_t len
,
851 user_addr_t user_addr
)
853 int error
= EOPNOTSUPP
;
855 struct if_fake_request iffr
;
859 case IF_FAKE_G_CMD_GET_PEER
:
860 if (len
< sizeof(iffr
)) {
865 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
866 if (fakeif
== NULL
) {
871 peer
= fakeif
->iff_peer
;
873 bzero(&iffr
, sizeof(iffr
));
875 strlcpy(iffr
.iffr_peer_name
,
877 sizeof(iffr
.iffr_peer_name
));
879 error
= copyout(&iffr
, user_addr
, sizeof(iffr
));
888 struct ifdrv32
*ifdrvu_32
;
889 struct ifdrv64
*ifdrvu_64
;
894 feth_ioctl(ifnet_t ifp
, u_long cmd
, void * data
)
897 struct ifdevmtu
* devmtu_p
;
901 boolean_t drv_set_command
= FALSE
;
903 struct ifmediareq
* ifmr
;
907 user_addr_t user_addr
;
909 ifr
= (struct ifreq
*)data
;
912 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
918 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
919 if (fakeif
== NULL
) {
923 status
= (fakeif
->iff_peer
!= NULL
)
924 ? (IFM_AVALID
| IFM_ACTIVE
) : IFM_AVALID
;
925 ifmr
= (struct ifmediareq
*)data
;
926 user_addr
= (cmd
== SIOCGIFMEDIA64
) ?
927 ((struct ifmediareq64
*)ifmr
)->ifmu_ulist
:
928 CAST_USER_ADDR_T(((struct ifmediareq32
*)ifmr
)->ifmu_ulist
);
929 count
= ifmr
->ifm_count
;
930 ifmr
->ifm_active
= IFM_ETHER
;
931 ifmr
->ifm_current
= IFM_ETHER
;
933 ifmr
->ifm_status
= status
;
934 if (user_addr
== USER_ADDR_NULL
) {
935 ifmr
->ifm_count
= fakeif
->iff_media_count
;
937 else if (count
> 0) {
938 if (count
> fakeif
->iff_media_count
) {
939 count
= fakeif
->iff_media_count
;
941 ifmr
->ifm_count
= count
;
942 error
= copyout(&fakeif
->iff_media_list
, user_addr
,
943 count
* sizeof(int));
949 devmtu_p
= &ifr
->ifr_devmtu
;
950 devmtu_p
->ifdm_current
= ifnet_mtu(ifp
);
951 devmtu_p
->ifdm_max
= feth_max_mtu();
952 devmtu_p
->ifdm_min
= IF_MINMTU
;
956 if (ifr
->ifr_mtu
> feth_max_mtu() || ifr
->ifr_mtu
< IF_MINMTU
) {
959 error
= ifnet_set_mtu(ifp
, ifr
->ifr_mtu
);
965 error
= proc_suser(current_proc());
969 drv_set_command
= TRUE
;
974 if (cmd
== SIOCGDRVSPEC32
|| cmd
== SIOCSDRVSPEC32
) {
975 drv_cmd
= drv
.ifdrvu_32
->ifd_cmd
;
976 drv_len
= drv
.ifdrvu_32
->ifd_len
;
977 user_addr
= CAST_USER_ADDR_T(drv
.ifdrvu_32
->ifd_data
);
980 drv_cmd
= drv
.ifdrvu_64
->ifd_cmd
;
981 drv_len
= drv
.ifdrvu_64
->ifd_len
;
982 user_addr
= drv
.ifdrvu_64
->ifd_data
;
984 if (drv_set_command
) {
985 error
= feth_set_drvspec(ifp
, drv_cmd
, drv_len
,
988 error
= feth_get_drvspec(ifp
, drv_cmd
, drv_len
,
994 error
= ifnet_set_lladdr(ifp
, ifr
->ifr_addr
.sa_data
,
995 ifr
->ifr_addr
.sa_len
);
999 if ((ifp
->if_flags
& IFF_UP
) != 0) {
1000 /* marked up, set running if not already set */
1001 if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
1003 error
= ifnet_set_flags(ifp
, IFF_RUNNING
,
1006 } else if ((ifp
->if_flags
& IFF_RUNNING
) != 0) {
1007 /* marked down, clear running */
1008 error
= ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
1024 feth_if_free(ifnet_t ifp
)
1032 fakeif
= ifnet_get_if_fake(ifp
);
1033 if (fakeif
== NULL
) {
1037 ifp
->if_softc
= NULL
;
1039 feth_release(fakeif
);
1044 __private_extern__
void
1050 error
= if_clone_attach(&feth_cloner
);