Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F33105969
if_vether.c
henning.matyschok_outlook.com
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
henning.matyschok_outlook.com
Dec 4 2021, 12:39 PM
2021-12-04 12:39:22 (UTC+0)
Size
11 KB
Referenced Files
None
Subscribers
None
if_vether.c
View Options
/*
* Copyright (c) 2009 Theo de Raadt
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (c) 2018, 2021 Henning Andersen Matyschok, DARPA/AFRL
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include
<sys/cdefs.h>
__FBSDID
(
"$FreeBSD$"
);
#include
<sys/param.h>
#include
<sys/kernel.h>
#include
<sys/module.h>
#include
<sys/socket.h>
#include
<sys/sockio.h>
#include
<net/if.h>
#include
<net/if_var.h>
#include
<net/if_clone.h>
#include
<net/if_dl.h>
#include
<net/if_media.h>
#include
<net/netisr.h>
#include
<net/if_types.h>
#include
<net/bpf.h>
#include
<net/ethernet.h>
#include
<net/if_bridgevar.h>
#include
<net/vnet.h>
/*
* Virtual Ethernet interface, ported from OpenBSD. This interface
* operates in conjunction with if_bridge(4).
*/
struct
vether_softc
{
struct
ifmedia
sc_ifm
;
/* fake media information */
struct
ifnet
*
sc_ifp
;
/* network interface. */
};
#define VETHER_IF_FLAGS (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST)
#define VETHER_IFCAP_FLAGS (IFCAP_VLAN_MTU|IFCAP_JUMBO_MTU)
#define VETHER_IFM_FLAGS (IFM_ETHER|IFM_AUTO)
/*
* XXX
* The set of protocol-numbers index-set
* against <net/netisr.h> maps-to set
* over (enum), e. g.:
*
* typedef enum netisr_proto {
* netisr_ip = NETISR_IP,
* netisr_igmp = NETISR_IGMP,
* netisr_route = NETISR_ROUTE,
* netisr_arp = NETISR_ARP,
* netisr_ether = NETISR_ETHER,
* netisr_ipv6 = NETISR_IPV6,
* netisr_epair = NETISR_EPAIR,
* netisr_ip_direct = NETISR_IP_DIRECT,
* netisr_ipv6_direct = NETISR_IPV6_DIRECT,
* netisr_vether = NETISR_VETHER_FWD,
* } netisr_proto_t;
*/
#define NETISR_VETHER_FWD 11
typedef
enum
vether_netisr_component
{
vether_netisr_fwd
=
NETISR_VETHER_FWD
,
}
vether_netisr_component_t
;
static
void
vether_ifaddr_init
(
struct
ifnet
*
,
struct
ether_addr
*
);
static
void
vether_nh_fwd_cb
(
struct
mbuf
*
);
static
void
vether_texeof
(
struct
ifnet
*
);
static
void
vether_init
(
void
*
);
static
void
vether_stop
(
struct
ifnet
*
);
static
void
vether_start
(
struct
ifnet
*
);
static
int
vether_media_change
(
struct
ifnet
*
);
static
void
vether_media_status
(
struct
ifnet
*
,
struct
ifmediareq
*
);
static
int
vether_ioctl
(
struct
ifnet
*
,
u_long
,
caddr_t
);
static
int
vether_clone_create
(
struct
if_clone
*
,
int
,
caddr_t
);
static
void
vether_clone_destroy
(
struct
ifnet
*
);
static
struct
netisr_handler
vether_nh_fwd
=
{
.
nh_name
=
"Softintr. for if_vether(4)"
,
.
nh_handler
=
vether_nh_fwd_cb
,
.
nh_proto
=
vether_netisr_fwd
,
.
nh_policy
=
NETISR_POLICY_FLOW
,
};
static
const
char
vether_name
[]
=
"vether"
;
VNET_DEFINE
(
struct
if_clone
*
,
vether_cloner
);
#define V_vether_cloner VNET(vether_cloner)
static
int
vether_clone_create
(
struct
if_clone
*
ifc
,
int
unit
,
caddr_t
data
)
{
struct
vether_softc
*
sc
;
struct
ifnet
*
ifp
;
struct
ether_addr
lla
;
int
error
;
/*
* For safety reason, there is a condition test applied -
* independently, if M_WAITOK was enabled or not.
*/
if
((
sc
=
malloc
(
sizeof
(
struct
vether_softc
),
M_DEVBUF
,
M_WAITOK
|
M_ZERO
))
!=
NULL
)
{
if
((
ifp
=
if_alloc
(
IFT_ETHER
))
!=
NULL
)
{
sc
->
sc_ifp
=
ifp
;
ifp
->
if_softc
=
sc
;
if_initname
(
ifp
,
vether_name
,
unit
);
ifp
->
if_init
=
vether_init
;
ifp
->
if_ioctl
=
vether_ioctl
;
ifp
->
if_start
=
vether_start
;
ifp
->
if_flags
=
VETHER_IF_FLAGS
;
ifp
->
if_capabilities
=
VETHER_IFCAP_FLAGS
;
ifp
->
if_capenable
=
VETHER_IFCAP_FLAGS
;
ifp
->
if_baudrate
=
0
;
ifmedia_init
(
&
sc
->
sc_ifm
,
0
,
vether_media_change
,
vether_media_status
);
ifmedia_add
(
&
sc
->
sc_ifm
,
VETHER_IFM_FLAGS
,
0
,
NULL
);
ifmedia_set
(
&
sc
->
sc_ifm
,
VETHER_IFM_FLAGS
);
vether_ifaddr_init
(
ifp
,
&
lla
);
ether_ifattach
(
ifp
,
lla
.
octet
);
error
=
0
;
}
else
{
error
=
ENOSPC
;
free
(
sc
,
M_DEVBUF
);
}
}
else
error
=
ENOBUFS
;
return
(
error
);
}
static
void
vether_clone_destroy
(
struct
ifnet
*
ifp
)
{
struct
vether_softc
*
sc
;
if
(
ifp
!=
NULL
)
{
ifp
->
if_flags
&=
~
IFF_UP
;
vether_stop
(
ifp
);
if
((
sc
=
ifp
->
if_softc
)
!=
NULL
)
{
free
(
sc
,
M_DEVBUF
);
ifp
->
if_softc
=
NULL
;
}
ether_ifdetach
(
ifp
);
if_free
(
ifp
);
}
}
static
void
vnet_vether_init
(
const
void
*
unused
__unused
)
{
V_vether_cloner
=
if_clone_simple
(
vether_name
,
vether_clone_create
,
vether_clone_destroy
,
0
);
}
VNET_SYSINIT
(
vnet_vether_init
,
SI_SUB_PROTO_IFATTACHDOMAIN
,
SI_ORDER_ANY
,
vnet_vether_init
,
NULL
);
static
void
vnet_vether_uninit
(
const
void
*
unused
__unused
)
{
if_clone_detach
(
V_vether_cloner
);
}
VNET_SYSUNINIT
(
vnet_vether_uninit
,
SI_SUB_PSEUDO
,
SI_ORDER_ANY
,
vnet_vether_uninit
,
NULL
);
static
int
vether_mod_event
(
module_t
mod
,
int
event
,
void
*
data
)
{
switch
(
event
)
{
case
MOD_LOAD
:
netisr_register
(
&
vether_nh_fwd
);
return
(
0
);
case
MOD_UNLOAD
:
netisr_unregister
(
&
vether_nh_fwd
);
return
(
0
);
default
:
break
;
}
return
(
EOPNOTSUPP
);
}
static
moduledata_t
vether_mod
=
{
"if_vether"
,
vether_mod_event
,
0
};
DECLARE_MODULE
(
if_vether
,
vether_mod
,
SI_SUB_PSEUDO
,
SI_ORDER_ANY
);
/*
* I/O.
*/
static
void
vether_txeof
(
struct
ifnet
*
ifp
)
{
struct
mbuf
*
m
;
if
(
ifp
!=
NULL
)
{
IFQ_DEQUEUE
(
&
ifp
->
if_snd
,
m
);
if
(
m
!=
NULL
)
{
BPF_MTAP
(
ifp
,
m
);
if
((
m
->
m_pkthdr
&
M_PKTHDR
)
!=
0
)
{
/* do some statistics */
if_inc_counter
(
ifp
,
IFCOUNTER_OBYTES
,
m
->
m_pkthdr
.
len
);
if_inc_counter
(
ifp
,
IFCOUNTER_OPACKETS
,
1
);
/* discard, if not member of if_bridge(4) */
if
(
ifp
->
if_bridge
==
NULL
)
m
->
m_pkthdr
.
rcvif
=
ifp
;
/*
* Three cases are considered here:
*
* (a) Frame was tx'd by layer above.
*
* (b) Frame was rx'd by link-layer.
*
* (c) Data sink.
*/
if
(
m
->
m_pkthdr
.
rcvif
==
NULL
)
{
m
->
m_pkthdr
.
rcvif
=
ifp
;
netisr_dispatch
(
vether_netisr_fwd
,
m
);
}
else
if
(
m
->
m_pkthdr
.
rcvif
!=
ifp
)
{
m
->
m_pkthdr
.
rcvif
=
ifp
;
/* demultiplex any other frame */
(
*
ifp
->
if_input
)(
ifp
,
m
);
}
else
{
m_freem
(
m
);
m
=
NULL
;
}
vether_txeof
(
ifp
);
}
else
{
if_inc_counter
(
ifp
,
IFCOUNTER_OERRORS
,
1
);
m_freem
(
m
);
m
=
NULL
;
}
}
}
}
static
void
vether_start
(
struct
ifnet
*
ifp
)
{
if
((
ifp
->
if_flags
&
IFF_UP
)
!=
0
)
{
ifp
->
if_drv_flags
|=
IFF_DRV_OACTIVE
;
vether_txeof
(
ifp
);
ifp
->
if_drv_flags
&=
~
IFF_DRV_OACTIVE
;
}
}
/*
* Broadcast frame by if_bridge(4).
*/
static
void
vether_nh_fwd_cb
(
struct
mbuf
*
m
)
{
struct
ifnet
*
ifp
;
int
error
;
if
(
m
!=
NULL
)
{
if
((
m
->
m_flags
&
M_PKTHDR
)
!=
0
)
{
if
((
ifp
=
m
->
m_pkthdr
.
rcvif
)
!=
NULL
)
BRIDGE_OUTPUT
(
ifp
,
m
,
error
);
else
error
=
EADDRNOTAVAIL
;
}
else
error
=
ECONNABORTED
;
}
else
error
=
ENOBUFS
;
if
(
error
!=
0
)
{
if
(
m
!=
NULL
)
{
m_freem
(
m
);
m
=
NULL
;
}
}
}
/*
* Initialize lla.
*/
static
void
vether_ifaddr_init
(
struct
ifnet
*
ifp
,
struct
ether_addr
*
lla
)
{
caddr_t
pfx
,
sfx
;
if
(
ifp
!=
NULL
)
{
if
(
lla
!=
NULL
)
{
pfx
=
lla
->
octet
;
pfx
[
0
]
=
0x02
;
sfx
=
(
pfx
+
1
);
arc4rand
(
sfx
,
5
,
0
);
}
}
}
static
int
vether_media_change
(
struct
ifnet
*
ifp
)
{
int
error
;
if
(
ifp
!=
NULL
)
error
=
0
;
else
error
=
EADDRNOTAVAIL
;
return
(
error
);
}
static
void
vether_media_status
(
struct
ifnet
*
ifp
,
struct
ifmediareq
*
ifm
)
{
if
(
ifp
!=
NULL
)
{
if
(
ifm
!=
NULL
)
{
ifm
->
ifm_active
=
(
IFM_ETHER
|
IFM_AUTO
);
ifm
->
ifm_status
=
(
IFM_AVALID
|
IFM_ACTIVE
);
}
}
}
static
void
vether_init
(
void
*
xsc
)
{
struct
vether_softc
*
sc
;
struct
ifnet
*
ifp
;
if
((
sc
=
(
struct
vether_softc
*
)
xsc
)
!=
NULL
)
{
if
((
ifp
=
sc
->
sc_ifp
)
!=
NULL
)
{
ifp
->
if_drv_flags
|=
IFF_DRV_RUNNING
;
ifp
->
if_drv_flags
&=
~
IFF_DRV_OACTIVE
;
}
}
}
static
void
vether_stop
(
struct
ifnet
*
ifp
)
{
if
(
ifp
!=
NULL
)
ifp
->
if_drv_flags
&=
~
(
IFF_DRV_RUNNING
|
IFF_DRV_OACTIVE
);
}
static
int
vether_ioctl
(
struct
ifnet
*
ifp
,
u_long
req
,
caddr_t
argp
)
{
struct
vether_softc
*
sc
;
struct
ifreq
*
ifr
;
int
error
;
if
(
ifp
!=
NULL
)
{
if
((
sc
=
ifp
->
if_softc
)
!=
NULL
)
{
ifr
=
(
struct
ifreq
*
)
argp
;
switch
(
req
)
{
case
SIOCSIFMTU
:
if
(
ifr
->
ifr_mtu
<
ETHER_MAX_LEN_JUMBO
)
{
ifp
->
if_mtu
=
ifr
->
ifr_mtu
;
error
=
0
;
}
else
error
=
EINVAL
;
break
;
case
SIOCSIFMEDIA
:
/* Media types can't be changed. */
case
SIOCGIFMEDIA
:
error
=
ifmedia_ioctl
(
ifp
,
ifr
,
&
sc
->
sc_ifm
,
req
);
break
;
case
SIOCSIFFLAGS
:
case
SIOCADDMULTI
:
case
SIOCDELMULTI
:
error
=
0
;
break
;
case
SIOCSIFPHYS
:
error
=
EOPNOTSUPP
;
break
;
default
:
error
=
ether_ioctl
(
ifp
,
req
,
argp
);
break
;
}
}
else
error
=
ENXIO
;
}
else
error
=
ENOTTY
;
return
(
error
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4298626
Default Alt Text
if_vether.c (11 KB)
Attached To
Mode
D20468: if_vether, ported from OpenBSD
Attached
Detach File
Event Timeline
Log In to Comment