rust 如何将ioctl与SIOCGIWESSID结合使用

jogvjijk  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(107)

我想读取我连接到的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!来使它工作?或者我应该研究另一种解决方案?

8yparm6h

8yparm6h1#

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

  • 您的结构体不能准确地表示Linux内核预期的输入数据格式(例如,请参阅最新主线v6.5版本中的struct iwreq定义:include/uapi/linux/wireless.h
  • 无线子系统ioctl编号不遵循较新的约定。它们使用任意硬编码编号。nix crate文档将这些编号称为 badioctl 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。希望这对你有帮助!

相关问题