1use std::collections::HashSet;
2
3use anyhow::{Context, Result, bail};
4use bands::LteBand;
5use serde_json::Value;
6
7pub mod bands;
8#[cfg(feature = "mf289f")]
9pub(crate) mod util;
10
11#[cfg(feature = "g5ts")]
12pub mod g5ts;
13
14#[cfg(feature = "mf289f")]
15pub mod mf289f;
16
17pub(crate) fn normalize_router_url(url: &str) -> Result<String> {
18 let mut target = reqwest::Url::parse(url)
19 .with_context(|| format!("Invalid router URL: {url}"))?;
20
21 if target.cannot_be_a_base() {
22 bail!("Router URL must be an absolute base URL: {url}");
23 }
24
25 if target.query().is_some() || target.fragment().is_some() {
26 bail!("Router URL must not include a query string or fragment: {url}");
27 }
28
29 if !target.path().ends_with('/') {
30 let normalized_path = format!("{}/", target.path().trim_end_matches('/'));
31 target.set_path(&normalized_path);
32 }
33
34 Ok(target.into())
35}
36
37#[derive(serde::Serialize, Debug, Clone, Copy, PartialEq, Eq)]
38pub enum ConnectionMode {
39 #[serde(rename = "auto_dial")]
40 Auto,
41 #[serde(rename = "manual_dial")]
42 Manual,
43}
44
45impl Default for ConnectionMode {
46 fn default() -> Self {
47 ConnectionMode::Auto
48 }
49}
50
51#[derive(serde::Serialize, Debug, Clone, Copy, PartialEq, Eq)]
52pub enum BearerPreference {
53 #[serde(rename = "NETWORK_auto")]
54 Auto,
55 #[serde(rename = "4G_AND_5G")]
57 LteAndNr5g,
58 #[serde(rename = "LTE_AND_5G")]
60 Nr5gNsa,
61 #[serde(rename = "Only_5G")]
63 OnlyNr5g,
64 #[serde(rename = "Only_LTE")]
65 OnlyLte,
66 #[serde(rename = "Only_GSM")]
67 OnlyGsm,
68 #[serde(rename = "Only_WCDMA")]
69 OnlyWcdma,
70}
71
72impl Default for BearerPreference {
73 fn default() -> Self {
74 BearerPreference::Auto
75 }
76}
77
78#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
81pub enum ApnAuthMode {
82 None,
83 Pap,
84 Chap,
85 PapChap,
86}
87
88impl std::fmt::Display for ApnAuthMode {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 match self {
91 ApnAuthMode::None => write!(f, "NONE"),
92 ApnAuthMode::Pap => write!(f, "PAP"),
93 ApnAuthMode::Chap => write!(f, "CHAP"),
94 ApnAuthMode::PapChap => write!(f, "PAP_CHAP"),
95 }
96 }
97}
98
99#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
100pub enum PdpType {
101 IPv4,
102 IPv6,
103 IPv4v6,
104}
105
106impl std::fmt::Display for PdpType {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 match self {
109 PdpType::IPv4 => write!(f, "IPv4"),
110 PdpType::IPv6 => write!(f, "IPv6"),
111 PdpType::IPv4v6 => write!(f, "IPv4v6"),
112 }
113 }
114}
115
116#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
117pub struct ApnProfile {
118 pub profile_id: Option<String>,
119 pub profile_name: String,
120 pub apn: String,
121 pub pdp_type: PdpType,
122 pub auth_mode: ApnAuthMode,
123 pub username: String,
124 pub password: String,
125}
126
127#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
130pub struct DhcpSettings {
131 pub ip_address: String,
132 pub subnet_mask: String,
133 pub dhcp_enabled: bool,
134 pub lease_time: u32,
135}
136
137#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
140pub struct MtuSettings {
141 pub mtu: u32,
142 pub mss: u32,
143}
144
145#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
148pub struct SmsSettings {
149 pub validity: String,
150 pub center_number: String,
151 pub delivery_report: bool,
152}
153
154#[async_trait::async_trait]
176pub trait RouterClient {
177 async fn login(&mut self, password: &str) -> Result<()>;
179
180 async fn logout(&mut self) -> Result<()>;
182
183 async fn disconnect_network(&self) -> Result<()>;
185
186 async fn connect_network(&self) -> Result<()>;
188
189 async fn reboot(&self) -> Result<()>;
191
192 async fn get_version(&self) -> Result<(String, String)>;
197
198 async fn set_connection_mode(
200 &self,
201 connection_mode: ConnectionMode,
202 roam: bool,
203 ) -> Result<()>;
204
205 async fn set_network_bearer_preference(
212 &self,
213 bearer_preference: BearerPreference,
214 ) -> Result<()>;
215
216 async fn set_upnp(&self, enabled: bool) -> Result<()>;
218
219 async fn set_dmz(&self, ip_address: Option<String>) -> Result<()>;
221
222 async fn select_lte_band(&self, lte_band: Option<HashSet<LteBand>>) -> Result<()>;
224
225 async fn set_dns(&self, manual: Option<[String; 2]>) -> Result<()>;
227
228 async fn get_status(&self) -> Result<Value>;
230
231 async fn get_apn_mode(&self) -> Result<bool> {
233 bail!("get_apn_mode is not supported on this model")
234 }
235
236 async fn set_apn_mode(&self, _manual: bool) -> Result<()> {
238 bail!("set_apn_mode is not supported on this model")
239 }
240
241 async fn get_apn_profiles(&self) -> Result<Vec<ApnProfile>> {
243 bail!("get_apn_profiles is not supported on this model")
244 }
245
246 async fn set_apn_profile(&self, _profile: &ApnProfile) -> Result<()> {
248 bail!("set_apn_profile is not supported on this model")
249 }
250
251 async fn enable_apn_profile(&self, _profile_id: &str) -> Result<()> {
253 bail!("enable_apn_profile is not supported on this model")
254 }
255
256 async fn get_dhcp_settings(&self) -> Result<DhcpSettings> {
258 bail!("get_dhcp_settings is not supported on this model")
259 }
260
261 async fn set_dhcp_settings(&self, _settings: &DhcpSettings) -> Result<()> {
263 bail!("set_dhcp_settings is not supported on this model")
264 }
265
266 async fn get_mtu_settings(&self) -> Result<MtuSettings> {
268 bail!("get_mtu_settings is not supported on this model")
269 }
270
271 async fn set_mtu_settings(&self, _settings: &MtuSettings) -> Result<()> {
273 bail!("set_mtu_settings is not supported on this model")
274 }
275
276 async fn get_sms_settings(&self) -> Result<SmsSettings> {
278 bail!("get_sms_settings is not supported on this model")
279 }
280
281 async fn get_network_info(&self) -> Result<Value> {
283 bail!("get_network_info is not supported on this model")
284 }
285
286 async fn get_sim_info(&self) -> Result<Value> {
288 bail!("get_sim_info is not supported on this model")
289 }
290
291 async fn get_device_info(&self) -> Result<Value> {
293 bail!("get_device_info is not supported on this model")
294 }
295
296 async fn get_connected_devices(&self) -> Result<Value> {
298 bail!("get_connected_devices is not supported on this model")
299 }
300}
301