Skip to content

Commit

Permalink
station: add station get command and dump example
Browse files Browse the repository at this point in the history
  • Loading branch information
AbuShawarib authored and cathay4t committed Mar 14, 2024
1 parent 40cc282 commit 19d03a5
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 1 deletion.
42 changes: 42 additions & 0 deletions examples/dump_nl80211_station.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT

use std::env::args;

use anyhow::{bail, Context, Error};
use futures::stream::TryStreamExt;

fn main() -> Result<(), Error> {
let argv: Vec<_> = args().collect();

if argv.len() < 2 {
eprintln!("Usage: dump_nl80211_station <interface index>");
bail!("Required arguments not given");
}

let err_msg = format!("Invalid interface index value: {}", argv[1]);
let index = argv[1].parse::<u32>().context(err_msg)?;

let rt = tokio::runtime::Builder::new_current_thread()
.enable_io()
.build()
.unwrap();
rt.block_on(dump_station(index));

Ok(())
}

async fn dump_station(if_index: u32) {
let (connection, handle, _) = wl_nl80211::new_connection().unwrap();
tokio::spawn(connection);

let mut sta_handle = handle.station().dump(if_index).execute().await;

let mut msgs = Vec::new();
while let Some(msg) = sta_handle.try_next().await.unwrap() {
msgs.push(msg);
}
assert!(!msgs.is_empty());
for msg in msgs {
println!("{:?}", msg);
}
}
6 changes: 6 additions & 0 deletions src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use netlink_packet_utils::DecodeError;

use crate::{
try_nl80211, Nl80211Error, Nl80211InterfaceHandle, Nl80211Message,
Nl80211StationHandle,
};

#[derive(Clone, Debug)]
Expand All @@ -25,6 +26,11 @@ impl Nl80211Handle {
Nl80211InterfaceHandle::new(self.clone())
}

// equivalent to `iw dev DEVICE station` command
pub fn station(&self) -> Nl80211StationHandle {
Nl80211StationHandle::new(self.clone())
}

pub async fn request(
&mut self,
message: NetlinkMessage<GenlMessage<Nl80211Message>>,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use iface::{
};
pub use message::{Nl80211Cmd, Nl80211Message};
pub use station::{
Nl80211StationInfo,
Nl80211StationGetRequest, Nl80211StationHandle, Nl80211StationInfo,
};
pub use stats::{
NestedNl80211TidStats, Nl80211TidStats, Nl80211TransmitQueueStat,
Expand Down
21 changes: 21 additions & 0 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ use crate::attr::Nl80211Attr;

const NL80211_CMD_GET_INTERFACE: u8 = 5;
const NL80211_CMD_NEW_INTERFACE: u8 = 7;
const NL80211_CMD_GET_STATION: u8 = 17;
const NL80211_CMD_NEW_STATION: u8 = 19;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Nl80211Cmd {
InterfaceGet,
InterfaceNew,
StationGet,
StationNew,
}

impl From<Nl80211Cmd> for u8 {
fn from(cmd: Nl80211Cmd) -> Self {
match cmd {
Nl80211Cmd::InterfaceGet => NL80211_CMD_GET_INTERFACE,
Nl80211Cmd::InterfaceNew => NL80211_CMD_NEW_INTERFACE,
Nl80211Cmd::StationGet => NL80211_CMD_GET_STATION,
Nl80211Cmd::StationNew => NL80211_CMD_NEW_STATION,
}
}
}
Expand Down Expand Up @@ -53,6 +59,13 @@ impl Nl80211Message {
nlas: vec![],
}
}

pub fn new_station_get(nlas: Vec<Nl80211Attr>) -> Self {
Nl80211Message {
cmd: Nl80211Cmd::StationGet,
nlas,
}
}
}

impl Emitable for Nl80211Message {
Expand Down Expand Up @@ -86,6 +99,14 @@ impl ParseableParametrized<[u8], GenlHeader> for Nl80211Message {
cmd: Nl80211Cmd::InterfaceNew,
nlas: parse_nlas(buffer)?,
},
NL80211_CMD_GET_STATION => Self {
cmd: Nl80211Cmd::StationGet,
nlas: parse_nlas(buffer)?,
},
NL80211_CMD_NEW_STATION => Self {
cmd: Nl80211Cmd::StationNew,
nlas: parse_nlas(buffer)?,
},
cmd => {
return Err(DecodeError::from(format!(
"Unsupported nl80211 reply command: {}",
Expand Down
50 changes: 50 additions & 0 deletions src/station/get.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT

use futures::TryStream;
use netlink_packet_generic::GenlMessage;

use crate::{
nl80211_execute, Nl80211Attr, Nl80211Error, Nl80211Handle, Nl80211Message,
};

const ETH_ALEN: usize = 6;

pub struct Nl80211StationGetRequest {
handle: Nl80211Handle,
if_index: u32,
mac_address: Option<[u8; ETH_ALEN]>,
}

impl Nl80211StationGetRequest {
pub(crate) fn new(
handle: Nl80211Handle,
if_index: u32,
mac_address: Option<[u8; ETH_ALEN]>,
) -> Self {
Nl80211StationGetRequest {
handle,
if_index,
mac_address,
}
}

pub async fn execute(
self,
) -> impl TryStream<Ok = GenlMessage<Nl80211Message>, Error = Nl80211Error>
{
let Nl80211StationGetRequest {
mut handle,
if_index,
mac_address,
} = self;

let mut nlas = vec![Nl80211Attr::IfIndex(if_index)];
if let Some(arr) = mac_address {
nlas.push(Nl80211Attr::Mac(arr))
}

let nl80211_msg = Nl80211Message::new_station_get(nlas);

nl80211_execute(&mut handle, nl80211_msg).await
}
}
17 changes: 17 additions & 0 deletions src/station/handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

use crate::{Nl80211Handle, Nl80211StationGetRequest};

pub struct Nl80211StationHandle(Nl80211Handle);

impl Nl80211StationHandle {
pub fn new(handle: Nl80211Handle) -> Self {
Nl80211StationHandle(handle)
}

/// Retrieve the stations
/// (equivalent to `iw dev DEV station dump`)
pub fn dump(&mut self, if_index: u32) -> Nl80211StationGetRequest {
Nl80211StationGetRequest::new(self.0.clone(), if_index, None)
}
}
4 changes: 4 additions & 0 deletions src/station/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// SPDX-License-Identifier: MIT

mod get;
mod handle;
mod rate_info;
mod station_info;

pub use get::Nl80211StationGetRequest;
pub use handle::Nl80211StationHandle;
pub use rate_info::Nl80211RateInfo;
pub use station_info::Nl80211StationInfo;

0 comments on commit 19d03a5

Please sign in to comment.