Skip to main content

usb_gadget/function/
net.rs

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