我想读取我连接的 SSID。
我正在使用 ioctl 来执行此操作。我正在尝试使用
nix::ioctl_read
来阅读它。
我对此很陌生,所以我不确定我所做的是否正确。
这是我尝试过的。
const SIOCGIWESSID: u8 = 0x8B;
ioctl_read!(read_essid, SIOCGIWESSID, 0x8B1B, Iwreq);
#[derive(Debug)]
pub struct Essid {
length: u8,
pointer: [u8; 33],
}
#[derive(Debug)]
pub struct WreqData {
essid: Essid,
}
#[derive(Debug)]
#[repr(C)]
pub struct Iwreq {
frn_name: [u8; 33],
u: WreqData,
}
fn get_essid() -> String {
const WESSID_LEN: usize = 33;
let fd = socket(
AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None,
)
.unwrap();
let pointer: [u8; WESSID_LEN] = [0; WESSID_LEN];
let mut ifr_tmp = [0u8; WESSID_LEN];
let interface_name = "wlp2s0\0";
ifr_tmp[..interface_name.len()].copy_from_slice(interface_name.as_bytes());
let mut data = Iwreq {
frn_name: ifr_tmp,
u: WreqData {
essid: Essid {
length: WESSID_LEN as u8,
pointer,
},
},
};
println!("{}", unsafe { read_essid(fd, &mut data).unwrap() });
println!("{:?}", data);
unimplemented!()
}
我从 ioctl 调用中收到错误“ENOTTY”。我认为我向 ioctl_read 传递了错误的参数。
我可以将什么传递给
ioctl_read!
以使其正常工作?或者我应该研究其他解决方案吗?
看起来您有两个主要问题:
struct iwreq
版本中的 v6.5
定义:include/uapi/linux/wireless.h
)ioctl
数字不遵循较新的约定。相反,他们使用任意硬编码数字。 nix
板条箱文档将这些称为 bad ioctl
s。因此,您可以使用 ioctl_read_bad!
宏这是一个修改后的版本,似乎可以在我的机器上运行:
#[repr(C)]
pub struct Essid {
pointer: *const c_char,
length: u16,
flags: u16,
}
impl Essid {
const fn new(pointer: *const c_char) -> Self {
Self {
pointer,
length: 33,
flags: 0,
}
}
}
#[repr(C)]
pub struct WreqData {
essid: Essid,
}
#[repr(C)]
pub struct Iwreq {
frn_name: [u8; 16],
u: WreqData,
}
impl Iwreq {
fn new(name: &str, buf: &[c_char; 33]) -> Self {
let mut frn_name = [0; 16];
frn_name[..name.len()].copy_from_slice(name.as_bytes());
Self {
frn_name,
u: WreqData {
essid: Essid::new(buf.as_ptr()),
},
}
}
}
nix::ioctl_read_bad!(read_essid, 0x8B1B, Iwreq);
fn get_essid(name: &str) -> anyhow::Result<String> {
let sock = socket::socket(
AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None,
)?;
let buf = [0; 33];
let mut data = Iwreq::new(name, &buf);
unsafe { read_essid(sock.as_raw_fd(), &mut data) }?;
let ptr = buf.as_ptr();
Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_owned())
}
或者,可以使用 netlink 套接字获取相同的信息。例如:
async fn get_essid(name: &str) -> anyhow::Result<String> {
let (connection, handle, _) = wl_nl80211::new_connection()?;
tokio::spawn(connection);
let mut ifaces = handle.interface().get().execute().await;
while let Ok(Some(iface)) = ifaces.try_next().await {
if !iface
.payload
.nlas
.iter()
.any(|nla| matches!(nla, Nl80211Attr::IfName(n) if n == name))
{
continue;
}
for nla in iface.payload.nlas {
if let Nl80211Attr::Ssid(ssid) = nla {
return Ok(ssid);
}
}
}
bail!("SSID not found")
}
如果您想完整查看此示例/测试代码,我已将其上传到 GitLab:https://gitlab.com/harryausten/ssid-query。希望这有帮助!