从开发者角度来说,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以加深理解。
* * * * *
- 前言
- 第1章 准备工作
- 1.1 Android系统架构
- 1.2 工具使用
- 1.2.1 Source Insight的使用
- 1.2.2 Eclipse的使用
- 1.2.3 BusyBox的使用
- 1.3 本书资源下载说明
- 第2章 深入理解Netd
- 2.1 概述
- 2.2 Netd工作流程
- 2.2.1 main函数分析
- 2.2.2 NetlinkManager分析
- 2.2.3 CommandListener分析
- 2.2.4 DnsProxyListener分析
- 2.2.5 MDnsSdListener分析
- 2.3 CommandListener中的命令
- 2.3.1 iptables、tc和ip命令
- 2.3.2 CommandListener构造函数和测试工具ndc
- 2.3.3 InterfaceCmd命令
- 2.3.4 IpFwd和FirewallCmd命令
- 2.3.5 ListTtysCmd和PppdCmd命令
- 2.3.6 BandwidthControlCmd和IdletimerControlCmd命令
- 2.3.7 NatCmd命令
- 2.3.8 TetherCmd和SoftapCmd命令
- 2.3.9 ResolverCmd命令
- 2.4 NetworkManagementService介绍
- 2.4.1 create函数详解
- 2.4.2 systemReady函数详解
- 2.5 本章总结和参考资料说明
- 2.5.1 本章总结
- 2.5.2 参考资料说明
- 第3章 Wi-Fi基础知识
- 3.1 概述
- 3.2 无线电频谱和802.11协议的发展历程
- 3.2.1 无线电频谱知识
- 3.2.2 IEEE 802.11发展历程
- 3.3 802.11无线网络技术
- 3.3.1 OSI基本参考模型及相关基本概念
- 3.3.2 802.11知识点导读
- 3.3.3 802.11组件
- 3.3.4 802.11 Service介绍
- 3.3.5 802.11 MAC服务和帧
- 3.3.6 802.11 MAC管理实体
- 3.3.7 无线网络安全技术知识点
- 3.4 Linux Wi-Fi编程API介绍
- 3.4.1 Linux Wireless Extensions介绍
- 3.4.2 nl80211介绍
- 3.5 本章总结和参考资料说明
- 3.5.1 本章总结
- 3.5.2 参考资料说明
- 第4章 深入理解wpa_supplicant
- 4.1 概述
- 4.2 初识wpa_supplicant
- 4.2.1 wpa_supplicant架构
- 4.2.2 wpa_supplicant编译配置
- 4.2.3 wpa_supplicant命令和控制API
- 4.2.4 git的使用
- 4.3 wpa_supplicant初始化流程
- 4.3.1 main函数分析
- 4.3.2 wpa_supplicant_init函数分析
- 4.3.3 wpa_supplicant_add_iface函数分析
- 4.3.4 wpa_supplicant_init_iface函数分析
- 4.4 EAP和EAPOL模块
- 4.4.1 EAP模块分析
- 4.4.2 EAPOL模块分析
- 4.5 wpa_supplicant连接无线网络分析
- 4.5.1 ADD_NETWORK命令处理
- 4.5.2 SET_NETWORK命令处理
- 4.5.3 ENABLE_NETWORK命令处理
- 4.6 本章总结和参考资料说明
- 4.6.1 本章总结
- 4.6.2 参考资料说明
- 第5章 深入理解WifiService
- 5.1 概述
- 5.2 WifiService的创建及初始化
- 5.2.1 HSM和AsyncChannel介绍
- 5.2.2 WifiService构造函数分析
- 5.2.3 WifiStateMachine介绍
- 5.3 加入无线网络分析
- 5.3.1 Settings操作Wi-Fi分析
- 5.3.2 WifiService操作Wi-Fi分析
- 5.4 WifiWatchdogStateMachine介绍
- 5.5 Captive Portal Check介绍
- 5.6 本章总结和参考资料说明
- 5.6.1 本章总结
- 5.6.2 参考资料说明
- 第6章 深入理解Wi-Fi Simple Configuration
- 6.1 概述
- 6.2 WSC基础知识
- 6.2.1 WSC应用场景
- 6.2.2 WSC核心组件及接口
- 6.3 Registration Protocol详解
- 6.3.1 WSC IE和Attribute介绍
- 6.3.2 802.11管理帧WSC IE设置
- 6.3.3 EAP-WSC介绍
- 6.4 WSC代码分析
- 6.4.1 Settings中的WSC处理
- 6.4.2 WifiStateMachine的处理
- 6.4.3 wpa_supplicant中的WSC处理
- 6.4.4 EAP-WSC处理流程分析
- 6.5 本章总结和参考资料说明
- 6.5.1 本章总结
- 6.5.2 参考资料说明
- 第7章 深入理解Wi-Fi P2P
- 7.1 概述
- 7.2 P2P基础知识
- 7.2.1 P2P架构
- 7.2.2 P2P Discovery技术
- 7.2.3 P2P工作流程
- 7.3 WifiP2pSettings和WifiP2pService介绍
- 7.3.1 WifiP2pSettings工作流程
- 7.3.2 WifiP2pService工作流程
- 7.4 wpa_supplicant中的P2P
- 7.4.1 P2P模块初始化
- 7.4.2 P2P Device Discovery流程分析
- 7.4.3 Provision Discovery流程分析
- 7.4.4 GO Negotiation流程分析
- 7.5 本章总结和参考资料说明
- 7.5.1 本章总结
- 7.5.2 参考资料说明
- 第8章 深入理解NFC
- 8.1 概述
- 8.2 NFC基础知识
- 8.2.1 NFC概述
- 8.2.2 NFC R/W运行模式
- 8.2.3 NFC P2P运行模式
- 8.2.4 NFC CE运行模式
- 8.2.5 NCI原理
- 8.2.6 NFC相关规范
- 8.3 Android中的NFC
- 8.3.1 NFC应用示例
- 8.3.2 NFC系统模块
- 8.4 NFC HAL层讨论
- 8.5 本章总结和参考资料说明
- 8.5.1 本章总结
- 8.5.2 参考资料说明
- 第9章 深入理解GPS
- 9.1 概述
- 9.2 GPS基础知识
- 9.2.1 卫星导航基本原理
- 9.2.2 GPS系统组成及原理
- 9.2.3 OMA-SUPL协议
- 9.3 Android中的位置管理
- 9.3.1 LocationManager架构
- 9.3.2 LocationManager应用示例
- 9.3.3 LocationManager系统模块
- 9.4 本章总结和参考资料说明
- 9.4.1 本章总结
- 9.4.2 参考资料说明
- 附录