You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ioctl与SIOCGIWESSID读取当前连接的SSID?

问题:使用nix::ioctl_read读取当前连接SSID时遭遇ENOTTY错误

我想用ioctl读取当前连接的SSID,尝试通过nix::ioctl_read实现,但调用ioctl时遇到了“ENOTTY”错误,怀疑是传递给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!()
}

请问该传递什么参数才能让它正常工作?或者有没有其他可行的解决方案?


解决方案

ENOTTY错误的核心原因是ioctl命令与文件描述符不匹配,或结构体内存布局与C标准不一致。以下是具体修正步骤和替代方案:

1. 修正ioctl命令码定义

SIOCGIWESSID的正确值是0x8B1B,而非0x8B。nix的ioctl_read!宏的正确调用格式是:

const SIOCGIWESSID: u32 = 0x8B1B;
ioctl_read!(read_essid, SIOCGIWESSID, Iwreq);

2. 修正C结构体映射

Linux的iwreq结构体有严格的内存布局要求:

  • ifr_name长度为IFNAMSIZ(通常是16字节,不是33)
  • u是共用体,其中essid对应iw_point结构体,length为s32类型

修正后的结构体定义:

use nix::sys::socket::sockaddr;

#[repr(C)]
pub struct IwEssidData {
    length: i32,
    data: [u8; 33], // SSID最大32字节,预留1字节存终止符
    flags: u32,
}

#[repr(C)]
pub union IwReqUnion {
    essid: IwEssidData,
    addr: sockaddr, // 保留共用体的其他字段占位
}

#[repr(C)]
pub struct Iwreq {
    ifr_name: [u8; 16],
    u: IwReqUnion,
}

3. 修正socket创建方式

无线扩展ioctl需要绑定IP协议的UDP socket,指定Protocol::Ip确保兼容性:

let fd = socket(
    AddressFamily::Inet,
    SockType::Datagram,
    SockFlag::empty(),
    Some(Protocol::Ip),
).unwrap();

4. 完整可运行代码

use nix::sys::socket::{AddressFamily, SockType, SockFlag, Protocol, socket};
use nix::ioctl_read;

const SIOCGIWESSID: u32 = 0x8B1B;

#[repr(C)]
pub struct IwEssidData {
    length: i32,
    data: [u8; 33],
    flags: u32,
}

#[repr(C)]
pub union IwReqUnion {
    essid: IwEssidData,
}

#[repr(C)]
pub struct Iwreq {
    ifr_name: [u8; 16],
    u: IwReqUnion,
}

ioctl_read!(read_essid, SIOCGIWESSID, Iwreq);

fn get_essid() -> Result<String, Box<dyn std::error::Error>> {
    const WESSID_MAX_LEN: usize = 32;
    const IFNAMSIZ: usize = 16;

    // 打开socket
    let fd = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        Some(Protocol::Ip),
    )?;

    // 初始化接口名字段
    let mut ifr_name = [0u8; IFNAMSIZ];
    let interface_name = "wlp2s0\0";
    ifr_name[..interface_name.len()].copy_from_slice(interface_name.as_bytes());

    // 初始化iwreq结构体
    let mut data = Iwreq {
        ifr_name,
        u: IwReqUnion {
            essid: IwEssidData {
                length: (WESSID_MAX_LEN + 1) as i32,
                data: [0; 33],
                flags: 0,
            },
        },
    };

    // 调用ioctl
    unsafe {
        read_essid(fd, &mut data)?;
    }

    // 提取并转换SSID为字符串
    let essid_len = data.u.essid.length as usize;
    let essid_bytes = &data.u.essid.data[..essid_len];
    Ok(String::from_utf8_lossy(essid_bytes).trim_end_matches('\0').to_string())
}

fn main() {
    match get_essid() {
        Ok(essid) => println!("当前连接SSID: {}", essid),
        Err(e) => eprintln!("错误: {}", e),
    }
}

替代方案

如果不想直接操作ioctl,可以使用现成的Rust crate简化开发:

  • wireless-utils:封装无线扩展操作,一行代码读取SSID:
    use wireless_utils::Wireless;
    
    fn main() {
        let wireless = Wireless::new("wlp2s0").unwrap();
        let essid = wireless.essid().unwrap();
        println!("当前连接SSID: {}", essid);
    }
    
  • netlink-packet-wifi:通过Netlink接口获取无线信息,更现代的Linux原生方案。

内容的提问来源于stack exchange,提问作者Mahesh Bansod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:46:01