Wifi Direct流程分析
Android平台中,P2P操作比较简单,用户只需要执行如下三个步骤:
1)进入WifiP2pSettings界面
2)搜索周围的P2P设备。搜索到的设备将显示在WifiP2pSettings中
3)用户选择其中的某个设备发起连接或者接受某设备发起的连接
下面将根据这些步骤来分析WifiP2pSettings和WifiP2pService的流程,主要包括:P2P的使能、P2P的扫描、P2P的配对以及P2P的连接。
Wifi Direct环境的建立
WifiP2pSettings创建
首先从WifiP2pSettings中的onActivityCreated()函数分析,代码如下:
public void onActivityCreated(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.wifi_p2p_settings);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.
WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
final Activity activity = getActivity();
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
if (mWifiP2pManager != null) {
mChannel = mWifiP2pManager.initialize(activity, getActivity().getMainLooper(), null);
if (mChannel == null) {
//Failure to set up connection
Log.e(TAG, "Failed to set up connection with wifi p2p service");
mWifiP2pManager = null;
}
..............
mRenameListener = new OnClickListener() {..............}
...............
uper.onActivityCreated(savedInstanceState);
}
onActivityCreated()函数主要的做了三件事:
①将P2P特有的Action添加到过滤器中。
②构造和初始化WifiP2pManager对象,并建立和WifiService联系。
③创建UI中按钮对应的OnClickListener。
WifiP2pSettings主要通过通过监听广播方式了解系统中Wifi P2p信息以及变化情况,下面简要介绍这几个属于P2P特有的广播:
1)WIFI_P2P_STATE_CHANGED_ACTION-用于通知P2P功能的请用情况。
2)WIFI_P2P_PEERS_CHANGED_ACTION-系统内部保存搜索到其他P2P设备信息的变化情况
3)WIFI_P2P_CONNECTION_CHANGED_ACTION-用于通知P2P的连接情况
4)WIFI_P2P_THIS_DEVICE_CHANGED_ACTION-用于通知本机设备信息变化情况
5)WIFI_P2P_DISCOVERY_CHANGED_ACTION-用于通知P2P Discovery的工作状态
6)WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION-用于通知persistent group信息的变化情况。
WifiP2pService的启动
首先WifiP2pService中new了一个WifiP2pServiceimpl对象,下面主要来看看WifiP2pServiceimpl的构造函数:
public WifiP2pServiceImpl(Context context) {
mContext = context;
//STOPSHIP: get this from native side
mInterface = "p2p0";
..........
mP2pStateMachine = new P2pStateMachine(
TAG, wifiP2pThread.getLooper(), mP2pSupported);
mP2pStateMachine.start();
}
WifiP2pServiceimpl构造函数主要是创建一个NetworkInfo,然后调用getPackageManager判断本机设备是否支持P2P功能。通过创建一个P2pStateMachine并启动StateMachine。
下面进入P2pStateMachine函数分析
P2pStateMachine(String name, Looper looper, boolean p2pSupported) {
super(name, looper);
addState(mDefaultState);
addState(mP2pNotSupportedState, mDefaultState);
..............
if (p2pSupported) {
setInitialState(mP2pDisabledState);
} else {
setInitialState(mP2pNotSupportedState);
}
setLogRecSize(50);
setLogOnlyTransitions(true);
分析构造函数,看出P2pStateMachine的各个State关系如下图:
P2pStateMachine是WifiP2pService的核心,P2pStateMachine的初始状态是P2pDisableState。
Wifi Direct模块的初始化
Wifi Direct的主要数据结构
下面来分析Wifi Direct的几个主要的数据结构,首先看的是p2p_config和p2p_data,它们的成员如下图5所示:
p2p_config定义了25个回调函数,这些回调函数定义了P2P模块与外界交互的接口,均指向p2p_supplicant.c.
p2p_data指向一个p2p_config对象。
下面来看下其他几个重要的数据结构。如下图6:
p2p_device代表一个p2p设备。其中设备名等信息存放在类型为p2p_peer_info的对象中
p2p_group代表一个p2p group的信息,其内包含一个p2p_group_config对象和一个p2p_group_member链表。p2p_group_config代表group的配置信息,p2p_group_member链表代表的是p2p client信息。
Wifi Direct在WPAS中的初始化流程
Wifi Direct在WPAS中的初始化工作主要从wpas_p2p_init()函数开始,下面看看wpas_p2p_init()代码:
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p;
int i;
if (wpa_s->conf->p2p_disabled)
if (wpa_s->conf->p2p_disabled)
..........
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
p2p.p2p_scan = wpas_p2p_scan;
p2p.send_action = wpas_send_action;
..........
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
p2p.dev_name = wpa_s->conf->device_name;
p2p.manufacturer = wpa_s->conf->manufacturer;
p2p.model_name = wpa_s->conf->model_name;
p2p.model_number = wpa_s->conf->model_number;
p2p.serial_number = wpa_s->conf->serial_number;
if (wpa_s->wps) {
os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
p2p.config_methods = wpa_s->wps->config_methods;
}
.........
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
global->p2p_init_wpa_s = wpa_s;
for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
if (wpa_s->conf->wps_vendor_ext[i] == NULL)
continue;
p2p_add_wps_vendor_extension(
global->p2p, wpa_s->conf->wps_vendor_ext[i]);
}
...........
}
wpas_p2p_init()函数主要完成两件工作:
1)构造一个p2p_config对象并对p2p_config对象对象初始化,然后根据p2p_supplicant.conf文件的信息设置其中的内容。同时,为p2p模块设置回调函数。
2)调用p2p_init()函数初始化p2p模块
p2p_init()函数中主要构造了一个p2p_data结构体并设置相应的参数,p2p_init()函数代码比较简单感兴趣可以取分析。
3、注册Action帧
本机设备和对端设备信息交互时候,Action帧扮演重要的角色。在P2P Device Discovenry、Provision Discovery流程以及GO Negotiation流程都涉及到Action帧的处理流程。因此,这边在初始化阶段对Action帧进行注册。
tatic int wpa_driver_nl80211_set_mode_impl(
struct i802_bss *bss,
enum nl80211_iftype nlmode,
struct hostapd_freq_params *desired_freq_params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
int i;
int was_ap = is_ap_interface(drv->nlmode);
int res;
int mode_switch_res;
mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
mode_switch_res = 0;
......
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
/* Setup additional AP mode functionality if needed */
if (nl80211_setup_ap(bss))
return -1;
} else if (was_ap) {
/* Remove additional AP mode functionality */
nl80211_teardown_ap(bss);
} else {
nl80211_mgmt_unsubscribe(bss, "mode change");
}
if (!bss->in_deinit && !is_ap_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
return 0;
}
wpa_driver_nl80211_set_mode_impl()函数中主要的是调用了nl80211_mgmt_subscribe_non_ap()函数,nl80211_mgmt_subscribe_non_ap()将注册对Action帧的监听时间,其作用就是当设备收到Action帧后,Wifi driver将发送相对应的netlink消息给WPAS.
nl80211_mgmt_subscribe_non_ap()注册了两种类型的帧监听事件。
1)P2P Public Action帧监听事件:根据P2P规范,目前适用的军事802.11 P2P Public Action帧(Category的值为0x04)。目前GON、P2P Invitation、Provision Discovery以及Device Discoverability都是适用P2P Public Action帧。
2)P2P Action帧监听事件:这种类型的帧属于802.11Action帧的一种(Category的值为0x7F),目前Notice of Absence、P2P Presence、GO Discoverability适用P2P Action帧。
3.2.Wifi Direct的使能
P2pStateMachine虽然属于WifiP2pService,但它也受WifiStateMachine影响。如果平台支持P2P,在WifiStateMachine中将创建一个名为mWifiP2pChannel的AsyncChannelde 的对象用于向P2pStateMachine发消息。
如果用户打开WiFI功能,P2pStateMachine就会收到来自WifiStateMachine发送的消息CMD_ ENABLE_P2P。
CMD_ ENABLE_P2P消息的处理过程主要在wifip2pserviceinpl.java的P2pDisabledState函数中完成
class P2pDisabledState extends State {
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiStateMachine.CMD_ENABLE_P2P:
try {
mNwService.setInterfaceUp(mInterface);
} catch (RemoteException re) {
...............
}
mWifiMonitor.startMonitoring();
transitionTo(mP2pEnablingState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
接收到CMD_ ENABLE_P2P消息后,P2pStateMachine主要做了两件工作:
1)创建一个WifiMonitor用于接收来自wpa_supplicant的消息
2)同时将状态机转入到P2pEnablingState状态
WifiMonitor连接连接wpa_supplicant之后,WifiMonitor会发送一个SUP_CONNECT_EVENT
消息给P2pStateMachine,该消息由P2pEnablingState处理。
class P2pEnablingState extends State {
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.SUP_CONNECTION_EVENT:
if (DBG) logd("P2p socket connection successful");
transitionTo(mInactiveState);
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT:
loge("P2p socket connection failed");
transitionTo(mP2pDisabledState);
break;
.......}
return HANDLED;
}
}
P2pEnablingState这时会跳转到InactiveState中,由前面P2pStateMachine的State关系图我们可以知道,P2pEnabledState是InactiveState父状态,我们先到P2pEnabledState的enter函数去分析:
class P2pEnabledState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
sendP2pStateChangedBroadcast(true);
mNetworkInfo.setIsAvailable(true);
sendP2pConnectionChangedBroadcast();
initializeP2pSettings();
}
P2pEnabledState()函数主要工作如下:
1)通过sendP2pStateChangedBroadcast()发送WIFI_P2P_STATE_CHANGED_ACTION广播,它将携带WifiP2pInfo和NetworkInfo信息,同时还将通过sendP2pConnectionChangedBroadcast()函数向WifiStateMachine发送WIFI_P2P_CONNECTION_CHANGED_ACTION广播。
调用函数initializeP2pSettings()初始化P2P的一些设,包括deviceName、DeviceType、ConfigMethods,并且获取以前persistent的相关device信息
3.3.Wifi Direct的扫描
P2P的扫描还是从WifiP2psettings开始,当用户单击“SEARCH”按钮搜索P2P设备。该按钮对应的函数是WifiP2pSettings的startSearch()函数。
startSearch()函数调用WifiManager的discoverPeers搜索周围的P2P设备。discoverPeers()函数主要的工作是发布DISCOVER_PEERS消息,由WifiP2pService的P2pEnabledState函数处理。
下面来看下WifiP2pService中discoverPeers处理流程。
class P2pEnabledState extends State {
..............
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
....................
case WifiP2pManager.DISCOVER_PEERS:
if (mDiscoveryBlocked) {
replyToMessage(
message,WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
}
// do not send service discovery request while normal find operation.
clearSupplicantServiceRequest();
if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
replyToMessage(
message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
sendP2pDiscoveryChangedBroadcast(true);
} else {
replyToMessage(
message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.ERROR);
}
break;
...........
}
}
P2pEnabledState()收到DISCOVER_PEERS主要做了三件事:
1)通过clearSupplicantServiceRequest()取消Service Discovery请求。
2)调用WifiNative的p2pFind函数向wpa_supplicant发送P2P_FIND命令。
3)通过sendP2pDiscoveryChangedBroadcast()函数发送
WIFI_P2P_DISCOVERY_CHANGE_ACTION广播通知P2P Device Discovery已经启动。
其中,wpa_supplicant收到P2P_FIND命令开始搜索周边的P2P设备,如果找到就会向WifiMonitor发送P2P-DEVICE-FOUND这样的EVENT,这个event会带有对方设备的信息,包括MAC地址、device type、设备名字以及config methods等。WifiMonitor收到这样的event后,会将P2P-DEVICE-FOUND后面的data数据封装成为一个WifiP2pDevice对象,然后发送P2P_DEVICE_FOUND_EVENT消息给WIfiStateMachine处理。
下面来看下WifiP2pService中P2P_DEVICE_FOUND_EVENT处理流程。
class P2pEnabledState extends State {
..............
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
....................
case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
WifiP2pDevice device = (WifiP2pDevice) message.obj;
if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
mPeers.updateSupplicantDetails(device);
sendPeersChangedBroadcast();
break;
}.................
}
P2pEnabledState()收到P2P_DEVICE_FOUND_EVENT,在构造函数中主要做了两件事:
①通过WPAS反馈的信息构建一个WifiP2pDevice对象
②发送WIFI_P2P_PEERS_CHANGED_ACTION广播
下面来看看WifiP2pSetting收到WIFI_P2P_PEERS_CHANGED_ACTION广播以及
WIFI_P2P_DISCOVERY_CHANGE_ACTION广播后的处理过程。
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
............
}else if
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action))
{
mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
handlePeersChanged();
}............
else if(
WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action))
{
...............
updateSearchMenu(true);
.. ........
}
}
WifiP2pSetting收到WIFI_P2P_PEERS_CHANGED_ACTION广播后,通过WifiManager的handlepeerschanged()函数获取P2P Device信息。收到WIFI_P2P_DISCOVERY_CHANGED_ACTION调用updateSearchMenu()函数显示所有的设备。至此,P2P扫描的全部过程已经完成。P2P扫描的时序图如图3:
由前面可知,P2pStateMachine将通过发送P2P_FIND命令给WPAS触发P2P Device Discovery流程。下面来看下P2P Device Discovery扫描过程,如下图4:
P2P Device Discovery扫描过程主要做了三件工作:
1)接受来之P2pStateMachine的命令,设置搜索方式。
2)调用wpas_p2p_scan()函数设置SSID、Probe Request帧中的WSC IE信息、P2P IE以及其他扫描参数。
3)调用wpa_driver_nl80211_scan()函数开始扫描以及设置P2P扫描结果处理指针函数主要调用wpas_p2p_scan_res_handle()函数。
其中,搜索方式主要有三种:
P2P_FIND_ONLY_WITH_FULL:默认设置。表示先扫描所有频段,然后再扫描social channels.
P2P_FIND_ONLY_SOCIAL:只扫描social channels。
P2P_FIND_PROGRESSIVE:和P2P_FIND_ONLY_WITH_FULL扫描过程相类似,只不过Search
State阶段将逐个扫描所有的频段。
对扫描结果的处理主要从wpas_p2p_scan_res_handle()开始。数据结构wpa_scan_results用于存储扫描结果,如图5为扫描结果的时序图:
wpas_p2p_scan_res_handler()函数中主要存在两个关键函数p2p_scan_res_handler()和p2p_scan_res_handled()。
每一个存储在wpa_scan_results结构体中的扫描结果,都会调用p2p_scan_res_handler()进行处理。p2p_scan_res_handler()函数主要的工作有两方面:
1)p2p_add_device()函数构造一个p2p Device对象加入到devices链表并获取对端设备的P2P DEVICE信息。
2)设置一个dev_found指针指向wpas_dev_found()函数,wpas_dev_found()将向WifiMonitor发送消息P2P DEVICE FOUND告知上层对端设备找到。
处理完扫描结果将调用第二个关键函数p2p_scan_res_handled()进入listen state状态。这边需要注意的是:
1)p2p_build_probe_resp_ies()函数为wifi driver设置P2P IE消息,如果wifi driver自己处理Probe Request帧,则wifi driver将把此处设置的P2P IE信息填写到Probe Response帧中。
2) wpa_drv_set_ap_wps_ie()要求wifi driver收到Probe Request帧后,发送EVENT_RX_PROBE_REQ给WPAS。
3)wpa_drv_remain_on_channel()函数要求wifi driver在指定的频段工作一段时间,若切换到某一频段,wifi driver会发送EVENT_REMAIN_ON_CHANNAL消息给WPAS.
3.4.Wifi Direct的连接
3.4.1Wifi Direct的连接
Wifi P2P连接主要分为:主动连接 、被动连接、主动invite以及被动invite,本文主要分析主动连接。
Wifi P2P扫描完成后,用户可以在界面中选择某个P2P设备并与之连接,Wifi P2P连接也是有WifiP2pSettings.java开始。先来看看WifiP2pSettings的onPreferenceTreeClick函数:
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof WifiP2pPeer) {
mSelectedWifiPeer = (WifiP2pPeer) preference;
if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {
showDialog(DIALOG_DISCONNECT);
} else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) {
showDialog(DIALOG_CANCEL_CONNECT);
} else {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mSelectedWifiPeer.device.deviceAddress;
int forceWps = SystemProperties.getInt("wifidirect.wps", -1);
if (forceWps != -1) {
config.wps.setup = forceWps;
} else {
if (mSelectedWifiPeer.device.wpsPbcSupported()) {
config.wps.setup = WpsInfo.PBC;
} else if (mSelectedWifiPeer.device.wpsKeypadSupported()) {
config.wps.setup = WpsInfo.KEYPAD;
} else {
config.wps.setup = WpsInfo.DISPLAY;
}
}
mWifiP2pManager.connect(mChannel, config,
new WifiP2pManager.ActionListener() {...................}
}..............
}
}
onPreferenceTreeClick()主要做了三件事:
①获取用户指定的WifiP2pPeer项。
②获取对端设备的WSC的配置方法。
③构造WifiP2pConfig对象存储对端设备信息并调用WifiP2pManager的connect函数向该对端设备发起连接。
connect函数的工作主要是通过Channel的AsyncChannel给P2pStatuesMachine发送CONNECT消息。
下面来看下CONNECT消息的处理流程。
class InactiveState extends State {
..............
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiP2pManager.CONNECT:
if (DBG) logd(getName() + " sending connect");
WifiP2pConfig config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping connect requeset " + config);
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
break;
}
mAutonomousGroup = false;
mWifiNative.p2pStopFind();
if (reinvokePersistentGroup(config)) {
transitionTo(mGroupNegotiationState);
} else {
transitionTo(mProvisionDiscoveryState);
}
...................
}.................
}
这里分为persistent的连接方式和非persistent的连接,对于persistent连接,如果第一次连接成功wpa_supplicant会记录连接的记录,包括credential、GO MAC地址、ssid等信息。采用非persistent的连接(即negotiate方式)则跳转到ProvisionDiscoveryState函数,调用WifiNative的p2pProvisionDiscovery向对端设备发送Provision discovery封包。对端设备处理Provision discovery封包后就会回复provision response,经wpa_supplicant处理WifiMonitor会收到P2P-PROV-DISC-PBC-RESP(当WPS方式为PBC方式时), WifiMonitor就会向P2pStateMachine发送P2P_PROV_DISC_PBC_RSP_EVENT。
下面来看看P2P_PROV_DISC_PBC_RSP_EVENT消息的处理过程,主要做两件事
①调用p2pConnectWithPinDisplay函数插法WPAS发送GON Request帧(调用Wifinative的P2pconnect函数有兴趣可以看看)。
②跳转到GroupNegotiationState,开始Group negotiate
class ProvisionDiscoveryState extends State {
..............
public boolean processMessage(Message message) {
..............
switch (message.what) {
case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
provDisc = (WifiP2pProvDiscEvent) message.obj;
device = provDisc.device;
if (!device.deviceAddress.equals(
mSavedPeerConfig.deviceAddress))
break;
if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
if (DBG) logd("Found a match " + mSavedPeerConfig);
p2pConnectWithPinDisplay(mSavedPeerConfig);
transitionTo(mGroupNegotiationState);
}
...................
}
下面来看下Group negotiate过程:
class GroupNegotiationState extends State {
..............
public boolean processMessage(Message message) {
..............
switch (message.what) {
case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
if (DBG) logd(getName() + " go success");
break;
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
if (DBG) logd(getName() + " group started");
if (mGroup.getNetworkId()=WifiP2pGroup.PERSISTENT_NET_ID) {
updatePersistentNetworks(NO_RELOAD);
String devAddr = mGroup.getOwner().deviceAddress;
mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
mGroup.getNetworkName()));
}
if (mGroup.isGroupOwner()) {
if (!mAutonomousGroup) {
mWifiNative.setP2pGroupIdle(
mGroup.getInterface(), GROUP_IDLE_TIME_S);
}
startDhcpServer(mGroup.getInterface());
} else {.............}
transitionTo(mGroupCreatedState);
}
}
开始group negotiate后,wpa_supplicant会发多个event给WifiMonitor,WifiMonitor处理后也会发送多个event消息给P2pStateMachine。其中比较重要的是P2P_GROUP_STARTED_EVENT
GroupNegotiationState()接收到P2P_GROUP_STARTED_EVENT主要做了四件事:
①更新和设置mgroup的信息。
②调用DHCP为两端设备分配IP地址。
③向wifiP2pSettings发送广播。
④更新Group owner信息,跳转到GroupCreatedState连接完成。
GroupCreatedState函数主要调用sendP2pConnectionChangedBroadcast()广播当前连接状态的改变,WifiP2pSettings会捕获这个WIFI_P2P_CONNECTION_CHANGED_ACTION这个消息并且更新UI为已连接状态。GroupCreatedState代码比较简单,感兴趣可以自行分析,到此P2P的主动连接已经结束。
P2P主动连接的时序图如图6:
3.4.2Wifi Direct的Provision Discovery流程
P2P规范定义Provision Discovery流程,为了是确定两个P2P Device交互双方适用的WSC方法,只有在双方适用相同的WSC配置方法才能建立P2P Group。
前文分析知道,当P2pStateMachine的ProvisionDiscoveryState发送P2P_PROV_DISC命令给WPAS时便启动了Provision Discovery流程。
Provision Discovery流程可以分为三个步骤:PD Request帧的发送流程(时序图1~9)、Action帧的接收流程(时序图10~19)以及PD Response帧的处理流程。Provision Discovery流程时序图如下图7所示:
PD Request帧最终通过p2p_send_action()函数发送出去,p2p_send_action()将涉及off channel发送以及处理对应的netlink消息的过程。
PD Response帧属于Public Action帧的一种,PD Response帧主要有两种帧:对端设备发来的PD Response帧以及本机设备发送的管理帧TX Report,详细请分析process_bss_event()函数。无论是代表由本机发送的管理帧TX Report帧(NL80211_CMD_FRME_TX_STATUS)还是代表本机接收到的对端神杯发来的管理时间的帧(NL80211_CMD_FRME)最终都会调用mlme_event()函数。
PD Response帧处理流程主要做的工作:
1)解析PD Response帧,判断PD Response帧返回的WSC方法是否与所要求的WSC方法一致。
2)调用wpas_prov_disc_resp()发消息给客户端。对于前面提到的WSC PBC方式而言,wpas将发送P2P_EVENT_PROV_DISC_PBC_RESP消息给客户端。
3.4.3Wifi Direct的GO Negotiation流程
由3.3.1节分析知道P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,将会通过ProvisionDiscoveryState中调用p2pConnectWithPinDisplay()函数,该函数内部将发送命令P2P_CONNECT给WPAS开始GO Negotiation流程。
GO Negotiation流程主要有四个过程:P2P_CONNECT处理流程、GON Request帧发送流程、GON Request帧处理流程以及EVENT_TX_STATUS处理流程。
图8为P2P_CONNECT处理和GON Request帧的发送流程。
对端设备设备根据接收到的GON Request帧回复GON Response帧,由前文分析知道GON Request帧将在p2p_process_go_neg_resp()函数负责处理。这段代码比较复杂暂且不进行分析,如果感兴趣自行分析。
当GON Confirmation帧发送出去后,wifi driver将向WPAS发送一个NL80211_CMD_FRAME _TX_STATUS,该消息直接导致driver wrapper发送EVENT_TX_STATUS消息给WPAS。图9为EVENT_TX_STATUS消息的处理流程:
当Group Negotiation完成后,WPAS将创建一个wpa_supplicant对象,它将用于管理和操作专门用于P2P Group的virtual interface(在GON Request帧发送过程创建)。一个interface对应一个wpa _supplicant对象,如果wpa_supplicant对象为GO角色,其MAC地址为P2P interface address;如果wpa_supplicant对象用于非P2P Group操作,其MAC地址为P2P Device address.