Android11 Wifi连接流程之IP地址分配

news/2025/1/1 7:52:56/

在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;}@Overridepublic 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 oneconfig.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);} else {// Clear any stored pseudonymsconfig.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 {@Overridepublic 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 countersgetWifiLinkLayerStats();}

二、接着我们再看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;@Overridepublic void enter() {ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;apfConfig.multicastFilter = mMulticastFiltering;// Get the Configuration for ApfFilter from ContextapfConfig.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));elsemDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);}return true;}

http://www.ppmy.cn/news/775915.html

相关文章

android 获取IP地址

https://blog.csdn.net/Alexlee1986/article/details/96120439 android获取ip地址方法 1、wifi下获取本地局域网IP地址2、移动网络获取网络IP地址3、获取外网地址3.1 通过pv.sohu.com获取3.2 通过api.ipify.org获取android获取IP地址的方法总结如下: 1、wifi下获取本地局域网…

linux-设置静态IP地址

linux-设置静态IP地址手动连接 修改/etc/network/interfaces文件&#xff1a; auto wlan0 //自动开启wlan0 iface wlan0 inet static //设置wlan0为静态获取IP address 192.168.1.177 //IP地址 gateway 192.168.1.1 //网关 netmask 255.255.255.0 //子网掩码修改/etc/resolv.c…

Linux设置固定IP连接wifi

环境&#xff1a;TPU上的Debian系统 设置固定IP 参考&#xff1a;https://blog.csdn.net/nzjdsds/article/details/77197246 例如想要设置网络的信息如下 IP地址&#xff1a;10.10.10.155 子网掩码&#xff1a;255.255.255.0 网关&#xff1a;10.10.10.2 广播地址&#xff1a…

Android获取手机WiFi IP地址,MAC地址和网关地址程序实例

现在博主在上大三&#xff0c;正在学习一些计算机网络的一些概念&#xff0c;知道了局域网ip和网关ip不同的概念&#xff0c;当时还纳了闷了2的32次方好像不咋够用啊&#xff0c;原来是这个样子。 由于之前学过一段时间的Android&#xff0c;同时又在上Android开发的个性课&am…

两台计算机能否共用一个ip地址,多台电脑共用一个WIFI,IP地址是不是一样?

网友解答: “我是哟哟吼&#xff0c;专注于数据网络的解答&#xff0c;欢迎大家与我交流数据网络的问题。” 如题&#xff0c;如果说私网IP地址&#xff0c;那么多台电脑的IP地址均不一样&#xff1b;如果说公网IP地址&#xff0c;那么多台电脑的IP地址会被路由器NAT成同一个IP…

办公室最经常用到的WIFI ip地址设置(window10)

1. 打开网络和Internet配置。点击电脑图标&#xff0c;鼠标右键&#xff0c;出现这个标志 2. 点击更改适配器选项。 3. 点击以太网 4.点击属性 5.用鼠标双击Internet协议版本&#xff08;TCP/Ipv4)&#xff0c;一定要双击&#xff01; 6. 然后在这里你就能自由配置你的路由信息…

树莓派WiFi设置固定IP地址

陈拓 2021/04/25-2021/04/25 树莓派开启WiFi 见《电脑连接树莓派3B》 https://zhuanlan.zhihu.com/p/40500429 https://blog.csdn.net/chentuo2000/article/details/103332186 通过WiFi登录树莓派&#xff0c;查看网络接口 wlan0在192.168.3网段上。 设置树莓派设置固定I…

Android~获取WiFi MAC地址和IP方法汇总

最近由于项目需求&#xff0c;需要获取手机WiFi的MAC地址和IP&#xff0c;于是乎网上搜罗了一波。各种版本的都有&#xff0c;各种方法都有&#xff0c;而且安卓6.0以下、6.0~7.0、7.0以上版本差异都很大&#xff01;在这里我就集中给归一下类&#xff0c;方便以后查阅。 1. 归…