1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use iwlib_sys::*;
use std::ffi::CStr;
use std::ffi::CString;

/// Represents wireless information for a particular ESSID
#[derive(PartialEq, PartialOrd, Debug)]
pub struct WirelessInfo {
    /// ESSID  identifying the name of the wireless network
    pub wi_essid: String,
    /// Quality of the wireless network
    pub wi_quality: u8,
}

/// Get current active `WirelessInfo` for the `interface`.
///
/// # Arguments
///
/// * `interface` - String representing the name name of the network
/// interface for your wireless hardware. In Linux systems, you can
/// find that out using `iw dev` command.
///
/// # Examples
///
/// ```
/// use iwlib::*;
/// let wireless_info = get_wireless_info("wlan0".to_string());
/// ```
pub fn get_wireless_info(interface: String) -> Option<WirelessInfo> {
    let interface_name = CString::new(interface).unwrap();
    let mut config: wireless_config = Default::default();
    let mut statistics: iw_statistics = Default::default();
    let mut range: iw_range = Default::default();
    let handle = unsafe { iw_sockets_open() };
    let basic_config_status =
        unsafe { iw_get_basic_config(handle, interface_name.as_ptr(), &mut config) };
    if basic_config_status < 0 {
        unsafe {
            libc::close(handle);
        }
        return None;
    }
    let stats_status =
        unsafe { iw_get_stats(handle, interface_name.as_ptr(), &mut statistics, &range, 1) };
    let range_status = unsafe { iw_get_range_info(handle, interface_name.as_ptr(), &mut range) };
    unsafe {
        libc::close(handle);
    }
    let mut quality: f64 = 0.0;
    if stats_status >= 0 && range_status >= 0 {
        let stats_quality = get_quality(statistics.qual);
        let range_quality = get_quality(range.max_qual);
        if range_quality != 0 {
            quality = stats_quality as f64 / range_quality as f64;
        }
    }
    match compute_essid(config) {
        None => None,
        Some(essid) => Some(WirelessInfo {
            wi_essid: essid,
            wi_quality: (quality * 100.0) as u8,
        }),
    }
}

fn compute_essid(wconfig: wireless_config) -> Option<String> {
    if wconfig.has_essid != 0 && wconfig.essid_on != 0 {
        let essid = unsafe { CStr::from_ptr(wconfig.essid.as_ptr()) };
        return Some(essid.to_owned().into_string().unwrap());
    }
    None
}

fn get_quality(config: iw_quality) -> u8 {
    config.qual
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_does_not_crash() {
        let wireless_info = get_wireless_info("wlp0s20f3".to_string());
        println!("Wireless info: {:?}", wireless_info);
    }
}