Skip to content

Commit 9c60c1c

Browse files
committed
add dummy_rs driver
Signed-off-by: Finn Behrens <me@kloenk.de>
1 parent 5fde710 commit 9c60c1c

File tree

3 files changed

+247
-0
lines changed

3 files changed

+247
-0
lines changed

drivers/net/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ config DUMMY
7272
To compile this driver as a module, choose M here: the module
7373
will be called dummy.
7474

75+
config DUMMY_RS
76+
tristate "Dummy net driver support (rust)"
77+
help
78+
This is essentially a bit-bucket device (i.e. traffic you send to
79+
this device is consigned into oblivion) with a configurable IP
80+
address. It is most commonly used in order to make your currently
81+
inactive SLIP address seem like a real address for local programs.
82+
If you use SLIP or PPP, you might want to say Y here. It won't
83+
enlarge your kernel. What a deal. Read about it in the Network
84+
Administrator's Guide, available from
85+
<http://www.tldp.org/docs.html#guide>.
86+
87+
To compile this driver as a module, choose M here: the module
88+
will be called dummy_rs.
89+
7590
config WIREGUARD
7691
tristate "WireGuard secure network tunnel"
7792
depends on NET && INET

drivers/net/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ obj-$(CONFIG_BONDING) += bonding/
1010
obj-$(CONFIG_IPVLAN) += ipvlan/
1111
obj-$(CONFIG_IPVTAP) += ipvlan/
1212
obj-$(CONFIG_DUMMY) += dummy.o
13+
obj-$(CONFIG_DUMMY_RS) += dummy_rs.o
1314
obj-$(CONFIG_WIREGUARD) += wireguard/
1415
obj-$(CONFIG_EQUALIZER) += eql.o
1516
obj-$(CONFIG_IFB) += ifb.o

drivers/net/dummy_rs.rs

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Rust dummy network driver
4+
//!
5+
//! The purpose of this driver is to provide a device to point a
6+
//! route through, but not to actually transmit packets.
7+
//!
8+
//! Why? If you have a machine whose only connection is an occasional
9+
//! PPP/SLIP/PLIP link, you can only connect to your own hostname
10+
//! when the link is up. Otherwise you have to use localhost.
11+
//! This isn't very consistent.
12+
//!
13+
//! One solution is to set up a dummy link using PPP/SLIP/PLIP,
14+
//! but this seems (to me) too much overhead for too little gain.
15+
//! This driver provides a small alternative. Thus you can do
16+
//!
17+
//! [when not running slip]
18+
//! ifconfig dummy slip.addr.ess.here up
19+
//! [to go to slip]
20+
//! ifconfig dummy down
21+
//! dip whatever
22+
//!
23+
//! This was written by looking at the dummy network driver from Nick
24+
//! Holloway, which was written by looking at Donald Becker's skeleton driver
25+
//! and the loopback driver.
26+
//!
27+
//! Finn Behrens, 30th April 2021
28+
//!
29+
//! rust rewrite of the C version from Nick Holloway, 27th May 1994
30+
//! see [dummy.c](./dummy.c)
31+
32+
#![no_std]
33+
#![feature(allocator_api, global_asm)]
34+
35+
use kernel::net::device;
36+
use kernel::net::prelude::*;
37+
use kernel::net::rtnl;
38+
use kernel::Error;
39+
use kernel::SavedAsPointer;
40+
use kernel::{
41+
net::netlink::{NlAttrVec, NlExtAck},
42+
prelude::*,
43+
};
44+
45+
module! {
46+
type: RustNetDummy,
47+
name: b"dummy_rs",
48+
author: b"Finn Behrens <me@kloenk.dev>",
49+
description: b"Rust dummy network driver",
50+
license: b"GPL v2",
51+
alias_rtnl_link: b"dummy_rs",
52+
params: {
53+
numdummies: usize {
54+
default: 0,
55+
permissions: 0,
56+
description: b"Number of dummy_rs pseudo devices",
57+
},
58+
},
59+
}
60+
61+
fn setup(dev: &mut NetDevice<DummyRsDev>) {
62+
dev.ether_setup();
63+
64+
dev.set_ops();
65+
66+
// Fill in device structure with ethernet-generic values.
67+
dev.add_flag(device::Iff::NOARP);
68+
dev.remove_flag(device::Iff::MULTICAST);
69+
70+
dev.add_private_flag(device::IffPriv::LIVE_ADDR_CHANGE);
71+
dev.add_private_flag(device::IffPriv::NO_QUEUE);
72+
73+
let mut feature = device::feature::NetIF::new();
74+
75+
feature += device::feature::NETIF_F_SG;
76+
feature += device::feature::NETIF_F_FRAGLIST;
77+
feature += device::feature::NETIF_F_GSO_SOFTWARE;
78+
feature += device::feature::NETIF_F_HW_CSUM;
79+
feature += device::feature::NETIF_F_HIGHDMA;
80+
feature += device::feature::NETIF_F_LLTX;
81+
feature += device::feature::NETIF_F_GSO_ENCAP_ALL;
82+
83+
dev.set_features(feature);
84+
dev.set_hw_features(feature);
85+
dev.set_hw_enc_features(feature);
86+
87+
dev.hw_addr_random();
88+
dev.set_mtu(0, 0);
89+
}
90+
91+
fn validate(tb: &NlAttrVec, _data: &NlAttrVec, _ext_ack: &NlExtAck) -> Result {
92+
if let Some(addr) = tb.get(kernel::bindings::IFLA_ADDRESS) {
93+
if Some(kernel::net::netlink::ETH_ALEN) != addr.nla_len() {
94+
return Err(Error::EINVAL);
95+
}
96+
if !addr.is_valid_ether_addr() {
97+
return Err(Error::EADDRNOTAVAIL);
98+
}
99+
}
100+
Ok(())
101+
}
102+
103+
rtnl_link_ops! {
104+
kind: b"dummy_rs",
105+
type: DummyRsDev,
106+
setup: setup,
107+
validate: validate,
108+
}
109+
110+
struct RustNetDummy {}
111+
112+
impl KernelModule for RustNetDummy {
113+
fn init() -> Result<Self> {
114+
let num = *numdummies.read();
115+
116+
unsafe { dummy_rs_link_ops.register() }?;
117+
118+
for _ in 0..(num) {
119+
let mut dev = NetDevice::new(
120+
DummyRsDev,
121+
kernel::c_str!("dummyrs%d"),
122+
kernel::net::device::NetNameAssingType::Enum,
123+
1,
124+
1,
125+
)?;
126+
dev.set_rtnl_ops(unsafe { &dummy_rs_link_ops });
127+
128+
if let Err(e) = dev.register() {
129+
pr_warn!("could not register: {}", e.to_kernel_errno());
130+
return Err(e);
131+
}
132+
}
133+
134+
Ok(RustNetDummy {
135+
//dev,
136+
})
137+
}
138+
}
139+
140+
impl Drop for RustNetDummy {
141+
fn drop(&mut self) {
142+
// TODO: remove unsafe somehow
143+
unsafe { dummy_rs_link_ops.unregister() };
144+
}
145+
}
146+
147+
struct DummyRsDev;
148+
149+
impl NetDeviceOps<Self> for DummyRsDev {
150+
kernel::declare_net_device_ops!(
151+
get_stats64,
152+
change_carrier,
153+
validate_addr,
154+
set_mac_addr,
155+
set_rx_mode
156+
);
157+
158+
fn init(dev: &mut NetDevice<Self>) -> Result {
159+
dev.set_new_pcpu_lstats()?;
160+
Ok(())
161+
}
162+
163+
fn uninit(dev: &mut NetDevice<Self>) {
164+
unsafe { dev.free_lstats() };
165+
}
166+
167+
fn start_xmit(skb: SkBuff, dev: &mut NetDevice<Self>) -> kernel::net::device::NetdevTX {
168+
let mut skb = skb;
169+
170+
dev.lstats_add(skb.len());
171+
172+
skb.tx_timestamp();
173+
drop(skb);
174+
175+
kernel::net::device::NetdevTX::TX_OK
176+
}
177+
178+
fn get_stats64(dev: &mut NetDevice<Self>, stats: &mut rtnl::RtnlLinkStats64) {
179+
stats.dev_read(dev);
180+
}
181+
182+
fn change_carrier(dev: &mut NetDevice<Self>, new_carrier: bool) -> Result {
183+
dev.carrier_set(new_carrier);
184+
185+
Ok(())
186+
}
187+
188+
fn validate_addr(dev: &mut NetDevice<Self>) -> Result {
189+
device::helpers::eth_validate_addr(dev)
190+
}
191+
192+
fn set_mac_addr(dev: &mut NetDevice<Self>, p: *mut kernel::c_types::c_void) -> Result {
193+
unsafe { device::helpers::eth_mac_addr(dev, p) }
194+
}
195+
196+
// [Someting about faking multicast](https://elixir.bootlin.com/linux/v5.12-rc4/source/drivers/net/dummy.c#L48).
197+
fn set_rx_mode(_dev: &mut NetDevice<Self>) {}
198+
}
199+
200+
impl NetDeviceAdapter for DummyRsDev {
201+
type Inner = Self;
202+
203+
type Ops = Self;
204+
205+
type EthOps = Self;
206+
207+
fn setup(dev: &mut NetDevice<Self>) {
208+
setup(dev);
209+
}
210+
}
211+
212+
impl EthToolOps<Self> for DummyRsDev {
213+
kernel::declare_eth_tool_ops!(get_drvinfo, get_ts_info);
214+
215+
fn get_drvinfo(_dev: &mut NetDevice<Self>, info: &mut ethtool::EthtoolDrvinfo) {
216+
// TODO: how to do this more efficient without unsafe?
217+
// FIXME: !!
218+
let info: &kernel::bindings::ethtool_drvinfo = info.get_internal();
219+
unsafe {
220+
kernel::bindings::strlcpy(
221+
&(info.driver) as *const _ as *mut i8,
222+
b"dummy_rs\0" as *const _ as *mut i8,
223+
32,
224+
);
225+
}
226+
}
227+
228+
fn get_ts_info(dev: &mut NetDevice<Self>, info: &mut ethtool::EthToolTsInfo) -> Result {
229+
kernel::net::ethtool::helpers::ethtool_op_get_ts_info(dev, info)
230+
}
231+
}

0 commit comments

Comments
 (0)