在Android11 wifi连接流程中我们代码跟踪到了supplicant中开始associate,关联成功以后就是四次握手然后连接成功。连接成功以后还需要分配IP地址,才可以通信,这一节我们看一下IP地址的获取流程。
一、在ClientModeImpl中有一个函数startIpClient。这个函数会在俩个地方被调用,一个是连接的时候ConnectModeState,一个是连接成功以后进入ObtainingIpState。这俩个地方的区别就是isFilsConnection的不同,连接过程中isFilsConnection为true,把IPClinet先关掉。如果isFilsConnection为flase,则开始处理IP地址分配。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
这里我们先看是怎么进入ObtainingIpState的
SupplicantStaIfaceHal中注册了一个Supplicant的回调函数,当supplicant的状态发生改变时这里就会监听到,然后WifiMonitor就会发送statechange的广播。
private class SupplicantVendorStaIfaceHalCallback extends ISupplicantVendorStaIfaceCallback.Stub {
private String mIfaceName;
private SupplicantStaIfaceHalCallback mSupplicantStaIfacecallback;
SupplicantVendorStaIfaceHalCallback(@NonNull String ifaceName, SupplicantStaIfaceHalCallback callback) {
mIfaceName = ifaceName;
mSupplicantStaIfacecallback = callback;
}
@Override
public void onVendorStateChanged(int newState, byte[/* 6 */] bssid, int id,
ArrayList<Byte> ssid, boolean filsHlpSent) {
synchronized (mLock) {
logCallback("onVendorStateChanged");
SupplicantState newSupplicantState =
SupplicantStaIfaceCallbackImpl.supplicantHidlStateToFrameworkState(newState);
WifiSsid wifiSsid = // wifigbk++
WifiGbk.createWifiSsidFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
String bssidStr = NativeUtil.macAddressFromByteArray(bssid);
if (newSupplicantState == SupplicantState.COMPLETED) {
mWifiMonitor.broadcastNetworkConnectionEvent(
mIfaceName, getCurrentNetworkId(mIfaceName), filsHlpSent, bssidStr);
}
mWifiMonitor.broadcastSupplicantStateChangeEvent(
mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid, bssidStr, newSupplicantState);
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
public void broadcastNetworkConnectionEvent(String iface, int networkId, boolean filsHlpSent,
String bssid) {
sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, filsHlpSent ? 1 : 0, bssid);
}
此时wifi状态机还在ConnectModeState,对于NETWORK_CONNECTION_EVENT的处理结果就是跳转到ObtainingIpState
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (mVerboseLoggingEnabled) log("Network connection established");
mLastNetworkId = message.arg1;
mSentHLPs = message.arg2 == 1;
if (mSentHLPs) mWifiMetrics.incrementL2ConnectionThroughFilsAuthCount();
mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
mLastBssid = (String) message.obj;
reasonCode = message.arg2;
// TODO: This check should not be needed after ClientModeImpl refactor.
// Currently, the last connected network configuration is left in
// wpa_supplicant, this may result in wpa_supplicant initiating connection
// to it after a config store reload. Hence the old network Id lookups may not
// work, so disconnect the network and let network selector reselect a new
// network.
config = getCurrentWifiConfiguration();
if (config != null) {
if (mWifiConfigManager.saveAutoConnectedNewNetwork(config.networkId)) {
Log.i(TAG, "Successfully connected to new network " + config.getPrintableSsid());
mAutoConnectNewNetworkResultNotifier.onConnectionAttemptSuccess(config.SSID);
}
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
if (scanDetailCache != null && mLastBssid != null) {
ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
if (scanResult != null) {
updateConnectedBand(scanResult.frequency, true);
}
}
// We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA'
if (config.enterpriseConfig != null
&& config.enterpriseConfig.isAuthenticationSimBased()) {
mLastSubId = mWifiCarrierInfoManager.getBestMatchSubscriptionId(config);
mLastSimBasedConnectionCarrierName =
mWifiCarrierInfoManager.getCarrierNameforSubId(mLastSubId);
String anonymousIdentity =
mWifiNative.getEapAnonymousIdentity(mInterfaceName);
if (!TextUtils.isEmpty(anonymousIdentity)
&& !WifiCarrierInfoManager
.isAnonymousAtRealmIdentity(anonymousIdentity)) {
String decoratedPseudonym = mWifiCarrierInfoManager
.decoratePseudonymWith3GppRealm(config,
anonymousIdentity);
if (decoratedPseudonym != null) {
anonymousIdentity = decoratedPseudonym;
}
if (mVerboseLoggingEnabled) {
log("EAP Pseudonym: " + anonymousIdentity);
}
// Save the pseudonym only if it is a real one
config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
} else {
// Clear any stored pseudonyms
config.enterpriseConfig.setAnonymousIdentity(null);
}
mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
}
mIpReachabilityMonitorActive = true;
transitionTo(mObtainingIpState);
} else {
logw("Connected to unknown networkId " + mLastNetworkId
+ ", disconnecting...");
sendMessage(CMD_DISCONNECT);
}
在ObtainingIpState进入时就会开启IPClient,注意这里if (mIpClientWithPreConnection && mIpClient != null) {
这个判断条件一定是不成立的,因为在连接时执行过stopIpClient。
class ObtainingIpState extends State {
@Override
public void enter() {
// Reset power save mode after association.
// Kernel does not forward power save request to driver if power
// save state of that interface is same as requested state in
// cfg80211. This happens when driver’s power save state not
// synchronized with cfg80211 power save state.
// By resetting power save state resolves issues of cfg80211
// ignoring enable power save request sent in ObtainingIpState.
mWifiNative.setPowerSave(mInterfaceName, false);
WifiConfiguration currentConfig = getCurrentWifiConfiguration();
if (mIpClientWithPreConnection && mIpClient != null) {
mIpClient.notifyPreconnectionComplete(mSentHLPs);
mIpClientWithPreConnection = false;
mSentHLPs = false;
} else {
startIpClient(currentConfig, false);
}
// Get Link layer stats so as we get fresh tx packet counters
getWifiLinkLayerStats();
}
二、接着我们再看startIpClient的具体内容。
private boolean startIpClient(WifiConfiguration config, boolean isFilsConnection) {
final boolean isUsingStaticIp =
(config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
final boolean isUsingMacRandomization =
config.macRandomizationSetting
== WifiConfiguration.RANDOMIZATION_PERSISTENT
&& isConnectedMacRandomizationEnabled();
if (isFilsConnection) {
stopIpClient();
if (isUsingStaticIp) {
mWifiNative.flushAllHlp(mInterfaceName);
return false;
}
setConfigurationsPriorToIpClientProvisioning(config);
final ProvisioningConfiguration.Builder prov =
new ProvisioningConfiguration.Builder()
.withPreDhcpAction()
.withPreconnection()
.withApfCapabilities(
mWifiNative.getApfCapabilities(mInterfaceName))
.withLayer2Information(layer2Info);
if (isUsingMacRandomization) {
// Use EUI64 address generation for link-local IPv6 addresses.
prov.withRandomMacAddress();
}
mIpClient.startProvisioning(prov.build());
} else {
sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR);
clearTargetBssid("ObtainingIpAddress");
stopDhcpSetup();
setConfigurationsPriorToIpClientProvisioning(config);
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
ScanResult scanResult = null;
if (mLastBssid != null) {
if (scanDetailCache != null) {
scanResult = scanDetailCache.getScanResult(mLastBssid);
}
if (scanResult == null) {
ScanRequestProxy scanRequestProxy = mWifiInjector.getScanRequestProxy();
List<ScanResult> scanResults = scanRequestProxy.getScanResults();
for (ScanResult result : scanResults) {
if (result.SSID.equals(WifiInfo.removeDoubleQuotes(config.SSID))
&& result.BSSID.equals(mLastBssid)) {
scanResult = result;
break;
}
}
}
}
final ProvisioningConfiguration.Builder prov;
ProvisioningConfiguration.ScanResultInfo scanResultInfo = null;
if (scanResult != null) {
final List<ScanResultInfo.InformationElement> ies =
new ArrayList<ScanResultInfo.InformationElement>();
for (ScanResult.InformationElement ie : scanResult.getInformationElements()) {
ScanResultInfo.InformationElement scanResultInfoIe =
new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes());
ies.add(scanResultInfoIe);
}
scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID,
scanResult.BSSID, ies);
}
if (!isUsingStaticIp) {
prov = new ProvisioningConfiguration.Builder()
.withPreDhcpAction()
.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
.withNetwork(getCurrentNetwork())
.withDisplayName(config.SSID)
.withScanResultInfo(scanResultInfo)
.withLayer2Information(layer2Info);
} else {
StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
prov = new ProvisioningConfiguration.Builder()
.withStaticConfiguration(staticIpConfig)
.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
.withNetwork(getCurrentNetwork())
.withDisplayName(config.SSID)
.withLayer2Information(layer2Info);
}
if (isUsingMacRandomization) {
// Use EUI64 address generation for link-local IPv6 addresses.
prov.withRandomMacAddress();
}
mIpClient.startProvisioning(prov.build());
}
return true;
}
三、IpClientManager通过aidl与IPClinet模块通信。
frameworks/base/services/net/java/android/net/ip/IpClientManager.java
public class IpClientManager {
@NonNull private final IIpClient mIpClient;
@NonNull private final String mTag;
public IpClientManager(@NonNull IIpClient ipClient, @NonNull String tag) {
mIpClient = ipClient;
mTag = tag;
}
IPClinet会发送CMD_START信息,然后会进入StartedState。
frameworks/base/packages/NetworkStack/src/android/net/ip/IpClient.java
public void startProvisioning(ProvisioningConfiguration req) {
if (!req.isValid()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
return;
}
mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
if (mInterfaceParams == null) {
logError("Failed to find InterfaceParams for " + mInterfaceName);
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
return;
}
mCallback.setNeighborDiscoveryOffload(true);
sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
}
最后进入了RunningState。在这里会开始Ipv6和Ipv4
class RunningState extends State {
private ConnectivityPacketTracker mPacketTracker;
private boolean mDhcpActionInFlight;
@Override
public void enter() {
ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
apfConfig.multicastFilter = mMulticastFiltering;
// Get the Configuration for ApfFilter from Context
apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
mCallback.setFallbackMulticastFilter(mMulticastFiltering);
}
mPacketTracker = createPacketTracker();
if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
if (mConfiguration.mEnableIPv6 && !startIPv6()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
enqueueJumpToStoppingState();
return;
}
if (mConfiguration.mEnableIPv4 && !startIPv4()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
enqueueJumpToStoppingState();
return;
}
final InitialConfiguration config = mConfiguration.mInitialConfig;
if ((config != null) && !applyInitialConfig(config)) {
// TODO introduce a new IpManagerEvent constant to distinguish this error case.
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
enqueueJumpToStoppingState();
return;
}
if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
doImmediateProvisioningFailure(
IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
enqueueJumpToStoppingState();
return;
}
}
这里会发送广播CMD_START_DHCP给DHCPClinet。到了这一步就和Android11 DHCP流程接上了。
private boolean startIPv4() {
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
if (mConfiguration.mStaticIpConfig != null) {
if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
return false;
}
} else {
// Start DHCPv4.
mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
mDhcpClient.registerForPreDhcpNotification();
if (mConfiguration.mRapidCommit || mConfiguration.mDiscoverSent)
mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP_RAPID_COMMIT,
(mConfiguration.mRapidCommit ? 1: 0),
(mConfiguration.mDiscoverSent ? 1: 0));
else
mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
}
return true;
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有