博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
wpa_supplicant学习
阅读量:4283 次
发布时间:2019-05-27

本文共 6921 字,大约阅读时间需要 23 分钟。

    wpa_supplicant是开源项目源码,被谷歌修改后加入android移动平台,它主要是用来支持WEP,WPA/WPA2和WAPI无线协议和加密认证的,而实际上是通过socket与驱动交互以及上报数据给用户(不管是wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯).

    用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯片操作。简单的说,wpa_supplicant就是WiFi驱动和用户的中转站,另外对协议和加密认证的支持。
    从framework到wpa_supplicant的适配层(wifi.c),其中framework部分需要注意的是wifiService和wifiMoniter两部分,这两块一个是转发AP的CMD,另一个是接收来自wpa_supplicant的CMD。他们与本地库的连接都是通过JNI方法,具体实现方法在android_net_wifi_Wifi.cpp中。

    android_net_wifi_Wifi.cpp中可以看出AP给wpa_supplicant发送的命令。这些命令通过wifi.c的wifi_command发送给wpa_supplicant,发送命令调用wpa_ctrl_request来完成,wpa_ctrl_request是通过socket的方式与wpa_supplicant进行通信的,然后通过wpa_ctrl_recv来接收来自wpa_supplicant的命令,并返回标识给wifi_wait_for_event。

   WifiStateTracker会创建WifiMonitor接收来自底层的事件,WifiService和WifiMonitor是整个模块的核心。

   WifiService负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor监视线程和把命令下发给wpa_supplicant。
   WifiMonitor则负责从wpa_supplicant接收事件通知。
连接 AP
1.使能 WIFI
WirelessSettings在初始化的时候配置了由WifiEnabler来处理 Wifi按钮,
private void initToggles() {
mWifiEnabler = new WifiEnabler(
this,(WifiManager) getSystemService(WIFI_SERVICE),
(CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI));
    当用户按下Wifi按钮后,Android会调用 WifiEnabler的onPreferenceChange,再由 WifiEnabler调用 WifiManager的setWifiEnabled接口函数,通过 AIDL,实际调用的是 WifiService的setWifiEnabled函数,WifiService接着向自身发送一条 MESSAGE_ENABLE_WIFI消息,在处理该消息的代码中做真正的使能工作:

    首先装载 WIFI内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ),

    然后启动wpa_supplicant (配置文件硬编码为"/data/misc/wifi/wpa_supplicant.conf")
    再通过 WifiStateTracker来启动WifiMonitor中的监视线程。
private boolean setWifiEnabledBlocking(boolean enable) {
final int eventualWifiState = enable ?WIFI_STATE_ENABLED :WIFI_STATE_DISABLED;
updateWifiState(enable ? WIFI_STATE_ENABLING:WIFI_STATE_DISABLING);
if (enable) {
if (!WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fidriver.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
if (!WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicantdaemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
mWifiStateTracker.startEventLoop();
}
// Success!
persistWifiEnabled(enable);
updateWifiState(eventualWifiState);
return true;
}
    当使能成功后,会广播发送 WIFI_STATE_CHANGED_ACTION 这个Intent通知外界WIFI已经成功使能了。WifiEnabler创建的时候就会向Android注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该 Intent,从而开始扫描。
   private void handleWifiStateChanged(intwifiState) {
if (wifiState == WIFI_STATE_ENABLED) {
loadConfiguredAccessPoints();
attemptScan();
}

2.查找 AP

扫描的入口函数是 WifiService的 startScan,它其实也就是往 wpa_supplicant发送 SCAN命令。
static jbooleanandroid_net_wifi_scanCommand(JNIEnv* env, jobjectclazz)
{
jboolean result;
// Ignore any error from setting the scanmode.
// The scan will still work.
(void)doBooleanCommand("DRIVERSCAN-ACTIVE", "OK");
result = doBooleanCommand("SCAN", "OK");
(void)doBooleanCommand("DRIVERSCAN-PASSIVE", "OK");
return result;
}

当wpa_supplicant处理完SCAN命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event函数会接收到该事件,由此 WifiMonitor 中的MonitorThread会被执行来出来这个事件,

void handleEvent(int event, Stringremainder) {

case SCAN_RESULTS:

mWifiStateTracker.notifyScanResultsAvailable();

break;

WifiStateTracker则接着广播发送 SCAN_RESULTS_AVAILABLE_ACTION这个Intent

case EVENT_SCAN_RESULTS_AVAILABLE:

mContext.sendBroadcast(new

Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

WifiLayer注册了接收 SCAN_RESULTS_AVAILABLE_ACTION这个Intent,所以它的相关处理函数handleScanResultsAvailable会被调用,在该函数中,先会去拿到 SCAN 的结果(最终是往 wpa_supplicant发送 SCAN_RESULT命令并读取返回值来实现的),

List<ScanResult> list=mWifiManager.getScanResults();

对每一个扫描返回的AP,WifiLayer会调用 WifiSettings的onAccessPointSetChanged函数,从而最终把该 AP加到 GUI显示列表中。

public voidonAccessPointSetChanged(AccessPointState ap, booleanadded) {

AccessPointPreference pref = mAps.get(ap);
if (added) {
if (pref == null) {
pref = new AccessPointPreference(this, ap);
mAps.put(ap, pref);
} else {
pref.setEnabled(true);
}
mApCategory.addPreference(pref);
}
}
3.配置 AP参数
当用户在WifiSettings界面上选择了一个AP后,会显示配置 AP参数的一个对话框,
public boolean onPreferenceTreeClick(PreferenceScreenpreferenceScreen,Preference preference) {
if (preference instanceofAccessPointPreference) {
AccessPointState state =((AccessPointPreference)
preference).getAccessPointState();
showAccessPointDialog(state,AccessPointDialog.MODE_INFO);
}
}
4.连接
当用户在AcessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP。
private void handleConnect() {
String password = getEnteredPassword();
if (!TextUtils.isEmpty(password)) {
mState.setPassword(password);
}
mWifiLayer.connectToNetwork(mState);
}
WifiLayer会先检测这个AP是不是之前被配置过,这个是通过向 wpa_supplicant 发送LIST_NETWORK命令并且比较返回值来实现的,
// Need WifiConfiguration for the AP
WifiConfiguration config =findConfiguredNetwork(state);
如果wpa_supplicant没有这个AP的配置信息,则会向wpa_supplicant发送 ADD_NETWORK命令来添加该AP,
if (config == null) {
// Connecting for the first time, need to create it
config =addConfiguration(state,ADD_CONFIGURATION_ENABLE|ADD_CONFIGURATION_SAVE);
}
ADD_NETWORK命令会返回一个 ID , WifiLayer再用这个返回的 ID作为参数向wpa_supplicant发送ENABLE_NETWORK命令,从而让 wpa_supplicant 去连接该AP。
// Make sure that network is enabled, anddisable others
mReenableApsOnNetworkStateChange = true;
if(!mWifiManager.enableNetwork(state.networkId, true)) {
Log.e(TAG, "Could not enable networkID " + state.networkId);
error(R.string.error_connecting);
return false;
}
5.配置 IP地址
当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread会被执行来出来这个事件,
void handleEvent(int event, Stringremainder) {
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);
break;
WifiMonitor再调用WifiStateTracker的notifyStateChange,WifiStateTracker则接着会往自身发送EVENT_DHCP_START消息来启动DHCP去获取 IP地址。
private void handleConnectedState() {
setPollTimer();
mLastSignalLevel = -1;
if (!mHaveIPAddress&&!mObtainingIPAddress) {
mObtainingIPAddress = true;
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();
}
}
然后再广播发送NETWORK_STATE_CHANGED_ACTION这个Intent
case EVENT_NETWORK_STATE_CHANGED:
if (result.state != DetailedState.DISCONNECTED ||!mDisconnectPending) {
intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO,mNetworkInfo);
if (result.BSSID != null)
intent.putExtra(WifiManager.EXTRA_BSSID,result.BSSID);
mContext.sendStickyBroadcast(intent);
}
break;
WifiLayer注册了接收 NETWORK_STATE_CHANGED_ACTION这个 Intent,所以它的相关处理函数handleNetworkStateChanged会被调用,

当DHCP拿到IP地址之后,会再发送 EVENT_DHCP_SUCCEEDED消息,

private class DhcpHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DHCP_START:
if (NetworkUtils.runDhcp(mInterfaceName,mDhcpInfo)) {
event = EVENT_DHCP_SUCCEEDED;
}
WifiLayer处理 EVENT_DHCP_SUCCEEDED消息 ,会再次广播发送
NETWORK_STATE_CHANGED_ACTION这个 Intent,这次带上完整的 IP地址信息。
case EVENT_DHCP_SUCCEEDED:
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
setDetailedState(DetailedState.CONNECTED);
intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO,mNetworkInfo);
mContext.sendStickyBroadcast(intent);
break;

至此为止,整个连接过程完成。

问题:
目前的实现不支持 Ad-hoc方式。

转载地址:http://wtcgi.baihongyu.com/

你可能感兴趣的文章
nyoj - 947(Max Xor)字典树
查看>>
单链表
查看>>
双向链表
查看>>
UVA Live 6068
查看>>
UVa Cellular Structure
查看>>
UVa Distinct Subsequences
查看>>
nyoj-字和串之差
查看>>
UVA Compromise(最长公共子序列 + 打印路径)
查看>>
01背包之打印路径
查看>>
01背包之(数之组合)
查看>>
reverse() 几种操作
查看>>
cf-123B
查看>>
poj -- 1185 炮兵阵地
查看>>
hdu-4539 郑厂长系列故事――排兵布阵(状态压缩)
查看>>
hdu-1074 Doing Homework
查看>>
hdu-5063 Operation the Sequence
查看>>
zoj - 3502 Contest
查看>>
zoj-3471 Most powful
查看>>
poj-Scout YYF I
查看>>
CodeForces 165E Compatible Numbers
查看>>