從開發者角度來說,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 參考資料說明
- 附錄