use std::{error::Error, iter::once};
#[cfg(feature = "async")]
use neli::router::asynchronous::NlRouter;
#[cfg(not(feature = "async"))]
use neli::router::synchronous::NlRouter;
use neli::{
attr::Attribute,
consts::{
nl::{GenlId, NlmF},
socket::NlFamily,
},
genl::{AttrTypeBuilder, NlattrBuilder},
genl::{Genlmsghdr, GenlmsghdrBuilder, NoUserHeader},
nl::{NlPayload, Nlmsghdr},
types::GenlBuffer,
utils::Groups,
};
#[neli::neli_enum(serialized_type = "u8")]
pub enum Nl80211Command {
Unspecified = 0,
GetWiPhy = 1,
GetInterface = 5,
}
impl neli::consts::genl::Cmd for Nl80211Command {}
#[neli::neli_enum(serialized_type = "u16")]
pub enum Nl80211Attribute {
Unspecified = 0,
Wiphy = 1,
WiphyName = 2,
Ifname = 4,
Iftype = 5,
Ssid = 52,
Wdev = 153,
}
impl neli::consts::genl::NlAttrType for Nl80211Attribute {}
#[neli::neli_enum(serialized_type = "u32")]
pub enum Nl80211IfType {
Unspecified = 0,
Station = 2,
Ap = 3,
Monitor = 6,
P2pDevice = 10,
}
fn handle(msg: Nlmsghdr<GenlId, Genlmsghdr<Nl80211Command, Nl80211Attribute>>) {
let payload = match msg.nl_payload() {
NlPayload::Payload(p) => p,
_ => return,
};
let attr_handle = payload.attrs().get_attr_handle();
for attr in attr_handle.iter() {
match attr.nla_type().nla_type() {
Nl80211Attribute::Wiphy => {
let wiphy = attr.get_payload_as::<u32>().unwrap();
println!("{:<12}{}", "Wiphy:", wiphy);
}
Nl80211Attribute::WiphyName => {
let wiphy_name = attr.get_payload_as_with_len::<String>().unwrap();
println!("{:<12}{}", "WiphyName:", wiphy_name);
}
Nl80211Attribute::Ifname => {
let ifname = attr.get_payload_as_with_len::<String>().unwrap();
println!("{:<12}{}", "Ifname:", ifname);
}
Nl80211Attribute::Iftype => {
let iftype = attr.get_payload_as::<Nl80211IfType>().unwrap();
println!("{:<12}{:?}", "Iftype:", iftype);
}
Nl80211Attribute::Wdev => {
let wdev = attr.get_payload_as::<u64>().unwrap();
println!("{:<12}0x{:09x}", "Wdev:", wdev);
}
Nl80211Attribute::Ssid => {
let ssid: &[u8] = attr.get_payload_as_with_len_borrowed().unwrap();
println!("{:<12}{}", "Ssid:", std::str::from_utf8(ssid).unwrap());
}
_ => (),
}
}
}
#[cfg(feature = "async")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let (sock, _) = NlRouter::connect(
NlFamily::Generic,
Some(0),
Groups::empty(),
)
.await?;
let family_id = sock.resolve_genl_family("nl80211").await?;
let mut recv = sock
.send::<_, _, u16, Genlmsghdr<Nl80211Command, Nl80211Attribute>>(
family_id,
NlmF::DUMP | NlmF::ACK,
NlPayload::Payload(
GenlmsghdrBuilder::<Nl80211Command, Nl80211Attribute, NoUserHeader>::default()
.cmd(Nl80211Command::GetWiPhy)
.version(1)
.build()?,
),
)
.await?;
println!("WiFi radios:");
while let Some(Ok(msg)) = recv.next().await {
handle(msg);
println!();
}
let attrs = once(
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(Nl80211Attribute::Ifname)
.build()
.unwrap(),
)
.nla_payload(())
.build()
.unwrap(),
)
.collect::<GenlBuffer<_, _>>();
let mut recv = sock
.send::<_, _, u16, Genlmsghdr<Nl80211Command, Nl80211Attribute>>(
family_id,
NlmF::DUMP | NlmF::ACK,
NlPayload::Payload(
GenlmsghdrBuilder::<Nl80211Command, Nl80211Attribute, NoUserHeader>::default()
.cmd(Nl80211Command::GetInterface)
.attrs(attrs)
.version(1)
.build()?,
),
)
.await?;
println!("WiFi interfaces:");
while let Some(Ok(msg)) = recv.next().await {
handle(msg);
println!();
}
Ok(())
}
#[cfg(not(feature = "async"))]
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let (sock, _) = NlRouter::connect(
NlFamily::Generic,
Some(0),
Groups::empty(),
)?;
let family_id = sock.resolve_genl_family("nl80211")?;
let recv = sock.send(
family_id,
NlmF::DUMP | NlmF::ACK,
NlPayload::Payload(
GenlmsghdrBuilder::<Nl80211Command, Nl80211Attribute, NoUserHeader>::default()
.cmd(Nl80211Command::GetWiPhy)
.version(1)
.build()?,
),
)?;
println!("WiFi radios:");
for msg in recv {
let msg = msg?;
handle(msg);
println!();
}
let attrs = once(
NlattrBuilder::default()
.nla_type(
AttrTypeBuilder::default()
.nla_type(Nl80211Attribute::Ifname)
.build()
.unwrap(),
)
.nla_payload(())
.build()
.unwrap(),
)
.collect::<GenlBuffer<_, _>>();
let recv = sock.send(
family_id,
NlmF::DUMP | NlmF::ACK,
NlPayload::Payload(
GenlmsghdrBuilder::<Nl80211Command, Nl80211Attribute, NoUserHeader>::default()
.cmd(Nl80211Command::GetInterface)
.attrs(attrs)
.version(1)
.build()?,
),
)?;
println!("WiFi interfaces:");
for msg in recv {
let msg = msg?;
handle(msg);
println!();
}
Ok(())
}