如何将 ioctl 与 SIOCGIWESSID 一起使用

问题描述 投票:0回答:1

我想读取我连接的 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!
以使其正常工作?或者我应该研究其他解决方案吗?

rust ioctl
1个回答
0
投票

看起来您有两个主要问题:

  • 您的结构体不能准确表示 Linux 内核的预期输入数据格式(例如,请参阅最新主线
    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。希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.