1use core::fmt::Display;
2use core::str::FromStr;
3
4pub use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
6
7#[cfg(feature = "use_serde")]
8use serde::{Deserialize, Serialize};
9
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12#[cfg_attr(feature = "std", derive(Hash))]
13#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
14pub struct Mask(pub u8);
15
16impl FromStr for Mask {
17 type Err = &'static str;
18
19 fn from_str(s: &str) -> Result<Self, Self::Err> {
20 s.parse::<u8>()
21 .map_err(|_| "Invalid subnet mask")
22 .map_or_else(Err, |mask| {
23 if (1..=32).contains(&mask) {
24 Ok(Mask(mask))
25 } else {
26 Err("Mask should be a number between 1 and 32")
27 }
28 })
29 }
30}
31
32impl Display for Mask {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 write!(f, "{}", self.0)
35 }
36}
37
38impl TryFrom<Ipv4Addr> for Mask {
39 type Error = ();
40
41 fn try_from(ip: Ipv4Addr) -> Result<Self, Self::Error> {
42 let octets = ip.octets();
43 let addr: u32 = ((octets[0] as u32 & 0xff) << 24)
44 | ((octets[1] as u32 & 0xff) << 16)
45 | ((octets[2] as u32 & 0xff) << 8)
46 | (octets[3] as u32 & 0xff);
47
48 if addr.leading_ones() + addr.trailing_zeros() == 32 {
49 Ok(Mask(addr.leading_ones() as u8))
50 } else {
51 Err(())
52 }
53 }
54}
55
56impl From<Mask> for Ipv4Addr {
57 fn from(mask: Mask) -> Self {
58 let addr: u32 = ((1 << (32 - mask.0)) - 1) ^ 0xffffffffu32;
59
60 let (a, b, c, d) = (
61 ((addr >> 24) & 0xff) as u8,
62 ((addr >> 16) & 0xff) as u8,
63 ((addr >> 8) & 0xff) as u8,
64 (addr & 0xff) as u8,
65 );
66
67 Ipv4Addr::new(a, b, c, d)
68 }
69}
70
71#[derive(Copy, Clone, Debug, Eq, PartialEq)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[cfg_attr(feature = "std", derive(Hash))]
74#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
75pub struct Subnet {
76 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
77 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_serialize"))]
78 #[cfg_attr(feature = "use_serde", serde(deserialize_with = "ipv4_deserialize"))]
79 pub gateway: Ipv4Addr,
80 pub mask: Mask,
81}
82
83impl Display for Subnet {
84 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 write!(f, "{}/{}", self.gateway, self.mask)
86 }
87}
88
89impl FromStr for Subnet {
90 type Err = &'static str;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 let mut split = s.split('/');
94 if let Some(gateway_str) = split.next() {
95 if let Some(mask_str) = split.next() {
96 if split.next().is_none() {
97 if let Ok(gateway) = gateway_str.parse::<Ipv4Addr>() {
98 return mask_str.parse::<Mask>().map(|mask| Self { gateway, mask });
99 } else {
100 return Err("Invalid IP address format, expected XXX.XXX.XXX.XXX");
101 }
102 }
103 }
104 }
105
106 Err("Expected <gateway-ip-address>/<mask>")
107 }
108}
109
110#[derive(Copy, Clone, Debug, Eq, PartialEq)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
113pub struct ClientSettings {
114 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
115 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_serialize"))]
116 #[cfg_attr(feature = "use_serde", serde(deserialize_with = "ipv4_deserialize"))]
117 pub ip: Ipv4Addr,
118 pub subnet: Subnet,
119 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
120 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
121 #[cfg_attr(
122 feature = "use_serde",
123 serde(deserialize_with = "ipv4_opt_deserialize")
124 )]
125 pub dns: Option<Ipv4Addr>,
126 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
127 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
128 #[cfg_attr(
129 feature = "use_serde",
130 serde(deserialize_with = "ipv4_opt_deserialize")
131 )]
132 pub secondary_dns: Option<Ipv4Addr>,
133}
134
135impl Default for ClientSettings {
136 fn default() -> ClientSettings {
137 ClientSettings {
138 ip: Ipv4Addr::new(192, 168, 71, 200),
139 subnet: Subnet {
140 gateway: Ipv4Addr::new(192, 168, 71, 1),
141 mask: Mask(24),
142 },
143 dns: Some(Ipv4Addr::new(8, 8, 8, 8)),
144 secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)),
145 }
146 }
147}
148
149#[derive(Default, Clone, Debug, PartialEq, Eq)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
152pub struct DHCPClientSettings {
153 pub hostname: Option<heapless::String<30>>,
154}
155
156#[derive(Clone, Debug, PartialEq, Eq)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
159pub enum ClientConfiguration {
160 DHCP(DHCPClientSettings),
161 Fixed(ClientSettings),
162}
163
164impl ClientConfiguration {
165 pub fn as_fixed_settings_ref(&self) -> Option<&ClientSettings> {
166 match self {
167 Self::Fixed(client_settings) => Some(client_settings),
168 _ => None,
169 }
170 }
171
172 pub fn as_fixed_settings_mut(&mut self) -> &mut ClientSettings {
173 match self {
174 Self::Fixed(client_settings) => client_settings,
175 _ => {
176 *self = ClientConfiguration::Fixed(Default::default());
177 self.as_fixed_settings_mut()
178 }
179 }
180 }
181}
182
183impl Default for ClientConfiguration {
184 fn default() -> ClientConfiguration {
185 ClientConfiguration::DHCP(Default::default())
186 }
187}
188
189#[derive(Clone, Debug, Eq, PartialEq)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
192pub struct RouterConfiguration {
193 pub subnet: Subnet,
194 pub dhcp_enabled: bool,
195 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
196 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
197 #[cfg_attr(
198 feature = "use_serde",
199 serde(deserialize_with = "ipv4_opt_deserialize")
200 )]
201 pub dns: Option<Ipv4Addr>,
202 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
203 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
204 #[cfg_attr(
205 feature = "use_serde",
206 serde(deserialize_with = "ipv4_opt_deserialize")
207 )]
208 pub secondary_dns: Option<Ipv4Addr>,
209}
210
211impl Default for RouterConfiguration {
212 fn default() -> RouterConfiguration {
213 RouterConfiguration {
214 subnet: Subnet {
215 gateway: Ipv4Addr::new(192, 168, 71, 1),
216 mask: Mask(24),
217 },
218 dhcp_enabled: true,
219 dns: Some(Ipv4Addr::new(8, 8, 8, 8)),
220 secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)),
221 }
222 }
223}
224
225#[derive(Clone, Debug, Eq, PartialEq)]
226#[cfg_attr(feature = "defmt", derive(defmt::Format))]
227#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
228pub enum Configuration {
229 Client(ClientConfiguration),
230 Router(RouterConfiguration),
231}
232
233impl Default for Configuration {
234 fn default() -> Self {
235 Self::Client(Default::default())
236 }
237}
238
239#[derive(Copy, Clone, Debug, Eq, PartialEq)]
240#[cfg_attr(feature = "defmt", derive(defmt::Format))]
241#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
242pub struct IpInfo {
243 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
244 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_serialize"))]
245 #[cfg_attr(feature = "use_serde", serde(deserialize_with = "ipv4_deserialize"))]
246 pub ip: Ipv4Addr,
247 pub subnet: Subnet,
248 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
249 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
250 #[cfg_attr(
251 feature = "use_serde",
252 serde(deserialize_with = "ipv4_opt_deserialize")
253 )]
254 pub dns: Option<Ipv4Addr>,
255 #[cfg_attr(feature = "defmt", defmt(Debug2Format))]
256 #[cfg_attr(feature = "use_serde", serde(serialize_with = "ipv4_opt_serialize"))]
257 #[cfg_attr(
258 feature = "use_serde",
259 serde(deserialize_with = "ipv4_opt_deserialize")
260 )]
261 pub secondary_dns: Option<Ipv4Addr>,
262}
263
264pub trait Interface {
265 type Error;
266
267 fn get_iface_configuration(&self) -> Result<Configuration, Self::Error>;
268 fn set_iface_configuration(&mut self, conf: &Configuration) -> Result<(), Self::Error>;
269
270 fn is_iface_up(&self) -> bool;
271
272 fn get_ip_info(&self) -> Result<IpInfo, Self::Error>;
273}
274
275#[cfg(feature = "use_serde")]
276fn ipv4_serialize<S>(ipv4: &Ipv4Addr, serializer: S) -> Result<S::Ok, S::Error>
277where
278 S: serde::Serializer,
279{
280 ipv4.octets().serialize(serializer)
281}
282
283#[cfg(feature = "use_serde")]
284fn ipv4_deserialize<'de, D>(deserializer: D) -> Result<Ipv4Addr, D::Error>
285where
286 D: serde::Deserializer<'de>,
287{
288 <[u8; 4]>::deserialize(deserializer).map(Ipv4Addr::from)
289}
290
291#[cfg(feature = "use_serde")]
292fn ipv4_opt_serialize<S>(ipv4: &Option<Ipv4Addr>, serializer: S) -> Result<S::Ok, S::Error>
293where
294 S: serde::Serializer,
295{
296 ipv4.map(|ip| ip.octets()).serialize(serializer)
297}
298
299#[cfg(feature = "use_serde")]
300fn ipv4_opt_deserialize<'de, D>(deserializer: D) -> Result<Option<Ipv4Addr>, D::Error>
301where
302 D: serde::Deserializer<'de>,
303{
304 <Option<[u8; 4]>>::deserialize(deserializer).map(|octets| octets.map(Ipv4Addr::from))
305}