Added comparing hw_address everywhere

This commit is contained in:
András 2024-12-04 22:33:41 +02:00 committed by Michael Murphy
parent b743c724ff
commit 2198fa9b9a
5 changed files with 479 additions and 279 deletions

View file

@ -7,6 +7,8 @@ use itertools::Itertools;
use std::collections::HashMap;
use zbus::zvariant::ObjectPath;
use super::hw_address::HwAddress;
pub async fn handle_wireless_device(
device: WirelessDevice<'_>,
hw_address: Option<String>,
@ -45,7 +47,10 @@ pub async fn handle_wireless_device(
state,
working: false,
path: ap.inner().path().to_owned(),
hw_address: hw_address.as_ref().unwrap_or(&"".to_string()).clone(),
hw_address: hw_address
.as_ref()
.and_then(|str_addr| HwAddress::from_str(str_addr))
.unwrap_or_default(),
},
);
}
@ -63,5 +68,5 @@ pub struct AccessPoint {
pub state: DeviceState,
pub working: bool,
pub path: ObjectPath<'static>,
pub hw_address: String,
pub hw_address: HwAddress,
}

View file

@ -6,6 +6,8 @@ use cosmic_dbus_networkmanager::{
};
use std::net::Ipv4Addr;
use super::hw_address::HwAddress;
pub async fn active_connections(
active_connections: Vec<ActiveConnection<'_>>,
) -> zbus::Result<Vec<ActiveConnectionInfo>> {
@ -40,7 +42,8 @@ pub async fn active_connections(
Some(SpecificDevice::Wired(wired_device)) => {
info.push(ActiveConnectionInfo::Wired {
name: connection.id().await?,
hw_address: wired_device.hw_address().await?,
hw_address: HwAddress::from_string(&wired_device.hw_address().await?)
.unwrap_or_default(),
speed: wired_device.speed().await?,
ip_addresses: addresses.clone(),
});
@ -50,7 +53,10 @@ pub async fn active_connections(
info.push(ActiveConnectionInfo::WiFi {
name: String::from_utf8_lossy(&access_point.ssid().await?).into_owned(),
ip_addresses: addresses.clone(),
hw_address: wireless_device.hw_address().await?,
hw_address: HwAddress::from_string(
&wireless_device.hw_address().await?,
)
.unwrap_or_default(),
state,
strength: access_point.strength().await.unwrap_or_default(),
});
@ -83,14 +89,14 @@ pub async fn active_connections(
pub enum ActiveConnectionInfo {
Wired {
name: String,
hw_address: String,
hw_address: HwAddress,
speed: u32,
ip_addresses: Vec<Ipv4Addr>,
},
WiFi {
name: String,
ip_addresses: Vec<Ipv4Addr>,
hw_address: String,
hw_address: HwAddress,
state: ActiveConnectionState,
strength: u8,
},
@ -108,4 +114,11 @@ impl ActiveConnectionInfo {
Self::Vpn { name, .. } => name.clone(),
}
}
pub fn hw_address(&self) -> HwAddress {
match &self {
Self::Wired { hw_address, .. } => *hw_address,
Self::WiFi { hw_address, .. } => *hw_address,
Self::Vpn { .. } => HwAddress::default(),
}
}
}

View file

@ -0,0 +1,39 @@
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
pub struct HwAddress {
address: u64,
}
impl HwAddress {
pub fn from_str(arg: &str) -> Option<Self> {
let columnless_vec = arg.split(":").collect::<Vec<&str>>();
if columnless_vec.len() * 3 - 1 != arg.len() {
return None;
}
for byte in &columnless_vec {
if byte.len() != 2 {
return None;
}
}
u64::from_str_radix(columnless_vec.join("").as_str(), 16)
.ok()
.and_then(|address| Some(HwAddress { address }))
}
pub fn from_string(arg: &String) -> Option<Self> {
HwAddress::from_str(arg.as_str())
}
pub fn to_string(&self) -> String {
// return if self.address > 100000000000000 {
// "Intel Corp".to_string()
// } else {
// "TP-Link".to_string()
// };
format!("{:#x}", self.address)
.trim_start_matches("0x")
.chars()
.collect::<Vec<_>>()
.chunks(2)
.map(|chunk| chunk.iter().cloned().collect::<String>())
.collect::<Vec<String>>()
.join(":")
}
}

View file

@ -2,6 +2,7 @@ pub mod active_conns;
pub mod available_wifi;
pub mod current_networks;
pub mod devices;
pub mod hw_address;
pub mod wireless_enabled;
use std::{collections::HashMap, fmt::Debug, time::Duration};
@ -24,6 +25,7 @@ use futures::{
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
SinkExt, StreamExt,
};
use hw_address::HwAddress;
use tokio::process::Command;
use zbus::{
zvariant::{self, Value},
@ -172,15 +174,19 @@ async fn start_listening(
};
_ = output.send(response).await;
}
Some(NetworkManagerRequest::Password(ssid, password)) => {
Some(NetworkManagerRequest::Password(ssid, password, hw_address)) => {
let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
let success = nm_state
.connect_wifi(&conn, &ssid, Some(&password))
.connect_wifi(&conn, &ssid, Some(&password), hw_address)
.await
.is_ok();
let status = Some(NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::Password(ssid.clone(), password.clone()),
req: NetworkManagerRequest::Password(
ssid.clone(),
password.clone(),
hw_address,
),
success,
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
});
@ -190,16 +196,18 @@ async fn start_listening(
} else {
_ = output
.send(NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::Password(ssid, password),
req: NetworkManagerRequest::Password(ssid, password, hw_address),
success: false,
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
})
.await;
}
}
Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => {
Some(NetworkManagerRequest::SelectAccessPoint(ssid, hw_address)) => {
let state = NetworkManagerState::new(&conn).await.unwrap_or_default();
let success = if let Err(err) = state.connect_wifi(&conn, &ssid, None).await {
let success = if let Err(err) =
state.connect_wifi(&conn, &ssid, None, hw_address).await
{
tracing::error!("Failed to connect to access point: {:?}", err);
false
} else {
@ -208,7 +216,7 @@ async fn start_listening(
_ = output
.send(NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone(), hw_address),
success,
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
})
@ -266,9 +274,9 @@ async fn start_listening(
pub enum NetworkManagerRequest {
SetAirplaneMode(bool),
SetWiFi(bool),
SelectAccessPoint(String),
SelectAccessPoint(String, HwAddress),
Disconnect(String),
Password(String, String),
Password(String, String, HwAddress),
Forget(String),
Reload,
}
@ -382,7 +390,10 @@ impl NetworkManagerState {
let known_access_points: Vec<_> = wireless_access_points
.iter()
.filter(|a| {
known_ssid.contains(&a.ssid) && !active_conns.iter().any(|ac| ac.name() == a.ssid)
known_ssid.contains(&a.ssid)
&& !active_conns
.iter()
.any(|ac| ac.name() == a.ssid && ac.hw_address() == a.hw_address)
})
.cloned()
.collect();
@ -407,6 +418,7 @@ impl NetworkManagerState {
conn: &Connection,
ssid: &str,
password: Option<&str>,
hw_address: HwAddress,
) -> anyhow::Result<()> {
let nm = NetworkManager::new(conn).await?;
@ -423,7 +435,7 @@ impl NetworkManagerState {
let Some(ap) = self
.wireless_access_points
.iter()
.find(|ap| ap.ssid == ssid)
.find(|ap| ap.ssid == ssid && ap.hw_address == hw_address)
else {
return Err(anyhow::anyhow!("Access point not found"));
};
@ -468,13 +480,19 @@ impl NetworkManagerState {
let settings = c.get_settings().await.ok().unwrap_or_default();
let s = Settings::new(settings);
let cur_hw_address = s
.wifi
.as_ref()
.and_then(|w| w.assigned_mac_address.as_ref())
.and_then(|mac| HwAddress::from_string(&mac));
// s.wifi.clone().
if let Some(cur_ssid) = s
.wifi
.clone()
.and_then(|w| w.ssid)
.and_then(|ssid| String::from_utf8(ssid).ok())
{
if cur_ssid == ssid {
if cur_ssid == ssid && hw_address == cur_hw_address.unwrap_or_default() {
known_conn = Some(c);
break;
}