use std::iter::once; use neli::{ consts::{ nl::{GenlId, NlmF}, socket::NlFamily, }, err::RouterError, genl::{AttrTypeBuilder, Genlmsghdr, GenlmsghdrBuilder, NlattrBuilder, NoUserHeader}, nl::{NlPayload, Nlmsghdr}, router::synchronous::NlRouter, types::GenlBuffer, utils::Groups, }; #[neli::neli_enum(serialized_type = "u8")] pub enum Nl80211Command { GetInterface = 5, /* Others elided */ } impl neli::consts::genl::Cmd for Nl80211Command {} #[neli::neli_enum(serialized_type = "u16")] pub enum Nl80211Attribute { Mac = 6, /* Attributes Elided */ } impl neli::consts::genl::NlAttrType for Nl80211Attribute {} #[neli::neli_enum(serialized_type = "u16")] pub enum ExtAckAttr { Unused = 0, Msg = 1, Offs = 2, Cookie = 3, Policy = 4, } impl neli::consts::genl::NlAttrType for ExtAckAttr {} fn main() -> Result<(), Box> { env_logger::init(); let (sock, _) = NlRouter::connect( NlFamily::Generic, /* family */ None, /* pid */ Groups::empty(), /* groups */ )?; sock.enable_ext_ack(true)?; let family_id = sock.resolve_genl_family("nl80211")?; let attrs = once( NlattrBuilder::default() .nla_type( AttrTypeBuilder::default() .nla_type(/* Attribute */ Nl80211Attribute::Mac) .build() .unwrap(), ) .nla_payload( /* Value */ vec![0_u8], /* NOTE: Deliberately wrong length */ ) .build() .unwrap(), ) .collect::>(); let mut recv = sock.send::<_, _, GenlId, Genlmsghdr>( family_id, NlmF::ACK, NlPayload::Payload( GenlmsghdrBuilder::::default() .cmd(Nl80211Command::GetInterface) .version(1) .attrs(attrs) .build()?, ), )?; let data: Option>, _>> = recv.next(); match data { Some(Ok(msgs)) => { println!("msgs: {msgs:?}"); } Some(Err(RouterError::Nlmsgerr(e))) => { println!("msg err: {e:?}"); println!( "unix error: {:?}", std::io::Error::from_raw_os_error(-e.error()) ); for attr in e.ext_ack().iter() { match ExtAckAttr::from(u16::from(attr.nla_type())) { ExtAckAttr::Msg => { println!( "Msg={:?}", String::from_utf8(attr.nla_payload().as_ref().to_vec()) ); } ExtAckAttr::Offs => { println!("Offs={:?}", attr.nla_payload().as_ref()); } ExtAckAttr::Cookie => { println!("Cookie={:?}", attr.nla_payload().as_ref()); } ExtAckAttr::Policy => { println!("Policy={:?}", attr.nla_payload().as_ref()); } _ => println!("attr: {attr:?}"), } } } Some(Err(e)) => { println!("err: {e:#?}"); } None => { println!("No messages received"); } } Ok(()) }