orb_network_manager/
wifi.rs

1use std::rc::Rc;
2use std::net::Ipv4Addr;
3
4use errors::*;
5use dbus_nm::DBusNetworkManager;
6
7use connection::{connect_to_access_point, create_hotspot, Connection, ConnectionState};
8use device::{Device, PathGetter};
9use ssid::{AsSsidSlice, Ssid, SsidSlice};
10
11pub struct WiFiDevice<'a> {
12    dbus_manager: Rc<DBusNetworkManager>,
13    device: &'a Device,
14}
15
16impl<'a> WiFiDevice<'a> {
17    /// Get the list of access points visible to this device.
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use network_manager::{NetworkManager, DeviceType};
23    /// let manager = NetworkManager::new();
24    /// let devices = manager.get_devices().unwrap();
25    /// let i = devices.iter().position(|ref d| *d.device_type() == DeviceType::WiFi).unwrap();
26    /// let device = devices[i].as_wifi_device().unwrap();
27    /// device.request_scan()?;
28    /// let access_points = device.get_access_points().unwrap();
29    /// println!("{:?}", access_points);
30    /// ```
31    pub fn get_access_points(&self) -> Result<Vec<AccessPoint>> {
32        let mut access_points = Vec::new();
33
34        let paths = self.dbus_manager
35            .get_device_access_points(self.device.path())?;
36
37        for path in paths {
38            if let Some(access_point) = get_access_point(&self.dbus_manager, &path)? {
39                access_points.push(access_point);
40            }
41        }
42
43        access_points.sort_by_key(|ap| ap.strength);
44        access_points.reverse();
45
46        Ok(access_points)
47    }
48
49    pub fn request_scan(&self) -> Result<()> {
50        self.dbus_manager
51            .request_access_point_scan(self.device.path())?;
52        Ok(())
53    }
54
55    pub fn connect(
56        &self,
57        access_point: &AccessPoint,
58        credentials: &AccessPointCredentials,
59    ) -> Result<(Connection, ConnectionState)> {
60        connect_to_access_point(
61            &self.dbus_manager,
62            self.device.path(),
63            access_point,
64            credentials,
65        )
66    }
67
68    pub fn create_hotspot<T>(
69        &self,
70        ssid: &T,
71        password: Option<&str>,
72        address: Option<Ipv4Addr>,
73    ) -> Result<(Connection, ConnectionState)>
74    where
75        T: AsSsidSlice + ?Sized,
76    {
77        create_hotspot(
78            &self.dbus_manager,
79            self.device.path(),
80            self.device.interface(),
81            ssid,
82            password,
83            address,
84        )
85    }
86}
87
88#[derive(Debug)]
89pub struct AccessPoint {
90    pub path: String,
91    pub ssid: Ssid,
92    pub strength: u32,
93    pub security: Security,
94}
95
96impl AccessPoint {
97    pub fn ssid(&self) -> &SsidSlice {
98        &self.ssid
99    }
100}
101
102bitflags! {
103    pub struct Security: u32 {
104        const NONE         = 0b0000_0000;
105        const WEP          = 0b0000_0001;
106        const WPA          = 0b0000_0010;
107        const WPA2         = 0b0000_0100;
108        const ENTERPRISE   = 0b0000_1000;
109    }
110}
111
112#[derive(Debug)]
113pub enum AccessPointCredentials {
114    None,
115    Wep {
116        passphrase: String,
117    },
118    Wpa {
119        passphrase: String,
120    },
121    Enterprise {
122        identity: String,
123        passphrase: String,
124    },
125}
126
127bitflags! {
128    pub struct NM80211ApFlags: u32 {
129        // access point has no special capabilities
130        const AP_FLAGS_NONE                  = 0x0000_0000;
131        // access point requires authentication and encryption (usually means WEP)
132        const AP_FLAGS_PRIVACY               = 0x0000_0001;
133        // access point supports some WPS method
134        const AP_FLAGS_WPS                   = 0x0000_0002;
135        // access point supports push-button WPS
136        const AP_FLAGS_WPS_PBC               = 0x0000_0004;
137        // access point supports PIN-based WPS
138        const AP_FLAGS_WPS_PIN               = 0x0000_0008;
139    }
140}
141
142bitflags! {
143    pub struct NM80211ApSecurityFlags: u32 {
144         // the access point has no special security requirements
145        const AP_SEC_NONE                    = 0x0000_0000;
146        // 40/64-bit WEP is supported for pairwise/unicast encryption
147        const AP_SEC_PAIR_WEP40              = 0x0000_0001;
148        // 104/128-bit WEP is supported for pairwise/unicast encryption
149        const AP_SEC_PAIR_WEP104             = 0x0000_0002;
150        // TKIP is supported for pairwise/unicast encryption
151        const AP_SEC_PAIR_TKIP               = 0x0000_0004;
152        // AES/CCMP is supported for pairwise/unicast encryption
153        const AP_SEC_PAIR_CCMP               = 0x0000_0008;
154        // 40/64-bit WEP is supported for group/broadcast encryption
155        const AP_SEC_GROUP_WEP40             = 0x0000_0010;
156        // 104/128-bit WEP is supported for group/broadcast encryption
157        const AP_SEC_GROUP_WEP104            = 0x0000_0020;
158        // TKIP is supported for group/broadcast encryption
159        const AP_SEC_GROUP_TKIP              = 0x0000_0040;
160        // AES/CCMP is supported for group/broadcast encryption
161        const AP_SEC_GROUP_CCMP              = 0x0000_0080;
162        // WPA/RSN Pre-Shared Key encryption is supported
163        const AP_SEC_KEY_MGMT_PSK            = 0x0000_0100;
164        // 802.1x authentication and key management is supported
165        const AP_SEC_KEY_MGMT_802_1X         = 0x0000_0200;
166    }
167}
168
169pub fn new_wifi_device<'a>(
170    dbus_manager: &Rc<DBusNetworkManager>,
171    device: &'a Device,
172) -> WiFiDevice<'a> {
173    WiFiDevice {
174        dbus_manager: Rc::clone(dbus_manager),
175        device: device,
176    }
177}
178
179fn get_access_point(manager: &DBusNetworkManager, path: &str) -> Result<Option<AccessPoint>> {
180    if let Some(ssid) = manager.get_access_point_ssid(path) {
181        let strength = manager.get_access_point_strength(path)?;
182
183        let security = get_access_point_security(manager, path)?;
184
185        let access_point = AccessPoint {
186            path: path.to_string(),
187            ssid: ssid,
188            strength: strength,
189            security: security,
190        };
191
192        Ok(Some(access_point))
193    } else {
194        Ok(None)
195    }
196}
197
198fn get_access_point_security(manager: &DBusNetworkManager, path: &str) -> Result<Security> {
199    let flags = manager.get_access_point_flags(path)?;
200
201    let wpa_flags = manager.get_access_point_wpa_flags(path)?;
202
203    let rsn_flags = manager.get_access_point_rsn_flags(path)?;
204
205    let mut security = Security::NONE;
206
207    if flags.contains(NM80211ApFlags::AP_FLAGS_PRIVACY)
208        && wpa_flags == NM80211ApSecurityFlags::AP_SEC_NONE
209        && rsn_flags == NM80211ApSecurityFlags::AP_SEC_NONE
210    {
211        security |= Security::WEP;
212    }
213
214    if wpa_flags != NM80211ApSecurityFlags::AP_SEC_NONE {
215        security |= Security::WPA;
216    }
217
218    if rsn_flags != NM80211ApSecurityFlags::AP_SEC_NONE {
219        security |= Security::WPA2;
220    }
221
222    if wpa_flags.contains(NM80211ApSecurityFlags::AP_SEC_KEY_MGMT_802_1X)
223        || rsn_flags.contains(NM80211ApSecurityFlags::AP_SEC_KEY_MGMT_802_1X)
224    {
225        security |= Security::ENTERPRISE;
226    }
227
228    Ok(security)
229}