Commit b610d10c authored by Max Verevkin's avatar Max Verevkin
Browse files

rewrite with neli 0.6

parent c4542687
......@@ -2,15 +2,12 @@
name = "nl80211"
version = "0.0.2"
authors = ["eonm <eon.mathis@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
description = "Send commands to nl80211 and receive messages"
homepage = "https://github.com/Eonm/nl80211"
repository = "https://github.com/Eonm/nl80211"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
buffering = { version = "0.3.2", features = ["copy"] }
neli = "0.4.3-r1"
hex = "0.4.0"
neli = "0.6.0"
neli-proc-macros = "0.1.0"
//! Pretty print host interfaces.
use nl80211::Socket;
use std::error::Error;
fn main() -> Result<(), neli::err::NlError> {
let interfaces = Socket::connect()?.get_interfaces_info()?;
fn main() -> Result<(), Box<dyn Error>> {
let mut socket = Socket::connect()?;
for interface in interfaces {
println!("{}\n", interface);
for interface in socket.get_interfaces_info()? {
dbg!(&interface);
if let Some(index) = &interface.index {
dbg!(socket.get_station_info(index)?);
dbg!(socket.get_bss_info(index)?);
}
eprintln!("---");
}
Ok(())
......
This diff is collapsed.
use std::fmt;
use crate::attr::Nl80211Attr;
use crate::attr::Nl80211Bss;
use crate::nl80211traits::ParseNlAttr;
use crate::parse_attr::{parse_hex, parse_i32, parse_u16, parse_u32};
use neli::nlattr::AttrHandle;
use crate::attr::{Attrs, Nl80211Attr, Nl80211Bss};
use neli::attr::Attribute;
use neli::err::DeError;
/// A struct representing a BSS (Basic Service Set)
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Bss {
/// BSSID
pub bssid: Option<Vec<u8>>,
/// Frequency in MHz (u32)
pub frequency: Option<Vec<u8>>,
/// Beacon interval of the (I)BSS (u16)
pub beacon_interval: Option<Vec<u8>>,
/// Age of this BSS entry in ms (u32)
pub seen_ms_ago: Option<Vec<u8>>,
/// Status, if this BSS is "used" (u8)
pub status: Option<Vec<u8>>,
/// Signal strength of probe response/beacon in mBm (100 * dBm) (i32)
pub signal: Option<Vec<u8>>,
}
impl Bss {
pub fn default() -> Bss {
Bss {
bssid: None,
frequency: None,
beacon_interval: None,
seen_ms_ago: None,
status: None,
signal: None,
}
}
}
impl fmt::Display for Bss {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut result = Vec::new();
if let Some(bssid) = &self.bssid {
result.push(format!("bssid : {}", parse_hex(bssid)))
};
if let Some(frequency) = &self.frequency {
result.push(format!(
"frequency : {} Ghz",
parse_u32(frequency) as f32 / 1000.00
))
};
if let Some(beacon_interval) = &self.beacon_interval {
result.push(format!(
"beacon interval : {} TUs",
parse_u16(beacon_interval)
))
};
if let Some(seen_ms_ago) = &self.seen_ms_ago {
result.push(format!("last seen : {} ms", parse_u32(seen_ms_ago)))
};
if let Some(status) = &self.status {
result.push(format!("status : {}", parse_u32(status)))
};
if let Some(signal) = &self.signal {
result.push(format!(
"signal : {:?} dBm",
parse_i32(signal) as f32 / 100.00
))
};
write!(f, "{}", result.join("\n"))
}
/// Frequency in MHz
pub frequency: Option<u32>,
/// Beacon interval of the (I)BSS
pub beacon_interval: Option<u16>,
/// Age of this BSS entry in ms
pub seen_ms_ago: Option<u32>,
/// Status, if this BSS is "used"
pub status: Option<u32>,
/// Signal strength of probe response/beacon in mBm (100 * dBm)
pub signal: Option<i32>,
}
impl ParseNlAttr for Bss {
/// Parse netlink messages returned by the nl80211 command CmdGetScan
fn parse(&mut self, handle: AttrHandle<Nl80211Attr>) -> Bss {
for attr in handle.iter() {
println!("{:?}", attr);
match attr.nla_type {
Nl80211Attr::AttrBss => {
let sub_handle = attr.get_nested_attributes::<Nl80211Bss>().unwrap();
for sub_attr in sub_handle.iter() {
match sub_attr.nla_type {
Nl80211Bss::BssBeaconInterval => {
self.beacon_interval = Some(sub_attr.payload.clone())
}
Nl80211Bss::BssFrequency => {
self.frequency = Some(sub_attr.payload.clone())
}
Nl80211Bss::BssSeenMsAgo => {
self.seen_ms_ago = Some(sub_attr.payload.clone())
}
Nl80211Bss::BssStatus => self.status = Some(sub_attr.payload.clone()),
Nl80211Bss::BssBssid => self.bssid = Some(sub_attr.payload.clone()),
Nl80211Bss::BssSignalMbm => {
self.signal = Some(sub_attr.payload.clone())
}
_ => (),
}
impl TryFrom<Attrs<'_, Nl80211Attr>> for Bss {
type Error = DeError;
fn try_from(attrs: Attrs<'_, Nl80211Attr>) -> Result<Self, Self::Error> {
let mut res = Self::default();
if let Some(bss) = attrs.get_attribute(Nl80211Attr::AttrBss) {
let attrs = bss.get_attr_handle::<Nl80211Bss>()?;
for attr in attrs.iter() {
match attr.nla_type.nla_type {
Nl80211Bss::BssBssid => {
res.bssid = Some(attr.get_payload_as_with_len()?);
}
Nl80211Bss::BssFrequency => {
res.frequency = Some(attr.get_payload_as()?);
}
Nl80211Bss::BssBeaconInterval => {
res.beacon_interval = Some(attr.get_payload_as()?);
}
Nl80211Bss::BssSeenMsAgo => {
res.seen_ms_ago = Some(attr.get_payload_as()?);
}
Nl80211Bss::BssStatus => {
res.status = Some(attr.get_payload_as()?);
}
Nl80211Bss::BssSignalMbm => {
res.signal = Some(attr.get_payload_as()?);
}
_ => (),
}
_ => (),
}
}
self.to_owned()
Ok(res)
}
}
......@@ -114,54 +59,31 @@ impl ParseNlAttr for Bss {
mod test_bss {
use super::*;
use crate::attr::Nl80211Attr::*;
use neli::nlattr::Nlattr;
#[test]
fn test_pretty_format() {
let bss = Bss {
bssid: Some(vec![255, 255, 255, 255, 255, 255]),
frequency: Some(vec![108, 9, 0, 0]),
beacon_interval: Some(vec![100, 0]),
seen_ms_ago: Some(vec![100, 0, 0, 0]),
status: Some(vec![1, 0, 0, 0]),
signal: Some(vec![76, 235, 255, 255]),
};
let expected_output = r#"bssid : FF:FF:FF:FF:FF:FF
frequency : 2.412 Ghz
beacon interval : 100 TUs
last seen : 100 ms
status : 1
signal : -53.0 dBm"#;
assert_eq!(
format!("{}", bss),
expected_output.replace("\n ", "\n")
)
use neli::attr::AttrHandle;
use neli::genl::{AttrType, Nlattr};
use neli::types::Buffer;
fn new_attr(t: Nl80211Attr, d: Vec<u8>) -> Nlattr<Nl80211Attr, Buffer> {
Nlattr {
nla_len: (4 + d.len()) as _,
nla_type: AttrType {
nla_nested: false,
nla_network_order: true,
nla_type: t,
},
nla_payload: d.into(),
}
}
#[test]
fn test_parse() {
let handler = vec![
Nlattr {
nla_len: 8,
nla_type: AttrGeneration,
payload: vec![28, 4, 0, 0],
},
Nlattr {
nla_len: 8,
nla_type: AttrIfindex,
payload: vec![3, 0, 0, 0],
},
Nlattr {
nla_len: 12,
nla_type: AttrWdev,
payload: vec![1, 0, 0, 0, 0, 0, 0, 0],
},
Nlattr {
nla_len: 728,
nla_type: AttrBss,
payload: vec![
new_attr(AttrGeneration, vec![28, 4, 0, 0]),
new_attr(AttrIfindex, vec![3, 0, 0, 0]),
new_attr(AttrWdev, vec![1, 0, 0, 0, 0, 0, 0, 0]),
new_attr(
AttrBss,
vec![
10, 0, 1, 0, 255, 255, 255, 255, 255, 255, 0, 0, 4, 0, 14, 0, 12, 0, 3, 0, 132,
12, 93, 163, 39, 0, 0, 0, 95, 1, 6, 0, 0, 8, 83, 70, 82, 45, 49, 99, 50, 56, 1,
8, 130, 132, 139, 150, 36, 48, 72, 108, 3, 1, 1, 7, 6, 68, 69, 32, 1, 13, 20,
......@@ -197,17 +119,19 @@ mod test_bss {
12, 0, 0, 0, 0, 0, 8, 0, 10, 0, 100, 0, 0, 0, 8, 0, 7, 0, 76, 235, 255, 255, 8,
0, 9, 0, 1, 0, 0, 0,
],
},
),
];
let bss = Bss::default().parse(neli::nlattr::AttrHandle::Owned(handler));
let bss: Bss = AttrHandle::new(handler.into_iter().collect())
.try_into()
.unwrap();
let expected_bss = Bss {
bssid: Some(vec![255, 255, 255, 255, 255, 255]),
frequency: Some(vec![108, 9, 0, 0]),
beacon_interval: Some(vec![100, 0]),
seen_ms_ago: Some(vec![100, 0, 0, 0]),
status: Some(vec![1, 0, 0, 0]),
signal: Some(vec![76, 235, 255, 255]),
frequency: Some(u32::from_le_bytes([108, 9, 0, 0])),
beacon_interval: Some(u16::from_le_bytes([100, 0])),
seen_ms_ago: Some(u32::from_le_bytes([100, 0, 0, 0])),
status: Some(u32::from_le_bytes([1, 0, 0, 0])),
signal: Some(i32::from_le_bytes([76, 235, 255, 255])),
};
assert_eq!(bss, expected_bss)
......
use neli::consts::Cmd;
use neli::{impl_var, impl_var_base, impl_var_trait};
use neli::consts::genl::Cmd;
use neli_proc_macros::neli_enum;
// https://github.com/mdlayher/wifi/blob/b1436901ddee2ea3ee8782a440a084e457615766/internal/nl80211/const.go
impl_var_trait!(
/// nl80211Commands
///
/// Enumeration from nl80211/nl80211.h:880
Nl80211Cmd, u8, Cmd,
CmdUnspec => 0,
CmdGetWiphy => 1,
CmdSetWiphy => 2,
CmdNewWiphy => 3,
CmdDelWiphy => 4,
CmdGetInterface => 5,
CmdSetInterface => 6,
CmdNewInterface => 7,
CmdDelInterface => 8,
CmdGetKey => 9,
CmdSetKey => 10,
CmdNewKey => 11,
CmdDelKey => 12,
CmdGetBeacon => 13,
CmdSetBeacon => 14,
CmdStartAp => 15,
CmdNewBeacon => 15,//CmdStartAp,
CmdStopAp => 16,
CmdDelBeacon => 16,//CmdStopAp,
CmdGetStation => 17,
CmdSetStation => 18,
CmdNewStation => 19,
CmdDelStation => 20,
CmdGetMpath => 21,
CmdSetMpath => 22,
CmdNewMpath => 23,
CmdDelMpath => 24,
CmdSetBss => 25,
CmdSetReg => 26,
CmdReqSetReg => 27,
CmdGetMeshConfig => 28,
CmdSetMeshConfig => 29,
CmdSetMgmtExtraIe => 30,
CmdGetReg => 31,
CmdGetScan => 32,
CmdTriggerScan => 33,
CmdNewScanResults => 34,
CmdScanAborted => 35,
CmdRegChange => 36,
CmdAuthenticate => 37,
CmdAssociate => 38,
CmdDeauthenticate => 39,
CmdDisassociate => 40,
CmdMichaelMicFailure => 41,
CmdRegBeaconHint => 42,
CmdJoinIbss => 43,
CmdLeaveIbss => 44,
CmdTestmode => 45,
CmdConnect => 46,
CmdRoam => 47,
CmdDisconnect => 48,
CmdSetWiphyNetns => 49,
CmdGetSurvey => 50,
CmdNewSurveyResults => 51,
CmdSetPmksa => 52,
CmdDelPmksa => 53,
CmdFlushPmksa => 54,
CmdRemainOnChannel => 55,
CmdCancelRemainOnChannel => 56,
CmdSetTxBitrateMask => 57,
CmdRegisterFrame => 58,
CmdRegisterAction => 58,//CmdRegisterFrame,
CmdFrame => 59,
CmdAction => 59,//CmdFrame,
CmdFrameTxStatus => 60,
CmdActionTxStatus => 60,//CmdFrameTxStatus,
CmdSetPowerSave => 61,
CmdGetPowerSave => 62,
CmdSetCqm => 63,
CmdNotifyCqm => 64,
CmdSetChannel => 65,
CmdSetWdsPeer => 66,
CmdFrameWaitCancel => 67,
CmdJoinMesh => 68,
CmdLeaveMesh => 69,
CmdUnprotDeauthenticate => 70,
CmdUnprotDisassociate => 71,
CmdNewPeerCandidate => 72,
CmdGetWowlan => 73,
CmdSetWowlan => 74,
CmdStartSchedScan => 75,
CmdStopSchedScan => 76,
CmdSchedScanResults => 77,
CmdSchedScanStopped => 78,
CmdSetRekeyOffload => 79,
CmdPmksaCandidate => 80,
CmdTdlsOper => 81,
CmdTdlsMgmt => 82,
CmdUnexpectedFrame => 83,
CmdProbeClient => 84,
CmdRegisterBeacons => 85,
CmdUnexpected4addrFrame => 86,
CmdSetNoackMap => 87,
CmdChSwitchNotify => 88,
CmdStartP2pDevice => 89,
CmdStopP2pDevice => 90,
CmdConnFailed => 91,
CmdSetMcastRate => 92,
CmdSetMacAcl => 93,
CmdRadarDetect => 94,
CmdGetProtocolFeatures => 95,
CmdUpdateFtIes => 96,
CmdFtEvent => 97,
CmdCritProtocolStart => 98,
CmdCritProtocolStop => 99,
CmdGetCoalesce => 100,
CmdSetCoalesce => 101,
CmdChannelSwitch => 102,
CmdVendor => 103,
CmdSetQosMap => 104,
CmdAddTxTs => 105,
CmdDelTxTs => 106,
CmdGetMpp => 107,
CmdJoinOcb => 108,
CmdLeaveOcb => 109,
CmdChSwitchStartedNotify => 110,
CmdTdlsChannelSwitch => 111,
CmdTdlsCancelChannelSwitch => 112,
CmdWiphyRegChange => 113,
CmdAbortScan => 114,
CmdStartNan => 115,
CmdStopNan => 116,
CmdAddNanFunction => 117,
CmdDelNanFunction => 118,
CmdChangeNanConfig => 119,
CmdNanMatch => 120,
CmdAfterLast => 121,
CmdMax => 120
);
/// nl80211Commands
///
/// https://github.com/mdlayher/wifi/blob/b1436901ddee2ea3ee8782a440a084e457615766/internal/nl80211/const.go
///
/// Enumeration from nl80211/nl80211.h:880
#[neli_enum(serialized_type = "u8")]
pub enum Nl80211Cmd {
CmdUnspec = 0,
CmdGetWiphy = 1,
CmdSetWiphy = 2,
CmdNewWiphy = 3,
CmdDelWiphy = 4,
CmdGetInterface = 5,
CmdSetInterface = 6,
CmdNewInterface = 7,
CmdDelInterface = 8,
CmdGetKey = 9,
CmdSetKey = 10,
CmdNewKey = 11,
CmdDelKey = 12,
CmdGetBeacon = 13,
CmdSetBeacon = 14,
CmdStartAp = 15,
CmdNewBeacon = 15, //CmdStartAp,
CmdStopAp = 16,
CmdDelBeacon = 16, //CmdStopAp,
CmdGetStation = 17,
CmdSetStation = 18,
CmdNewStation = 19,
CmdDelStation = 20,
CmdGetMpath = 21,
CmdSetMpath = 22,
CmdNewMpath = 23,
CmdDelMpath = 24,
CmdSetBss = 25,
CmdSetReg = 26,
CmdReqSetReg = 27,
CmdGetMeshConfig = 28,
CmdSetMeshConfig = 29,
CmdSetMgmtExtraIe = 30,
CmdGetReg = 31,
CmdGetScan = 32,
CmdTriggerScan = 33,
CmdNewScanResults = 34,
CmdScanAborted = 35,
CmdRegChange = 36,
CmdAuthenticate = 37,
CmdAssociate = 38,
CmdDeauthenticate = 39,
CmdDisassociate = 40,
CmdMichaelMicFailure = 41,
CmdRegBeaconHint = 42,
CmdJoinIbss = 43,
CmdLeaveIbss = 44,
CmdTestmode = 45,
CmdConnect = 46,
CmdRoam = 47,
CmdDisconnect = 48,
CmdSetWiphyNetns = 49,
CmdGetSurvey = 50,
CmdNewSurveyResults = 51,
CmdSetPmksa = 52,
CmdDelPmksa = 53,
CmdFlushPmksa = 54,
CmdRemainOnChannel = 55,
CmdCancelRemainOnChannel = 56,
CmdSetTxBitrateMask = 57,
CmdRegisterFrame = 58,
CmdRegisterAction = 58, //CmdRegisterFrame,
CmdFrame = 59,
CmdAction = 59, //CmdFrame,
CmdFrameTxStatus = 60,
CmdActionTxStatus = 60, //CmdFrameTxStatus,
CmdSetPowerSave = 61,
CmdGetPowerSave = 62,
CmdSetCqm = 63,
CmdNotifyCqm = 64,
CmdSetChannel = 65,
CmdSetWdsPeer = 66,
CmdFrameWaitCancel = 67,
CmdJoinMesh = 68,
CmdLeaveMesh = 69,
CmdUnprotDeauthenticate = 70,
CmdUnprotDisassociate = 71,
CmdNewPeerCandidate = 72,
CmdGetWowlan = 73,
CmdSetWowlan = 74,
CmdStartSchedScan = 75,
CmdStopSchedScan = 76,
CmdSchedScanResults = 77,
CmdSchedScanStopped = 78,
CmdSetRekeyOffload = 79,
CmdPmksaCandidate = 80,
CmdTdlsOper = 81,
CmdTdlsMgmt = 82,
CmdUnexpectedFrame = 83,
CmdProbeClient = 84,
CmdRegisterBeacons = 85,
CmdUnexpected4addrFrame = 86,
CmdSetNoackMap = 87,
CmdChSwitchNotify = 88,
CmdStartP2pDevice = 89,
CmdStopP2pDevice = 90,
CmdConnFailed = 91,
CmdSetMcastRate = 92,
CmdSetMacAcl = 93,
CmdRadarDetect = 94,
CmdGetProtocolFeatures = 95,
CmdUpdateFtIes = 96,
CmdFtEvent = 97,
CmdCritProtocolStart = 98,
CmdCritProtocolStop = 99,
CmdGetCoalesce = 100,
CmdSetCoalesce = 101,
CmdChannelSwitch = 102,
CmdVendor = 103,
CmdSetQosMap = 104,
CmdAddTxTs = 105,
CmdDelTxTs = 106,
CmdGetMpp = 107,
CmdJoinOcb = 108,
CmdLeaveOcb = 109,
CmdChSwitchStartedNotify = 110,
CmdTdlsChannelSwitch = 111,
CmdTdlsCancelChannelSwitch = 112,
CmdWiphyRegChange = 113,
CmdAbortScan = 114,
CmdStartNan = 115,
CmdStopNan = 116,
CmdAddNanFunction = 117,
CmdDelNanFunction = 118,
CmdChangeNanConfig = 119,
CmdNanMatch = 120,
CmdAfterLast = 121,
CmdMax = 120,
}
impl Cmd for Nl80211Cmd {}
pub const NL_80211_GENL_NAME: &str = "nl80211";
pub const NL_80211_GENL_VERSION: u8 = 1;
use std::fmt;
use crate::attr::*;
use crate::nl80211traits::ParseNlAttr;
use crate::parse_attr::parse_u32;
use crate::parse_attr::parse_u64;
use crate::socket::Socket;
use crate::station::Station;
use neli::nlattr::AttrHandle;
use crate::attr::{Attrs, Nl80211Attr};
use crate::parse_attr::{parse_hex, parse_string};
use neli::attr::Attribute;
use neli::err::DeError;
/// A struct representing a wifi interface
#[derive(Clone, Debug, PartialEq)]
......@@ -20,16 +14,16 @@ pub struct Interface {
pub mac: Option<Vec<u8>>,
/// Interface name (u8, String)
pub name: Option<Vec<u8>>,
/// Interface frequency of the selected channel (u32, MHz)
pub frequency: Option<Vec<u8>>,
/// Interface frequency of the selected channel (MHz)
pub frequency: Option<u32>,
/// Interface chanel
pub channel: Option<Vec<u8>>,
pub channel: Option<u32>,
/// Interface transmit power level in signed mBm units.