use std::rc::Rc;
use std::net::Ipv4Addr;
use errors::*;
use dbus_nm::DBusNetworkManager;
use connection::{connect_to_access_point, create_hotspot, Connection, ConnectionState};
use device::{Device, PathGetter};
use ssid::{AsSsidSlice, Ssid, SsidSlice};
pub struct WiFiDevice<'a> {
dbus_manager: Rc<DBusNetworkManager>,
device: &'a Device,
}
impl<'a> WiFiDevice<'a> {
pub fn get_access_points(&self) -> Result<Vec<AccessPoint>> {
let mut access_points = Vec::new();
let paths = self.dbus_manager
.get_device_access_points(self.device.path())?;
for path in paths {
if let Some(access_point) = get_access_point(&self.dbus_manager, &path)? {
access_points.push(access_point);
}
}
access_points.sort_by_key(|ap| ap.strength);
access_points.reverse();
Ok(access_points)
}
pub fn request_scan(&self) -> Result<()> {
self.dbus_manager
.request_access_point_scan(self.device.path())?;
Ok(())
}
pub fn connect(
&self,
access_point: &AccessPoint,
credentials: &AccessPointCredentials,
) -> Result<(Connection, ConnectionState)> {
connect_to_access_point(
&self.dbus_manager,
self.device.path(),
access_point,
credentials,
)
}
pub fn create_hotspot<T>(
&self,
ssid: &T,
password: Option<&str>,
address: Option<Ipv4Addr>,
) -> Result<(Connection, ConnectionState)>
where
T: AsSsidSlice + ?Sized,
{
create_hotspot(
&self.dbus_manager,
self.device.path(),
self.device.interface(),
ssid,
password,
address,
)
}
}
#[derive(Debug)]
pub struct AccessPoint {
pub path: String,
pub ssid: Ssid,
pub strength: u32,
pub security: Security,
}
impl AccessPoint {
pub fn ssid(&self) -> &SsidSlice {
&self.ssid
}
}
bitflags! {
pub struct Security: u32 {
const NONE = 0b0000_0000;
const WEP = 0b0000_0001;
const WPA = 0b0000_0010;
const WPA2 = 0b0000_0100;
const ENTERPRISE = 0b0000_1000;
}
}
#[derive(Debug)]
pub enum AccessPointCredentials {
None,
Wep {
passphrase: String,
},
Wpa {
passphrase: String,
},
Enterprise {
identity: String,
passphrase: String,
},
}
bitflags! {
pub struct NM80211ApFlags: u32 {
const AP_FLAGS_NONE = 0x0000_0000;
const AP_FLAGS_PRIVACY = 0x0000_0001;
const AP_FLAGS_WPS = 0x0000_0002;
const AP_FLAGS_WPS_PBC = 0x0000_0004;
const AP_FLAGS_WPS_PIN = 0x0000_0008;
}
}
bitflags! {
pub struct NM80211ApSecurityFlags: u32 {
const AP_SEC_NONE = 0x0000_0000;
const AP_SEC_PAIR_WEP40 = 0x0000_0001;
const AP_SEC_PAIR_WEP104 = 0x0000_0002;
const AP_SEC_PAIR_TKIP = 0x0000_0004;
const AP_SEC_PAIR_CCMP = 0x0000_0008;
const AP_SEC_GROUP_WEP40 = 0x0000_0010;
const AP_SEC_GROUP_WEP104 = 0x0000_0020;
const AP_SEC_GROUP_TKIP = 0x0000_0040;
const AP_SEC_GROUP_CCMP = 0x0000_0080;
const AP_SEC_KEY_MGMT_PSK = 0x0000_0100;
const AP_SEC_KEY_MGMT_802_1X = 0x0000_0200;
}
}
pub fn new_wifi_device<'a>(
dbus_manager: &Rc<DBusNetworkManager>,
device: &'a Device,
) -> WiFiDevice<'a> {
WiFiDevice {
dbus_manager: Rc::clone(dbus_manager),
device: device,
}
}
fn get_access_point(manager: &DBusNetworkManager, path: &str) -> Result<Option<AccessPoint>> {
if let Some(ssid) = manager.get_access_point_ssid(path) {
let strength = manager.get_access_point_strength(path)?;
let security = get_access_point_security(manager, path)?;
let access_point = AccessPoint {
path: path.to_string(),
ssid: ssid,
strength: strength,
security: security,
};
Ok(Some(access_point))
} else {
Ok(None)
}
}
fn get_access_point_security(manager: &DBusNetworkManager, path: &str) -> Result<Security> {
let flags = manager.get_access_point_flags(path)?;
let wpa_flags = manager.get_access_point_wpa_flags(path)?;
let rsn_flags = manager.get_access_point_rsn_flags(path)?;
let mut security = Security::NONE;
if flags.contains(NM80211ApFlags::AP_FLAGS_PRIVACY)
&& wpa_flags == NM80211ApSecurityFlags::AP_SEC_NONE
&& rsn_flags == NM80211ApSecurityFlags::AP_SEC_NONE
{
security |= Security::WEP;
}
if wpa_flags != NM80211ApSecurityFlags::AP_SEC_NONE {
security |= Security::WPA;
}
if rsn_flags != NM80211ApSecurityFlags::AP_SEC_NONE {
security |= Security::WPA2;
}
if wpa_flags.contains(NM80211ApSecurityFlags::AP_SEC_KEY_MGMT_802_1X)
|| rsn_flags.contains(NM80211ApSecurityFlags::AP_SEC_KEY_MGMT_802_1X)
{
security |= Security::ENTERPRISE;
}
Ok(security)
}