Skip to content

Commit 02f3c28

Browse files
committed
dbus: saved connections; forget_btn thread locks; context correction for network settings; re-introduced EAP
1 parent 24387e7 commit 02f3c28

File tree

8 files changed

+621
-301
lines changed

8 files changed

+621
-301
lines changed

nmrs-core/src/dbus.rs

Lines changed: 438 additions & 63 deletions
Large diffs are not rendered by default.

nmrs-core/src/models.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub struct Network {
88
pub ssid: String,
99
pub bssid: Option<String>,
1010
pub strength: Option<u8>,
11+
pub frequency: Option<u32>,
1112
pub secured: bool,
1213
pub is_psk: bool,
1314
pub is_eap: bool,
@@ -58,6 +59,12 @@ pub struct EapOptions {
5859
pub phase2: Phase2,
5960
}
6061

62+
pub struct ConnectionOptions {
63+
pub autoconnect: bool,
64+
pub autoconnect_priority: Option<i32>,
65+
pub autoconnect_retries: Option<i32>,
66+
}
67+
6168
pub enum WifiSecurity {
6269
Open,
6370
WpaPsk { psk: String },

nmrs-core/src/wifi_builders.rs

Lines changed: 63 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,58 @@
1+
use models::ConnectionOptions;
12
use std::collections::HashMap;
23
use zvariant::Value;
34

4-
use crate::models;
5+
use crate::models::{self, EapMethod};
56

6-
/*fn bytes(val: &str) -> Vec<u8> {
7+
fn bytes(val: &str) -> Vec<u8> {
78
val.as_bytes().to_vec()
89
}
910

11+
fn string_array(xs: &[&str]) -> Value<'static> {
12+
let vals: Vec<String> = xs.iter().map(|s| s.to_string()).collect();
13+
Value::from(vals)
14+
}
15+
1016
fn base_wifi_section(ssid: &str) -> HashMap<&'static str, Value<'static>> {
1117
let mut s = HashMap::new();
1218
s.insert("ssid", Value::from(bytes(ssid)));
1319
s.insert("mode", Value::from("infrastructure"));
1420
s
1521
}
1622

17-
fn base_connection_section(ssid: &str) -> HashMap<&'static str, Value<'static>> {
23+
fn base_connection_section(
24+
ssid: &str,
25+
opts: &ConnectionOptions,
26+
) -> HashMap<&'static str, Value<'static>> {
1827
let mut s = HashMap::new();
1928
s.insert("type", Value::from("802-11-wireless"));
2029
s.insert("id", Value::from(ssid.to_string()));
2130
s.insert("uuid", Value::from(uuid::Uuid::new_v4().to_string()));
22-
s.insert("autoconnect", Value::from(true));
31+
s.insert("autoconnect", Value::from(opts.autoconnect));
32+
33+
if let Some(p) = opts.autoconnect_priority {
34+
s.insert("autoconnect-priority", Value::from(p));
35+
}
36+
37+
if let Some(r) = opts.autoconnect_retries {
38+
s.insert("autoconnect-retries", Value::from(r));
39+
}
40+
2341
s
2442
}
2543

2644
fn build_psk_security(psk: &str) -> HashMap<&'static str, Value<'static>> {
2745
let mut sec = HashMap::new();
46+
2847
sec.insert("key-mgmt", Value::from("wpa-psk"));
2948
sec.insert("psk", Value::from(psk.to_string()));
30-
// hardening maybe
31-
// sec.insert("proto", Value::from(vec!["rsn"]));
32-
// pairwise
33-
// etc...
49+
sec.insert("psk-flags", Value::from(0u32)); // 0 = agent-owned, provided during activation
50+
sec.insert("auth-alg", Value::from("open"));
51+
52+
sec.insert("proto", string_array(&["rsn"]));
53+
sec.insert("pairwise", string_array(&["ccmp"]));
54+
sec.insert("group", string_array(&["ccmp"]));
55+
3456
sec
3557
}
3658

@@ -42,17 +64,18 @@ fn build_eap_security(
4264
) {
4365
let mut sec = HashMap::new();
4466
sec.insert("key-mgmt", Value::from("wpa-eap"));
45-
sec.insert("auth-alg", Value::from("OPEN"));
67+
sec.insert("auth-alg", Value::from("open"));
4668
// same hardening tips as psk
4769
// proto, pairwise, group, etc.
4870

4971
// 802-1x
5072
let mut e1x = HashMap::new();
51-
let eap_vec = match opts.method {
52-
models::EapMethod::Peap => vec!["peap"],
53-
models::EapMethod::Ttls => vec!["ttls"],
73+
74+
let eap_str = match opts.method {
75+
EapMethod::Peap => "peap",
76+
EapMethod::Ttls => "ttls",
5477
};
55-
e1x.insert("eap", Value::from(eap_vec));
78+
e1x.insert("eap", string_array(&[eap_str]));
5679
e1x.insert("identity", Value::from(opts.identity.clone()));
5780
e1x.insert("password", Value::from(opts.password.clone()));
5881

@@ -86,67 +109,48 @@ fn build_eap_security(
86109
pub fn build_wifi_connection(
87110
ssid: &str,
88111
security: &models::WifiSecurity,
112+
opts: &ConnectionOptions,
89113
) -> HashMap<&'static str, HashMap<&'static str, Value<'static>>> {
90114
let mut conn: HashMap<&'static str, HashMap<&'static str, Value<'static>>> = HashMap::new();
91-
conn.insert("connection", base_connection_section(ssid));
115+
116+
// base connections
117+
conn.insert("connection", base_connection_section(ssid, opts));
92118
conn.insert("802-11-wireless", base_wifi_section(ssid));
93119

120+
// Add IPv4 and IPv6 configuration to prevent state 60 stall
121+
// TODO: Expand upon auto/manual configuration options
122+
let mut ipv4 = HashMap::new();
123+
ipv4.insert("method", Value::from("auto"));
124+
conn.insert("ipv4", ipv4);
125+
126+
let mut ipv6 = HashMap::new();
127+
ipv6.insert("method", Value::from("auto"));
128+
conn.insert("ipv6", ipv6);
129+
94130
match security {
95131
models::WifiSecurity::Open => {}
96132

97133
models::WifiSecurity::WpaPsk { psk } => {
98-
conn.insert("802-11-wireless-security", build_psk_security(psk.as_str()));
99-
}
134+
// point wireless at security section
135+
if let Some(w) = conn.get_mut("802-11-wireless") {
136+
w.insert("security", Value::from("802-11-wireless-security"));
137+
}
100138

101-
models::WifiSecurity::WpaEap { opts } => {
102-
let (sec, e1x) = build_eap_security(&opts);
139+
let sec = build_psk_security(psk);
103140
conn.insert("802-11-wireless-security", sec);
104-
conn.insert("802-1x", e1x);
105141
}
106-
}
107-
conn
108-
}*/
109-
110-
pub fn build_wifi_connection(
111-
ssid: &str,
112-
security: &models::WifiSecurity,
113-
) -> HashMap<&'static str, HashMap<&'static str, zvariant::Value<'static>>> {
114-
let mut conn = HashMap::new();
115-
116-
let mut s_conn = HashMap::new();
117-
s_conn.insert("type", Value::from("802-11-wireless"));
118-
s_conn.insert("id", Value::from(ssid.to_string()));
119-
s_conn.insert("uuid", Value::from(uuid::Uuid::new_v4().to_string()));
120-
s_conn.insert("autoconnect", Value::from(true));
121-
s_conn.insert("interface-name", Value::from("wlan0"));
122-
conn.insert("connection", s_conn);
123142

124-
let mut s_wifi = HashMap::new();
125-
s_wifi.insert("ssid", Value::from(ssid.as_bytes().to_vec()));
126-
s_wifi.insert("mode", Value::from("infrastructure"));
143+
models::WifiSecurity::WpaEap { opts } => {
144+
if let Some(w) = conn.get_mut("802-11-wireless") {
145+
w.insert("security", Value::from("802-11-wireless-security"));
146+
}
127147

128-
match security {
129-
models::WifiSecurity::Open => {}
130-
models::WifiSecurity::WpaPsk { psk } => {
131-
s_wifi.insert("security", Value::from("802-11-wireless-security"));
132-
let mut s_sec = HashMap::new();
133-
s_sec.insert("key-mgmt", Value::from("wpa-psk"));
134-
s_sec.insert("auth-alg", Value::from("open"));
135-
s_sec.insert("psk", Value::from(psk.to_string()));
136-
conn.insert("802-11-wireless-security", s_sec);
148+
let (mut sec, e1x) = build_eap_security(opts);
149+
sec.insert("auth-alg", Value::from("open"));
150+
conn.insert("802-11-wireless-security", sec);
151+
conn.insert("802-1x", e1x);
137152
}
138-
_ => {}
139153
}
140154

141-
conn.insert("802-11-wireless", s_wifi);
142-
143-
let mut ipv4 = HashMap::new();
144-
ipv4.insert("method", Value::from("auto"));
145-
conn.insert("ipv4", ipv4);
146-
147-
let mut ipv6 = HashMap::new();
148-
ipv6.insert("method", Value::from("auto"));
149-
conn.insert("ipv6", ipv6);
150-
151155
conn
152156
}

nmrs-core/tests/wifi_buillders_test.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
use nmrs_core::models::WifiSecurity;
1+
use nmrs_core::models::{ConnectionOptions, WifiSecurity};
22
use nmrs_core::wifi_builders::build_wifi_connection;
33
use zvariant::Value;
44

5+
fn opts() -> ConnectionOptions {
6+
ConnectionOptions {
7+
autoconnect: true,
8+
autoconnect_priority: None,
9+
autoconnect_retries: None,
10+
}
11+
}
12+
513
#[test]
614
fn builds_open_wifi_connection() {
7-
let conn = build_wifi_connection("testnet", &WifiSecurity::Open);
15+
let conn = build_wifi_connection("testnet", &WifiSecurity::Open, &opts());
816
assert!(conn.contains_key("connection"));
917
assert!(conn.contains_key("802-11-wireless"));
1018
assert!(conn.contains_key("ipv4"));
@@ -18,6 +26,7 @@ fn builds_psk_wifi_connection_with_security_section() {
1826
&WifiSecurity::WpaPsk {
1927
psk: "pw123".into(),
2028
},
29+
&opts(),
2130
);
2231
let has_sec = conn.contains_key("802-11-wireless-security");
2332
assert!(has_sec, "security section missing");

nmrs-ui/src/ui/connect.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,29 @@ fn draw_connect_modal(parent: &ApplicationWindow, ssid: &str, is_eap: bool) {
6868
let ssid_owned = ssid.to_string();
6969
let user_entry_clone = user_entry.clone();
7070

71+
let status_label = Label::new(Some(""));
72+
status_label.add_css_class("status-label");
73+
vbox.append(&status_label);
74+
7175
{
7276
let dialog_rc = dialog_rc.clone();
77+
let status_label = status_label.clone();
78+
7379
entry.connect_activate(move |entry| {
7480
let pwd = entry.text().to_string();
81+
7582
let username = user_entry_clone
7683
.as_ref()
7784
.map(|e| e.text().to_string())
7885
.unwrap_or_default();
7986
let ssid = ssid_owned.clone();
87+
let dialog = dialog_rc.clone();
88+
let status = status_label.clone();
89+
let entry_clone = entry.clone();
8090

81-
eprintln!("User entered username={username}, password={pwd}");
91+
// Prevent double submission
92+
entry.set_sensitive(false);
93+
status.set_text("Connecting...");
8294

8395
glib::MainContext::default().spawn_local(async move {
8496
eprintln!("---in spawned task here--");
@@ -107,17 +119,28 @@ fn draw_connect_modal(parent: &ApplicationWindow, ssid: &str, is_eap: bool) {
107119

108120
println!("Calling nm.connect() for '{ssid}'");
109121
match nm.connect(&ssid, creds).await {
110-
Ok(_) => println!("nm.connect() succeeded!"),
111-
Err(err) => eprintln!("nm.connect() failed: {err}"),
122+
Ok(_) => {
123+
println!("nm.connect() succeeded!");
124+
status.set_text("✓ Connected!");
125+
glib::timeout_future_seconds(1).await;
126+
dialog.close();
127+
}
128+
Err(err) => {
129+
eprintln!("nm.connect() failed: {err}");
130+
status.set_text(&format!("✗ Failed: {err}"));
131+
entry_clone.set_sensitive(true);
132+
}
112133
}
113134
}
114-
Err(err) => eprintln!("Failed to create NetworkManager: {err}"),
135+
Err(err) => {
136+
eprintln!("Failed to create NetworkManager: {err}");
137+
status.set_text(&format!("✗ Error: {err}"));
138+
entry_clone.set_sensitive(true);
139+
}
115140
}
116141

117-
println!("---finsihed spawned task---");
142+
println!("---finished spawned task---");
118143
});
119-
120-
dialog_rc.close();
121144
});
122145
}
123146

0 commit comments

Comments
 (0)