1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Net functions.
use macaddr::MacAddr6;
use std::{
ffi::{OsStr, OsString},
io::{Error, ErrorKind, Result},
};
use super::{
util::{FunctionDir, Status},
Function, Handle,
};
use crate::{gadget::Class, hex_u8};
/// Class of USB network device.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NetClass {
/// Ethernet Control Model (CDC ECM).
///
/// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_ECM` must be enabled.
Ecm,
/// Subset of Ethernet Control Model (CDC ECM subset).
///
/// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_ECM_SUBSET` must be enabled.
EcmSubset,
/// Ethernet Emulation Model (CDC EEM).
///
/// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_EEM` must be enabled.
Eem,
/// Network Control Model (CDC NCM).
///
/// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_NCM` must be enabled.
Ncm,
/// Remote Network Driver Interface Specification (RNDIS).
///
/// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_RNDIS` must be enabled.
Rndis,
}
impl NetClass {
fn driver(&self) -> &OsStr {
OsStr::new(match self {
NetClass::Ecm => "ecm",
NetClass::EcmSubset => "geth",
NetClass::Eem => "eem",
NetClass::Ncm => "ncm",
NetClass::Rndis => "rndis",
})
}
}
/// Builder for Communication Device Class (CDC) network functions.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct NetBuilder {
net_class: NetClass,
/// MAC address of device's end of this Ethernet over USB link.
pub dev_addr: Option<MacAddr6>,
/// MAC address of host's end of this Ethernet over USB link.
pub host_addr: Option<MacAddr6>,
/// Queue length multiplier for high and super speed.
pub qmult: Option<u32>,
/// For RNDIS only: interface class.
pub interface_class: Option<Class>,
}
impl NetBuilder {
/// Build the USB function.
///
/// The returned handle must be added to a USB gadget configuration.
pub fn build(self) -> (Net, Handle) {
let dir = FunctionDir::new();
(Net { dir: dir.clone() }, Handle::new(NetFunction { builder: self, dir }))
}
}
#[derive(Debug)]
struct NetFunction {
builder: NetBuilder,
dir: FunctionDir,
}
impl Function for NetFunction {
fn driver(&self) -> OsString {
self.builder.net_class.driver().to_os_string()
}
fn dir(&self) -> FunctionDir {
self.dir.clone()
}
fn register(&self) -> Result<()> {
if let Some(dev_addr) = self.builder.dev_addr {
self.dir.write("dev_addr", dev_addr.to_string())?;
}
if let Some(host_addr) = self.builder.host_addr {
self.dir.write("host_addr", host_addr.to_string())?;
}
if let Some(qmult) = self.builder.qmult {
self.dir.write("qmult", qmult.to_string())?;
}
if let (NetClass::Rndis, Some(class)) = (self.builder.net_class, self.builder.interface_class) {
self.dir.write("class", hex_u8(class.class))?;
self.dir.write("subclass", hex_u8(class.sub_class))?;
self.dir.write("protocol", hex_u8(class.protocol))?;
}
Ok(())
}
}
/// Communication Device Class (CDC) network function.
#[derive(Debug)]
pub struct Net {
dir: FunctionDir,
}
impl Net {
/// Creates a new USB network function.
pub fn new(net_class: NetClass) -> (Net, Handle) {
Self::builder(net_class).build()
}
/// Creates a new USB network function builder.
pub fn builder(net_class: NetClass) -> NetBuilder {
NetBuilder { net_class, dev_addr: None, host_addr: None, qmult: None, interface_class: None }
}
/// Access to registration status.
pub fn status(&self) -> Status {
self.dir.status()
}
/// MAC address of device's end of this Ethernet over USB link.
pub fn dev_addr(&self) -> Result<MacAddr6> {
self.dir.read_string("dev_addr")?.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
/// MAC address of host's end of this Ethernet over USB link.
pub fn host_addr(&self) -> Result<MacAddr6> {
self.dir.read_string("host_addr")?.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
/// Network device interface name associated with this function instance.
pub fn ifname(&self) -> Result<OsString> {
self.dir.read_os_string("ifname")
}
}