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 #define M_FAKE M_DEVBUF
162 static int feth_clone_create(struct if_clone
*, u_int32_t
, void *);
163 static int feth_clone_destroy(ifnet_t
);
164 static int feth_output(ifnet_t ifp
, struct mbuf
*m
);
165 static void feth_start(ifnet_t ifp
);
166 static int feth_ioctl(ifnet_t ifp
, u_long cmd
, void * addr
);
167 static int feth_config(ifnet_t ifp
, ifnet_t peer
);
168 static void feth_if_free(ifnet_t ifp
);
169 static void feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
);
170 static void feth_free(if_fake_ref fakeif
);
172 static struct if_clone
173 feth_cloner
= IF_CLONE_INITIALIZER(FAKE_ETHER_NAME
,
178 static void interface_link_event(ifnet_t ifp
, u_int32_t event_code
);
180 /* some media words to pretend to be ethernet */
181 static int default_media_words
[] = {
182 IFM_MAKEWORD(IFM_ETHER
, 0, 0, 0),
183 IFM_MAKEWORD(IFM_ETHER
, IFM_10G_T
, IFM_FDX
, 0),
184 IFM_MAKEWORD(IFM_ETHER
, IFM_2500_T
, IFM_FDX
, 0),
185 IFM_MAKEWORD(IFM_ETHER
, IFM_5000_T
, IFM_FDX
, 0),
187 #define default_media_words_count (sizeof(default_media_words) \
188 / sizeof (default_media_words[0]))
193 static inline lck_grp_t
*
194 my_lck_grp_alloc_init(const char * grp_name
)
197 lck_grp_attr_t
* grp_attrs
;
199 grp_attrs
= lck_grp_attr_alloc_init();
200 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
201 lck_grp_attr_free(grp_attrs
);
205 static inline lck_mtx_t
*
206 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
208 lck_attr_t
* lck_attrs
;
211 lck_attrs
= lck_attr_alloc_init();
212 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
213 lck_attr_free(lck_attrs
);
217 static lck_mtx_t
* feth_lck_mtx
;
222 lck_grp_t
* feth_lck_grp
;
224 feth_lck_grp
= my_lck_grp_alloc_init("fake");
225 feth_lck_mtx
= my_lck_mtx_alloc_init(feth_lck_grp
);
230 feth_assert_lock_not_held(void)
232 LCK_MTX_ASSERT(feth_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
240 lck_mtx_lock(feth_lck_mtx
);
247 lck_mtx_unlock(feth_lck_mtx
);
255 return (M16KCLBYTES
- ETHER_HDR_LEN
);
257 return (MBIGCLBYTES
- ETHER_HDR_LEN
);
261 feth_free(if_fake_ref fakeif
)
263 assert(fakeif
->iff_retain_count
== 0);
264 if (feth_in_bsd_mode(fakeif
)) {
265 if (fakeif
->iff_pending_tx_packet
) {
266 m_freem(fakeif
->iff_pending_tx_packet
);
270 FETH_DPRINTF("%s\n", fakeif
->iff_name
);
271 FREE(fakeif
, M_FAKE
);
275 feth_release(if_fake_ref fakeif
)
277 u_int32_t old_retain_count
;
279 old_retain_count
= OSDecrementAtomic(&fakeif
->iff_retain_count
);
280 switch (old_retain_count
) {
282 assert(old_retain_count
!= 0);
295 ** feth interface routines
298 feth_ifnet_set_attrs(if_fake_ref fakeif
, ifnet_t ifp
)
300 (void)ifnet_set_capabilities_enabled(ifp
, 0, -1);
301 ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
);
302 ifnet_set_baudrate(ifp
, 0);
303 ifnet_set_mtu(ifp
, ETHERMTU
);
305 IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
,
307 ifnet_set_hdrlen(ifp
, sizeof(struct ether_header
));
308 if ((fakeif
->iff_flags
& IFF_FLAGS_HWCSUM
) != 0) {
309 ifnet_set_offload(ifp
,
310 IFNET_CSUM_IP
| IFNET_CSUM_TCP
| IFNET_CSUM_UDP
|
311 IFNET_CSUM_TCPIPV6
| IFNET_CSUM_UDPIPV6
);
313 ifnet_set_offload(ifp
, 0);
318 interface_link_event(ifnet_t ifp
, u_int32_t event_code
)
321 struct kern_event_msg header
;
323 char if_name
[IFNAMSIZ
];
326 bzero(&event
, sizeof(event
));
327 event
.header
.total_size
= sizeof(event
);
328 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
329 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
330 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
331 event
.header
.event_code
= event_code
;
332 event
.header
.event_data
[0] = ifnet_family(ifp
);
333 event
.unit
= (u_int32_t
) ifnet_unit(ifp
);
334 strlcpy(event
.if_name
, ifnet_name(ifp
), IFNAMSIZ
);
335 ifnet_event(ifp
, &event
.header
);
340 ifnet_get_if_fake(ifnet_t ifp
)
342 return ((if_fake_ref
)ifnet_softc(ifp
));
346 feth_clone_create(struct if_clone
*ifc
, u_int32_t unit
, __unused
void *params
)
350 struct ifnet_init_eparams feth_init
;
352 uint8_t mac_address
[ETHER_ADDR_LEN
];
354 fakeif
= _MALLOC(sizeof(struct if_fake
), M_FAKE
, M_WAITOK
| M_ZERO
);
355 if (fakeif
== NULL
) {
358 fakeif
->iff_retain_count
= 1;
359 #define FAKE_ETHER_NAME_LEN (sizeof(FAKE_ETHER_NAME) - 1)
360 _CASSERT(FAKE_ETHER_NAME_LEN
== 4);
361 bcopy(FAKE_ETHER_NAME
, mac_address
, FAKE_ETHER_NAME_LEN
);
362 mac_address
[ETHER_ADDR_LEN
- 2] = (unit
& 0xff00) >> 8;
363 mac_address
[ETHER_ADDR_LEN
- 1] = unit
& 0xff;
364 if (if_fake_bsd_mode
!= 0) {
365 fakeif
->iff_flags
|= IFF_FLAGS_BSD_MODE
;
367 if (if_fake_hwcsum
!= 0) {
368 fakeif
->iff_flags
|= IFF_FLAGS_HWCSUM
;
371 /* use the interface name as the unique id for ifp recycle */
373 snprintf(fakeif
->iff_name
, sizeof(fakeif
->iff_name
), "%s%d",
374 ifc
->ifc_name
, unit
) >= sizeof(fakeif
->iff_name
)) {
375 feth_release(fakeif
);
378 bzero(&feth_init
, sizeof(feth_init
));
379 feth_init
.ver
= IFNET_INIT_CURRENT_VERSION
;
380 feth_init
.len
= sizeof (feth_init
);
381 if (feth_in_bsd_mode(fakeif
)) {
382 if (if_fake_txstart
!= 0) {
383 feth_init
.start
= feth_start
;
385 feth_init
.flags
|= IFNET_INIT_LEGACY
;
386 feth_init
.output
= feth_output
;
389 if (if_fake_nxattach
== 0) {
390 feth_init
.flags
|= IFNET_INIT_NX_NOAUTO
;
392 feth_init
.uniqueid
= fakeif
->iff_name
;
393 feth_init
.uniqueid_len
= strlen(fakeif
->iff_name
);
394 feth_init
.name
= ifc
->ifc_name
;
395 feth_init
.unit
= unit
;
396 feth_init
.family
= IFNET_FAMILY_ETHERNET
;
397 feth_init
.type
= IFT_ETHER
;
398 feth_init
.demux
= ether_demux
;
399 feth_init
.add_proto
= ether_add_proto
;
400 feth_init
.del_proto
= ether_del_proto
;
401 feth_init
.check_multi
= ether_check_multi
;
402 feth_init
.framer_extended
= ether_frameout_extended
;
403 feth_init
.softc
= fakeif
;
404 feth_init
.ioctl
= feth_ioctl
;
405 feth_init
.set_bpf_tap
= NULL
;
406 feth_init
.detach
= feth_if_free
;
407 feth_init
.broadcast_addr
= etherbroadcastaddr
;
408 feth_init
.broadcast_len
= ETHER_ADDR_LEN
;
409 if (feth_in_bsd_mode(fakeif
)) {
410 error
= ifnet_allocate_extended(&feth_init
, &ifp
);
412 feth_release(fakeif
);
415 feth_ifnet_set_attrs(fakeif
, ifp
);
417 fakeif
->iff_media_count
= default_media_words_count
;
418 bcopy(default_media_words
, fakeif
->iff_media_list
,
419 sizeof(default_media_words
));
420 if (feth_in_bsd_mode(fakeif
)) {
421 error
= ifnet_attach(ifp
, NULL
);
424 feth_release(fakeif
);
427 fakeif
->iff_ifp
= ifp
;
430 ifnet_set_lladdr(ifp
, mac_address
, sizeof(mac_address
));
432 /* attach as ethernet */
433 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
438 feth_clone_destroy(ifnet_t ifp
)
443 fakeif
= ifnet_get_if_fake(ifp
);
444 if (fakeif
== NULL
|| feth_is_detaching(fakeif
)) {
448 feth_set_detaching(fakeif
);
451 feth_config(ifp
, NULL
);
457 feth_enqueue_input(ifnet_t ifp
, struct mbuf
* m
)
459 struct ifnet_stat_increment_param stats
= {};
461 stats
.packets_in
= 1;
462 stats
.bytes_in
= (uint32_t)mbuf_pkthdr_len(m
) + ETHER_HDR_LEN
;
463 ifnet_input(ifp
, m
, &stats
);
467 copy_mbuf(struct mbuf
*m
)
469 struct mbuf
* copy_m
;
473 if ((m
->m_flags
& M_PKTHDR
) == 0) {
476 pkt_len
= m
->m_pkthdr
.len
;
477 MGETHDR(copy_m
, M_DONTWAIT
, MT_DATA
);
478 if (copy_m
== NULL
) {
481 if (pkt_len
> MHLEN
) {
482 if (pkt_len
<= MCLBYTES
) {
483 MCLGET(copy_m
, M_DONTWAIT
);
484 } else if (pkt_len
<= MBIGCLBYTES
) {
485 copy_m
= m_mbigget(copy_m
, M_DONTWAIT
);
486 } else if (pkt_len
<= M16KCLBYTES
&& njcl
> 0) {
487 copy_m
= m_m16kget(copy_m
, M_DONTWAIT
);
489 printf("if_fake: copy_mbuf(): packet too large %d\n",
493 if (copy_m
== NULL
|| (copy_m
->m_flags
& M_EXT
) == 0) {
497 mbuf_setlen(copy_m
, pkt_len
);
498 copy_m
->m_pkthdr
.len
= pkt_len
;
500 while (m
!= NULL
&& offset
< pkt_len
) {
504 if (frag_len
> (pkt_len
- offset
)) {
505 printf("if_fake_: Large mbuf fragment %d > %d\n",
506 frag_len
, (pkt_len
- offset
));
509 m_copydata(m
, 0, frag_len
, mtod(copy_m
, void *) + offset
);
516 if (copy_m
!= NULL
) {
523 feth_output_common(ifnet_t ifp
, struct mbuf
* m
, ifnet_t peer
,
528 frame_header
= mbuf_data(m
);
529 if ((flags
& IFF_FLAGS_HWCSUM
) != 0) {
530 m
->m_pkthdr
.csum_data
= 0xffff;
531 m
->m_pkthdr
.csum_flags
=
532 CSUM_DATA_VALID
| CSUM_PSEUDO_HDR
|
533 CSUM_IP_CHECKED
| CSUM_IP_VALID
;
536 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
537 bpf_tap_out(ifp
, DLT_EN10MB
, m
, NULL
, 0);
539 (void)mbuf_pkthdr_setrcvif(m
, peer
);
540 mbuf_pkthdr_setheader(m
, frame_header
);
541 mbuf_pkthdr_adjustlen(m
, - ETHER_HDR_LEN
);
542 (void)mbuf_setdata(m
, (char *)mbuf_data(m
) + ETHER_HDR_LEN
,
543 mbuf_len(m
) - ETHER_HDR_LEN
);
544 bpf_tap_in(peer
, DLT_EN10MB
, m
, frame_header
,
545 sizeof(struct ether_header
));
546 feth_enqueue_input(peer
, m
);
550 feth_start(ifnet_t ifp
)
552 struct mbuf
* copy_m
= NULL
;
554 iff_flags_t flags
= 0;
557 struct mbuf
* save_m
;
560 fakeif
= ifnet_get_if_fake(ifp
);
561 if (fakeif
->iff_start_busy
) {
563 printf("if_fake: start is busy\n");
566 if (fakeif
!= NULL
) {
567 peer
= fakeif
->iff_peer
;
568 flags
= fakeif
->iff_flags
;
571 /* check for pending TX */
572 m
= fakeif
->iff_pending_tx_packet
;
575 copy_m
= copy_mbuf(m
);
576 if (copy_m
== NULL
) {
581 fakeif
->iff_pending_tx_packet
= NULL
;
585 fakeif
->iff_start_busy
= TRUE
;
589 if (copy_m
!= NULL
) {
590 assert(peer
!= NULL
);
591 feth_output_common(ifp
, copy_m
, peer
, flags
);
594 if (ifnet_dequeue(ifp
, &m
) != 0) {
600 copy_m
= copy_mbuf(m
);
601 if (copy_m
== NULL
) {
610 fakeif
= ifnet_get_if_fake(ifp
);
611 if (fakeif
!= NULL
) {
612 fakeif
->iff_start_busy
= FALSE
;
613 if (save_m
!= NULL
&& fakeif
->iff_peer
!= NULL
) {
614 /* save it for next time */
615 fakeif
->iff_pending_tx_packet
= save_m
;
620 if (save_m
!= NULL
) {
621 /* didn't save packet, so free it */
627 feth_output(ifnet_t ifp
, struct mbuf
* m
)
629 struct mbuf
* copy_m
;
637 copy_m
= copy_mbuf(m
);
640 if (copy_m
== NULL
) {
641 /* count this as an output error */
642 ifnet_stat_increment_out(ifp
, 0, 0, 1);
646 fakeif
= ifnet_get_if_fake(ifp
);
647 if (fakeif
!= NULL
) {
648 peer
= fakeif
->iff_peer
;
649 flags
= fakeif
->iff_flags
;
654 ifnet_stat_increment_out(ifp
, 0, 0, 1);
657 feth_output_common(ifp
, copy_m
, peer
, flags
);
662 feth_config(ifnet_t ifp
, ifnet_t peer
)
664 int connected
= FALSE
;
665 int disconnected
= FALSE
;
667 if_fake_ref fakeif
= NULL
;
670 fakeif
= ifnet_get_if_fake(ifp
);
671 if (fakeif
== NULL
) {
676 /* connect to peer */
677 if_fake_ref peer_fakeif
;
679 peer_fakeif
= ifnet_get_if_fake(peer
);
680 if (peer_fakeif
== NULL
) {
684 if (feth_is_detaching(fakeif
) ||
685 feth_is_detaching(peer_fakeif
) ||
686 peer_fakeif
->iff_peer
!= NULL
||
687 fakeif
->iff_peer
!= NULL
) {
691 fakeif
->iff_peer
= peer
;
692 peer_fakeif
->iff_peer
= ifp
;
695 else if (fakeif
->iff_peer
!= NULL
) {
696 /* disconnect from peer */
697 if_fake_ref peer_fakeif
;
699 peer
= fakeif
->iff_peer
;
700 peer_fakeif
= ifnet_get_if_fake(peer
);
701 if (peer_fakeif
== NULL
) {
702 /* should not happen */
706 fakeif
->iff_peer
= NULL
;
707 peer_fakeif
->iff_peer
= NULL
;
714 /* generate link status event if we connect or disconnect */
716 ifnet_set_flags(ifp
, IFF_RUNNING
, IFF_RUNNING
);
717 ifnet_set_flags(peer
, IFF_RUNNING
, IFF_RUNNING
);
718 interface_link_event(ifp
, KEV_DL_LINK_ON
);
719 interface_link_event(peer
, KEV_DL_LINK_ON
);
721 else if (disconnected
) {
722 ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
723 ifnet_set_flags(peer
, 0, IFF_RUNNING
);
724 interface_link_event(ifp
, KEV_DL_LINK_OFF
);
725 interface_link_event(peer
, KEV_DL_LINK_OFF
);
731 feth_set_media(ifnet_t ifp
, struct if_fake_request
* iffr
)
736 if (iffr
->iffr_media
.iffm_count
> IF_FAKE_MEDIA_LIST_MAX
) {
737 /* list is too long */
741 fakeif
= ifnet_get_if_fake(ifp
);
742 if (fakeif
== NULL
) {
746 fakeif
->iff_media_count
= iffr
->iffr_media
.iffm_count
;
747 bcopy(iffr
->iffr_media
.iffm_list
, fakeif
->iff_media_list
,
748 iffr
->iffr_media
.iffm_count
* sizeof(fakeif
->iff_media_list
[0]));
750 /* XXX: "auto-negotiate" active with peer? */
751 /* generate link status event? */
752 fakeif
->iff_media_current
= iffr
->iffr_media
.iffm_current
;
761 if_fake_request_copyin(user_addr_t user_addr
,
762 struct if_fake_request
*iffr
, u_int32_t len
)
766 if (user_addr
== USER_ADDR_NULL
|| len
< sizeof(*iffr
)) {
770 error
= copyin(user_addr
, iffr
, sizeof(*iffr
));
774 if (iffr
->iffr_reserved
[0] != 0 || iffr
->iffr_reserved
[1] != 0 ||
775 iffr
->iffr_reserved
[2] != 0 || iffr
->iffr_reserved
[3] != 0) {
784 feth_set_drvspec(ifnet_t ifp
, uint32_t cmd
, u_int32_t len
,
785 user_addr_t user_addr
)
788 struct if_fake_request iffr
;
792 case IF_FAKE_S_CMD_SET_PEER
:
793 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
797 if (iffr
.iffr_peer_name
[0] == '\0') {
798 error
= feth_config(ifp
, NULL
);
802 /* ensure nul termination */
803 iffr
.iffr_peer_name
[IFNAMSIZ
- 1] = '\0';
804 peer
= ifunit(iffr
.iffr_peer_name
);
809 if (ifnet_type(peer
) != IFT_ETHER
) {
813 if (strcmp(ifnet_name(peer
), FAKE_ETHER_NAME
) != 0) {
817 error
= feth_config(ifp
, peer
);
819 case IF_FAKE_S_CMD_SET_MEDIA
:
820 error
= if_fake_request_copyin(user_addr
, &iffr
, len
);
824 error
= feth_set_media(ifp
, &iffr
);
834 feth_get_drvspec(ifnet_t ifp
, u_int32_t cmd
, u_int32_t len
,
835 user_addr_t user_addr
)
837 int error
= EOPNOTSUPP
;
839 struct if_fake_request iffr
;
843 case IF_FAKE_G_CMD_GET_PEER
:
844 if (len
< sizeof(iffr
)) {
849 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
850 if (fakeif
== NULL
) {
855 peer
= fakeif
->iff_peer
;
857 bzero(&iffr
, sizeof(iffr
));
859 strlcpy(iffr
.iffr_peer_name
,
861 sizeof(iffr
.iffr_peer_name
));
863 error
= copyout(&iffr
, user_addr
, sizeof(iffr
));
872 struct ifdrv32
*ifdrvu_32
;
873 struct ifdrv64
*ifdrvu_64
;
878 feth_ioctl(ifnet_t ifp
, u_long cmd
, void * data
)
881 struct ifdevmtu
* devmtu_p
;
885 boolean_t drv_set_command
= FALSE
;
887 struct ifmediareq
* ifmr
;
891 user_addr_t user_addr
;
893 ifr
= (struct ifreq
*)data
;
896 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
902 fakeif
= (if_fake_ref
)ifnet_softc(ifp
);
903 if (fakeif
== NULL
) {
907 status
= (fakeif
->iff_peer
!= NULL
)
908 ? (IFM_AVALID
| IFM_ACTIVE
) : IFM_AVALID
;
909 ifmr
= (struct ifmediareq
*)data
;
910 user_addr
= (cmd
== SIOCGIFMEDIA64
) ?
911 ((struct ifmediareq64
*)ifmr
)->ifmu_ulist
:
912 CAST_USER_ADDR_T(((struct ifmediareq32
*)ifmr
)->ifmu_ulist
);
913 count
= ifmr
->ifm_count
;
914 ifmr
->ifm_active
= IFM_ETHER
;
915 ifmr
->ifm_current
= IFM_ETHER
;
917 ifmr
->ifm_status
= status
;
918 if (user_addr
== USER_ADDR_NULL
) {
919 ifmr
->ifm_count
= fakeif
->iff_media_count
;
921 else if (count
> 0) {
922 if (count
> fakeif
->iff_media_count
) {
923 count
= fakeif
->iff_media_count
;
925 ifmr
->ifm_count
= count
;
926 error
= copyout(&fakeif
->iff_media_list
, user_addr
,
927 count
* sizeof(int));
933 devmtu_p
= &ifr
->ifr_devmtu
;
934 devmtu_p
->ifdm_current
= ifnet_mtu(ifp
);
935 devmtu_p
->ifdm_max
= feth_max_mtu();
936 devmtu_p
->ifdm_min
= IF_MINMTU
;
940 if (ifr
->ifr_mtu
> feth_max_mtu() || ifr
->ifr_mtu
< IF_MINMTU
) {
943 error
= ifnet_set_mtu(ifp
, ifr
->ifr_mtu
);
949 error
= proc_suser(current_proc());
953 drv_set_command
= TRUE
;
958 if (cmd
== SIOCGDRVSPEC32
|| cmd
== SIOCSDRVSPEC32
) {
959 drv_cmd
= drv
.ifdrvu_32
->ifd_cmd
;
960 drv_len
= drv
.ifdrvu_32
->ifd_len
;
961 user_addr
= CAST_USER_ADDR_T(drv
.ifdrvu_32
->ifd_data
);
964 drv_cmd
= drv
.ifdrvu_64
->ifd_cmd
;
965 drv_len
= drv
.ifdrvu_64
->ifd_len
;
966 user_addr
= drv
.ifdrvu_64
->ifd_data
;
968 if (drv_set_command
) {
969 error
= feth_set_drvspec(ifp
, drv_cmd
, drv_len
,
972 error
= feth_get_drvspec(ifp
, drv_cmd
, drv_len
,
978 error
= ifnet_set_lladdr(ifp
, ifr
->ifr_addr
.sa_data
,
979 ifr
->ifr_addr
.sa_len
);
998 feth_if_free(ifnet_t ifp
)
1006 fakeif
= ifnet_get_if_fake(ifp
);
1007 if (fakeif
== NULL
) {
1011 ifp
->if_softc
= NULL
;
1013 feth_release(fakeif
);
1018 __private_extern__
void
1024 error
= if_clone_attach(&feth_cloner
);