企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
从开发者角度来说,wext的用法相当简单。Linux平台中,wext API定义于wireless.h文件。Android平台上,其文件位置在external/kernel-headers/original/linux目录下,主要供驱动开发者使用。 * * * * * **注意**,bionic/libc/kernel/common/linux目录中也有一个wireless.h,不过此文件由工具程序根据kernel中的wireless.h自动生成而来,供用户空间使用。两个文件的区别主要是bionic下的wireless.h包含很少的注释。所以本节将分析kernel中的wireless.h。Android 4.2中的wext版本为20,由wireless.h中的宏WIRELESS_EXT定义。 * * * * * 虽然前面提到说ioctl函数的一个缺点是其没有指明参数类型,但wext却比较严谨,它提供了自己的数据类型。 **1. 常用数据结构介绍** 首先,所有用户空间发起的请求都统一包括在struct iwreq中,其原型如下: **wireless.h::struct iwreq** ~~~ //wext API在设计时参考了系统中现有数据结构及命名方式。做为区分,wext中几乎所有数据结构、类型、宏 //等名字中都带一个w以代表wireless。如下面的iwreq结构体,其对应的普通数据结构类型是ifreq。 //该结构体专门用于往socket句柄传递ioctrl控制参数。 struct iwreq { union { char ifrn_name[IFNAMSIZ]; //用于指定要操作的网卡设备名,如wlan0 } ifr_ifrn; union iwreq_data u; //用于存储具体的参数信息 }; ~~~ 如iwreq结构所示,具体的参数信息存储在另外一个联合体iwreq_data中,其原型如下: **wireless.h::union:iwreq_data** ~~~ /* iwreq_data是一个联合体,其最大size为16字节 wext还自定义了一些小的数据结构,如iw_point、iw_param、iw_freq等。它们的作用是: 1 iw_point:当参数信息的长度超过16字节时,就只能通过iw_point指向另外一块内存区域,而参数就存储 在那个区域中。这个就是我们常用的指针方式。 2 iw_param:当参数信息不超过16字节时,可以把信息存储在iw_param中。 3 iw_freq:用于存储频率或信道值。其原型的介绍见本小节最后。 union iwreq_data { char name[IFNAMSIZ]; struct iw_point essid; //存储essid,也就是ssid struct iw_param nwid; //network id //频率或信道。取值为0-1000时代表channel,大于1000则代表频率,单位为Hz struct iw_freq freq; struct iw_param sens; //信号强度阈值 struct iw_param bitrate; //码率 struct iw_param txpower; struct iw_param rts; //RTS阈值时间 struct iw_param frag; __u32 mode; //操作模式 struct iw_param retry; struct iw_point encoding; struct iw_param power; struct iw_quality qual; struct sockaddr ap_addr; //AP地址 struct sockaddr addr; //目标地址 struct iw_param param; //其他参数 struct iw_point data; //其他字节数超过16的参数 }; ~~~ 当参数字节超过16的时候,wext还定义了和功能相关的参数类型,下面来看专门用于触发无线网卡发起扫描请求的数据结构iw_scan_req,其原型如下所示: **wireless.h::struct iw_scan_req** ~~~ struct iw_scan_req { __u8 scan_type; //可取值为IW_SCAN_TYPE_{ACTIVE,PASSIVE},代表主动或被动扫描 __u8 essid_len; //essid字符串长度 __u8 num_channels; // 指明信道个数,如果为0,则表示扫描所有可允许的信道 __u8 flags; //目前仅用于字节对齐 //bssid用于指明BSS的地址。如果全为FF则为广播BSSID,即wildcard bssid struct sockaddr bssid; __u8 essid[IW_ESSID_MAX_SIZE]; //essid /* min_channel_time:指示扫描过程中在每个信道等待到第一个回复的时间。如果在此时间内没有等到回复, 则跳到下一个信道去等待。如果等到一个回复的话,则一共在该信道等待的最大时间为max_channel_time。 所有时间单位均为TU(Time Units),即1024ms */ __u32 min_channel_time; __u32 max_channel_time; struct iw_freq channel_list[IW_MAX_FREQUENCIES];//IW_MAX_FREQUENCIES值为32 }; ~~~ 下面来看最后一个常见的数据结构iw_freq,其原型如下: **wireless.h::struct:iw_freq**: ~~~ //当频率小于109,m直接等于频率。否则m=f/(10e) struct iw_freq { __s32 m; __s16 e; __u8 i; //该值表示此频率对象在channel_list数组中的索引 __u8 flags; //固定或自动 }; ~~~ * * * * * **提醒**: wext中的数据结构和定义还有许多。建议读者结合实际需要去学习wireless.h。 wext API虽然简单,但相信读者已经体会到其背后所依赖的和802.11规范密切相关的理论知识了。 * * * * * 下面我们通过一个实际的例子来看看用户空间如何通过wext API来触发无线网卡扫描工作的。 2. wext API使用实例介绍 本例来源于wpa_supplicant,它是一个运行于用户空间的专门和无线网卡进行交互的程序。其详情将在下一章节进行介绍。本节仅通过一个函数看看wpa_supplicant如何利用wext API和无线网卡交互。 **driver_wext.c:wpa_driver_wext_scan** ~~~ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) { struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; //定义一个iwreq对象 int ret = 0, timeout; struct iw_scan_req req; //定义一个iw_scan_req对象 //获取调用者传递的ssid等参数 const u8 *ssid = params->ssids[0].ssid; size_t ssid_len = params->ssids[0].ssid_len; ...... os_memset(&iwr, 0, sizeof(iwr)); //为iwr的ifr_name传递需操作的网卡设备名 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); if (ssid && ssid_len) { os_memset(&req, 0, sizeof(req)); //设置iw_scan_req的信息 req.essid_len = ssid_len; req.bssid.sa_family = ARPHRD_ETHER; //设置bssid的MAC地址全为0XFF,代表这是一个wildcard BSSID搜索 os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); os_memcpy(req.essid, ssid, ssid_len); //通过data域指向这个iw_sca_req对象 iwr.u.data.pointer = (caddr_t) &req; iwr.u.data.length = sizeof(req); //IW_SCAN_THIS_ESSID表示只扫描指定ESSID的无线网络 iwr.u.data.flags = IW_SCAN_THIS_ESSID; } /* ioctl_sock指向一个socket句柄,其创建时候的代码如下: ioctl_sock = socket(PF_INET,SOCK_DGRAM,0) SIOCSIWSCAN用于通知驱动进行无线网络扫描 */ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { //返回错误 } ......//其他处理 return ret; } ~~~ * * * * * **提示**:wext相对比较简单,但其内部的数据结构定义、变量命名等都和规范中定义的原语有着莫大的关系。建议读者结合规范去阅读wireless.h以加深理解。 * * * * *