diff options
author | Vamsi Krishna <quic_vamsin@quicinc.com> | 2019-12-13 11:02:27 +0530 |
---|---|---|
committer | Sunil Ravi <sunilravi@google.com> | 2020-02-20 15:04:34 -0800 |
commit | 853857e57a4595ab67345fc8a198bb7b06e2aa0b (patch) | |
tree | 1d59c3027896e72544118862253cd3d1f3a6136f /service | |
parent | 40369495ec8f3fc06f655d3dd2ab07ae4844c130 (diff) |
STA: Add support to connect to FILS enabled APs
Fast Initial Link Setup (FILS) feature defined in 802.11ai specifications
provides means to make faster reconnections with APs within a realm using
EAP-Reauthentication Protocol (ERP). When a STA connecting initially to an
enterprise AP on which FILS is enabled, does full 802.1x EAP handshakes and
generates ERP keys. The STA uses the ERP keys (until they are expired) in
subsequent connections to the enterprise APs within same realm as that of
the AP with which the STA has generated ERP keys to EAP-ERP process to
make connection faster. The EAP-ERP request and EAP-ERP response frames
will be exchanged via 802.11 authentication frames between STA and AP.
More details of EAP-ERP can be found at https://tools.ietf.org/html/rfc6696
FILS specifications defines two AKM suites FILS-SHA256 and FILS-SHA384 for
normal connection and two more AKM suites FILS-FT-SHA256 and FILS-FT-SHA384
for FT connections.
The first connection without using ERP keys uses open auth algorithm and
connects using full eap handshake and the subsequent connections with ERP
keys uses FILS auth algorithm.
DHCP with rapid commit optimizes the DHCP packet exchange. When using rapid
commit feature, DHCP server responds with DHCP ACK packet when it receives
DHCP discover packet. More details of DHCP with rapid commit can be found
at https://tools.ietf.org/html/rfc4039.
The DHCP discover and DHCP ACK packets can be sent with Association
request frame and Association response frame using HLP feature defined in
FILS protocol in order to get the IP address quickly.
When connecting to a FILS AP, start the DHCP client withPreConnection
option set to true before sending connect request to wpa_supplicant. DHCP
client will form discover packet and sends it to Wi-Fi module, then the
DHCP client moves to listen state to be able to receive and process
DHCP ACK or DHCP Offer packets. After receiving DHCP discover packet
from DHCP client, configure DHCP discover packet as HLP packet to
wpa_supplicant and then issue connect request to wpa_supplicant with
appropriate FILS AKM suite. The ERP config option also needs to be enabled
so that wpa_supplicant generates ERP keys while connecting to FILS APs.
If the STA is already connected to a different AP when wpa_supplicant
receives the connect request to the FILS AP, wpa_supplicant disconnects
with that AP before connecting to FILS AP and sends a disconnection event
to frameworks. Do not stop IpClient when disconnection event is received
if FILS connection is in progress, as the IpClient is started for ongoing
FILS connection.
If STA does not have ERP keys required for FILS connection or if the AP is
rejecting the connection in FILS mode probably because of AP not having ERP
keys, then STA will connect to FILS AP with open auth algorithm using full
802.1x EAP handshake. In these cases wpa_supplicant doesn't include HLP IEs
in connect request. Wpa_supplicant notifies framework through connection
event whether it sent HLP IEs to AP or not in the connection request. When
HLP IEs are not sent in association request frame, abort pre-DHCP
connection. When pre-DHCP connection is aborted, DHCP client transitions to
dhcpInit state and sends DHCP discover packet to AP through data path.
If STA has ERP keys, it will send the DHCP discover packet using HLP IEs
in Association Request frame. AP may respond in three ways.
1. AP may not send any DHCP packet uisng HLP IEs in Association Response
frame if the DHCP server doesn't send response within a time less than
802.11 mgmt. timeout. In this case, AP sends the DHCP packet as a data
packet after sending out Association Response frame.
2. AP may send a DHCP ACK packet using HLP IEs in Association Response
frame if the DHCP server supports DHCP with Rapid Commit feature and
sends response within a time less than 802.11 mgmt. timeout.
3. AP may send a DHCP OFFER packet using HLP IEs in Association Response
frame if the DHCP server doesn't support DHCP with Rapid Commit feature and
sends response within a time less than 802.11 mgmt. timeout.
Bug: 143259898
Test: atest.
Test: Basic wifi sanity.
Change-Id: Ib42eb5295fa2403d5a98ceddb15f501c130b61e5
Diffstat (limited to 'service')
10 files changed, 641 insertions, 164 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 4b3732f22..86d799b41 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -18,6 +18,8 @@ package com.android.server.wifi; import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT; import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY; +import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256; +import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; @@ -40,6 +42,7 @@ import android.net.DhcpResultsParcelable; import android.net.InvalidPacketException; import android.net.IpConfiguration; import android.net.KeepalivePacketData; +import android.net.Layer2PacketParcelable; import android.net.LinkProperties; import android.net.MacAddress; import android.net.MatchAllNetworkSpecifier; @@ -611,6 +614,8 @@ public class ClientModeImpl extends StateMachine { private static final int CMD_SAVE_NETWORK = BASE + 259; private static final int CMD_PKT_CNT_FETCH = BASE + 261; + /* Start connection to FILS AP*/ + static final int CMD_START_FILS_CONNECTION = BASE + 262; // For message logging. private static final Class[] sMessageClasses = { AsyncChannel.class, ClientModeImpl.class }; @@ -678,6 +683,14 @@ public class ClientModeImpl extends StateMachine { /* Network is not connected, supplicant assoc+auth is not complete */ private State mDisconnectedState = new DisconnectedState(); + /* + * FILS connection related variables. + */ + /* To indicate to IpClient whether HLP IEs were included or not in assoc request */ + private boolean mSentHLPs = false; + /* Tracks IpClient start state until (FILS_)NETWORK_CONNECTION_EVENT event */ + private boolean mIpClientWithPreConnection = false; + /** * One of {@link WifiManager#WIFI_STATE_DISABLED}, * {@link WifiManager#WIFI_STATE_DISABLING}, @@ -878,6 +891,8 @@ public class ClientModeImpl extends StateMachine { getHandler()); mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT, getHandler()); + mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.FILS_NETWORK_CONNECTION_EVENT, + getHandler()); mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT, getHandler()); mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT, @@ -1013,6 +1028,11 @@ public class ClientModeImpl extends StateMachine { } @Override + public void onPreconnectionStart(List<Layer2PacketParcelable> packets) { + sendMessage(CMD_START_FILS_CONNECTION, 0, 0, packets); + } + + @Override public void onQuit() { mWaitForStopCv.open(); } @@ -1027,11 +1047,23 @@ public class ClientModeImpl extends StateMachine { } private void stopIpClient() { - /* Restore power save and suspend optimizations */ - handlePostDhcpSetup(); + if (mVerboseLoggingEnabled) { + log("stopIpClient IpClientWithPreConnection: " + mIpClientWithPreConnection); + } if (mIpClient != null) { + if (mIpClientWithPreConnection) { + mIpClient.notifyPreconnectionComplete(false); + } mIpClient.stop(); } + mIpClientWithPreConnection = false; + mSentHLPs = false; + } + + private void stopDhcpSetup() { + /* Restore power save and suspend optimizations */ + handlePostDhcpSetup(); + stopIpClient(); } /** @@ -1897,6 +1929,7 @@ public class ClientModeImpl extends StateMachine { } sb.append(" blacklist=" + Boolean.toString(mDidBlackListBSSID)); break; + case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT: case WifiMonitor.NETWORK_CONNECTION_EVENT: sb.append(" "); sb.append(Integer.toString(msg.arg1)); @@ -2162,6 +2195,9 @@ public class ClientModeImpl extends StateMachine { case WifiMonitor.NETWORK_CONNECTION_EVENT: s = "NETWORK_CONNECTION_EVENT"; break; + case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT: + s = "FILS_NETWORK_CONNECTION_EVENT"; + break; case WifiMonitor.NETWORK_DISCONNECTION_EVENT: s = "NETWORK_DISCONNECTION_EVENT"; break; @@ -2620,7 +2656,7 @@ public class ClientModeImpl extends StateMachine { */ private void handleNetworkDisconnect() { if (mVerboseLoggingEnabled) { - log("handleNetworkDisconnect: Stopping DHCP and clearing IP" + log("handleNetworkDisconnect:" + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() @@ -2637,7 +2673,18 @@ public class ClientModeImpl extends StateMachine { clearTargetBssid("handleNetworkDisconnect"); - stopIpClient(); + // Don't stop DHCP if Fils connection is in progress. + if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID + && mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID + && mLastNetworkId != mTargetNetworkId && mIpClientWithPreConnection) { + if (mVerboseLoggingEnabled) { + log("handleNetworkDisconnect: Don't stop IpClient as fils connection in progress: " + + " mLastNetworkId: " + mLastNetworkId + + " mTargetNetworkId" + mTargetNetworkId); + } + } else { + stopDhcpSetup(); + } /* Reset data structures */ mWifiScoreReport.reset(); @@ -2712,6 +2759,21 @@ public class ClientModeImpl extends StateMachine { } } + void addLayer2PacketsToHlpReq(List<Layer2PacketParcelable> packets) { + List<Layer2PacketParcelable> mLayer2Packet = packets; + if ((mLayer2Packet != null) && (mLayer2Packet.size() > 0)) { + mWifiNative.flushAllHlp(mInterfaceName); + + for (int j = 0; j < mLayer2Packet.size(); j++) { + byte [] bytes = mLayer2Packet.get(j).payload; + byte [] payloadBytes = Arrays.copyOfRange(bytes, 12, bytes.length); + MacAddress dstAddress = mLayer2Packet.get(j).dstMacAddress; + + mWifiNative.addHlpReq(mInterfaceName, dstAddress, payloadBytes); + } + } + } + void handlePostDhcpSetup() { /* Restore power save and suspend optimizations */ setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); @@ -3269,6 +3331,7 @@ public class ClientModeImpl extends StateMachine { case CMD_RECONNECT: case CMD_REASSOCIATE: case WifiMonitor.NETWORK_CONNECTION_EVENT: + case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT: case WifiMonitor.NETWORK_DISCONNECTION_EVENT: case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: @@ -3482,6 +3545,7 @@ public class ClientModeImpl extends StateMachine { * Helper method to stop external services and clean up state from client mode. */ private void stopClientMode() { + handleNetworkDisconnect(); // exiting supplicant started state is now only applicable to client mode mWifiDiagnostics.stopLogging(mInterfaceName); @@ -3558,6 +3622,26 @@ public class ClientModeImpl extends StateMachine { return mLastBssid; } + void connectToNetwork(WifiConfiguration config) { + if ((config != null) && mWifiNative.connectToNetwork(mInterfaceName, config)) { + mWifiInjector.getWifiLastResortWatchdog().noteStartConnectTime(); + mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config); + mLastConnectAttemptTimestamp = mClock.getWallClockMillis(); + mIsAutoRoaming = false; + if (getCurrentState() != mDisconnectedState) { + transitionTo(mDisconnectingState); + } + } else { + loge("CMD_START_CONNECT Failed to start connection to network " + config); + mTargetWifiConfiguration = null; + stopIpClient(); + reportConnectionAttemptEnd( + WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED, + WifiMetricsProto.ConnectionEvent.HLF_NONE, + WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN); + } + } + class ConnectModeState extends State { @Override @@ -3626,6 +3710,7 @@ public class ClientModeImpl extends StateMachine { WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN; switch (message.what) { case WifiMonitor.ASSOCIATION_REJECTION_EVENT: + stopIpClient(); mWifiDiagnostics.captureBugReportData( WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE); mDidBlackListBSSID = false; @@ -3663,6 +3748,7 @@ public class ClientModeImpl extends StateMachine { } break; case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: + stopIpClient(); mWifiDiagnostics.captureBugReportData( WifiDiagnostics.REPORT_REASON_AUTH_FAILURE); int disableReason = WifiConfiguration.NetworkSelectionStatus @@ -3843,6 +3929,7 @@ public class ClientModeImpl extends StateMachine { netId = message.arg1; int uid = message.arg2; bssid = (String) message.obj; + mSentHLPs = false; if (!hasConnectionRequests()) { if (mNetworkAgent == null) { @@ -3864,60 +3951,44 @@ public class ClientModeImpl extends StateMachine { loge("CMD_START_CONNECT and no config, bail out..."); break; } + mTargetNetworkId = netId; // Update scorecard while there is still state from existing connection int scanRssi = mWifiConfigManager.findScanRssi(netId, SCAN_RSSI_VALID_TIME_MS); mWifiScoreCard.noteConnectionAttempt(mWifiInfo, scanRssi, config.SSID); - mTargetNetworkId = netId; - setTargetBssid(config, bssid); mBssidBlocklistMonitor.updateFirmwareRoamingConfiguration(config.SSID); + updateWifiConfigOnStartConnection(config, bssid); + reportConnectionAttemptStart(config, mTargetRoamBSSID, WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED); - if (config.macRandomizationSetting - == WifiConfiguration.RANDOMIZATION_PERSISTENT - && isConnectedMacRandomizationEnabled()) { - configureRandomizedMacAddress(config); - } else { - setCurrentMacToFactoryMac(config); - } String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName); mWifiInfo.setMacAddress(currentMacAddress); Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address"); - if (config.enterpriseConfig != null - && config.enterpriseConfig.isAuthenticationSimBased() - && mTelephonyUtil.isImsiEncryptionInfoAvailable( - mTelephonyUtil.getBestMatchSubscriptionId(config)) - && TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) { - String anonAtRealm = mTelephonyUtil - .getAnonymousIdentityWith3GppRealm(config); - // Use anonymous@<realm> when pseudonym is not available - config.enterpriseConfig.setAnonymousIdentity(anonAtRealm); - } - - if (isWpa3SaeUpgradeEnabled() && config.allowedKeyManagement.get( - WifiConfiguration.KeyMgmt.WPA_PSK)) { - config = upgradeToWpa3IfPossible(config); - } + mTargetWifiConfiguration = config; + /* Check for FILS configuration again after updating the config */ + if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256) + || config.allowedKeyManagement.get( + WifiConfiguration.KeyMgmt.FILS_SHA384)) { - if (mWifiNative.connectToNetwork(mInterfaceName, config)) { - mWifiInjector.getWifiLastResortWatchdog().noteStartConnectTime(); - mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config); - mLastConnectAttemptTimestamp = mClock.getWallClockMillis(); - mTargetWifiConfiguration = config; - mIsAutoRoaming = false; - if (getCurrentState() != mDisconnectedState) { - transitionTo(mDisconnectingState); + boolean isIpClientStarted = startIpClient(config, true); + if (isIpClientStarted) { + mIpClientWithPreConnection = true; + break; } - } else { - loge("CMD_START_CONNECT Failed to start connection to network " + config); - reportConnectionAttemptEnd( - WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED, - WifiMetricsProto.ConnectionEvent.HLF_NONE, - WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN); - break; } + connectToNetwork(config); + break; + case CMD_START_FILS_CONNECTION: + List<Layer2PacketParcelable> packets; + packets = (List<Layer2PacketParcelable>) message.obj; + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Send HLP IEs to supplicant"); + } + addLayer2PacketsToHlpReq(packets); + config = mTargetWifiConfiguration; + connectToNetwork(config); break; case CMD_CONNECT_NETWORK: callbackIdentifier = message.arg2; @@ -3988,6 +4059,8 @@ public class ClientModeImpl extends StateMachine { } handleStatus = NOT_HANDLED; break; + case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT: + mSentHLPs = true; case WifiMonitor.NETWORK_CONNECTION_EVENT: if (mVerboseLoggingEnabled) log("Network connection established"); mLastNetworkId = message.arg1; @@ -4161,6 +4234,14 @@ public class ClientModeImpl extends StateMachine { final boolean enabled = (message.arg1 > 0); mWifiNative.configureNeighborDiscoveryOffload(mInterfaceName, enabled); break; + case CMD_PRE_DHCP_ACTION: + case CMD_PRE_DHCP_ACTION_COMPLETE: + case CMD_POST_DHCP_ACTION: + case CMD_IPV4_PROVISIONING_SUCCESS: + case CMD_IP_CONFIGURATION_SUCCESSFUL: + case CMD_IPV4_PROVISIONING_FAILURE: + handleStatus = handleL3MessagesWhenNotConnected(message); + break; default: handleStatus = NOT_HANDLED; break; @@ -4174,6 +4255,38 @@ public class ClientModeImpl extends StateMachine { } } + private boolean handleL3MessagesWhenNotConnected(Message message) { + boolean handleStatus = HANDLED; + + if (!mIpClientWithPreConnection) { + return NOT_HANDLED; + } + + switch (message.what) { + case CMD_PRE_DHCP_ACTION: + handlePreDhcpSetup(); + break; + case CMD_PRE_DHCP_ACTION_COMPLETE: + if (mIpClient != null) { + mIpClient.completedPreDhcpAction(); + } + break; + case CMD_IPV4_PROVISIONING_FAILURE: + stopDhcpSetup(); + deferMessage(message); + break; + case CMD_POST_DHCP_ACTION: + case CMD_IPV4_PROVISIONING_SUCCESS: + case CMD_IP_CONFIGURATION_SUCCESSFUL: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + + return handleStatus; + } + private WifiNetworkAgentSpecifier createNetworkAgentSpecifier( @NonNull WifiConfiguration currentWifiConfiguration, @Nullable String currentBssid) { currentWifiConfiguration.BSSID = currentBssid; @@ -4468,10 +4581,6 @@ public class ClientModeImpl extends StateMachine { @Override public void exit() { - if (mIpClient != null) { - mIpClient.stop(); - } - // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState // Bug: 15347363 // For paranoia's sake, call handleNetworkDisconnect @@ -4484,9 +4593,6 @@ public class ClientModeImpl extends StateMachine { sb.append(" ").append(mLastBssid); } } - if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { - handleNetworkDisconnect(); - } mCountryCode.setReadyForChange(true); mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED); mWifiStateTracker.updateState(WifiStateTracker.DISCONNECTED); @@ -4594,6 +4700,7 @@ public class ClientModeImpl extends StateMachine { } break; case WifiMonitor.NETWORK_CONNECTION_EVENT: + case WifiMonitor.FILS_NETWORK_CONNECTION_EVENT: mWifiInfo.setBSSID((String) message.obj); mLastNetworkId = message.arg1; mWifiInfo.setNetworkId(mLastNetworkId); @@ -4820,83 +4927,13 @@ public class ClientModeImpl extends StateMachine { class ObtainingIpState extends State { @Override public void enter() { - final WifiConfiguration currentConfig = getCurrentWifiConfiguration(); - final boolean isUsingStaticIp = - (currentConfig.getIpAssignment() == IpConfiguration.IpAssignment.STATIC); - if (mVerboseLoggingEnabled) { - final String key = currentConfig.getKey(); - log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) - + " " + key + " " - + " roam=" + mIsAutoRoaming - + " static=" + isUsingStaticIp); - } - - sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR); - - // We must clear the config BSSID, as the wifi chipset may decide to roam - // from this point on and having the BSSID specified in the network block would - // cause the roam to fail and the device to disconnect. - clearTargetBssid("ObtainingIpAddress"); - - // Stop IpClient in case we're switching from DHCP to static - // configuration or vice versa. - // - // When we transition from static configuration to DHCP in - // particular, we must tell ConnectivityService that we're - // disconnected, because DHCP might take a long time during which - // connectivity APIs such as getActiveNetworkInfo should not return - // CONNECTED. - stopIpClient(); - - if (mIpClient != null) { - mIpClient.setHttpProxy(currentConfig.getHttpProxy()); - if (!TextUtils.isEmpty(mContext.getResources().getString( - R.string.config_wifi_tcp_buffers))) { - mIpClient.setTcpBufferSizes(mContext.getResources().getString( - R.string.config_wifi_tcp_buffers)); - } - } - - WifiConfiguration config = getCurrentWifiConfiguration(); - ScanDetailCache scanDetailCache = - mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId); - ScanResult scanResult = null; - if (scanDetailCache != null && mLastBssid != null) { - scanResult = scanDetailCache.getScanResult(mLastBssid); - } - - final ProvisioningConfiguration 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, ies); - } - - if (!isUsingStaticIp) { - prov = new ProvisioningConfiguration.Builder() - .withPreDhcpAction() - .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)) - .withNetwork(getCurrentNetwork()) - .withDisplayName(currentConfig.SSID) - .withScanResultInfo(scanResultInfo) - .build(); + WifiConfiguration currentConfig = getCurrentWifiConfiguration(); + if (mIpClientWithPreConnection && mIpClient != null) { + mIpClient.notifyPreconnectionComplete(mSentHLPs); + mIpClientWithPreConnection = false; + mSentHLPs = false; } else { - StaticIpConfiguration staticIpConfig = currentConfig.getStaticIpConfiguration(); - prov = new ProvisioningConfiguration.Builder() - .withStaticConfiguration(staticIpConfig) - .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)) - .withNetwork(getCurrentNetwork()) - .withDisplayName(currentConfig.SSID) - .build(); - } - if (mIpClient != null) { - mIpClient.startProvisioning(prov); + startIpClient(currentConfig, false); } // Get Link layer stats so as we get fresh tx packet counters getWifiLinkLayerStats(); @@ -5434,6 +5471,7 @@ public class ClientModeImpl extends StateMachine { mWifiNative.disconnect(mInterfaceName); break; case WifiMonitor.NETWORK_DISCONNECTION_EVENT: + stopIpClient(); if (message.arg2 == 15 /* FOURWAY_HANDSHAKE_TIMEOUT */) { String bssid = (message.obj == null) ? mTargetRoamBSSID : (String) message.obj; @@ -6061,8 +6099,70 @@ public class ClientModeImpl extends StateMachine { } } - private WifiConfiguration upgradeToWpa3IfPossible(@NonNull WifiConfiguration config) { - if (isWpa3SaeUpgradeOffloadEnabled()) { + /** + * @return true if this device supports FILS-SHA256 + */ + private boolean isFilsSha256Supported() { + return (mWifiNative.getSupportedFeatureSet(mInterfaceName) & WIFI_FEATURE_FILS_SHA256) != 0; + } + + /** + * @return true if this device supports FILS-SHA384 + */ + private boolean isFilsSha384Supported() { + return (mWifiNative.getSupportedFeatureSet(mInterfaceName) & WIFI_FEATURE_FILS_SHA384) != 0; + } + + /** + * Helper method to set the allowed key management schemes from + * scan result. + */ + private void updateAllowedKeyManagementSchemesFromScanResult( + WifiConfiguration config, ScanResult scanResult) { + if (isFilsSha256Supported() + && ScanResultUtil.isScanResultForFilsSha256Network(scanResult)) { + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA256); + } + if (isFilsSha384Supported() + && ScanResultUtil.isScanResultForFilsSha384Network(scanResult)) { + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA384); + } + } + /** + * Update wifi configuration based on the matching scan result. + * + * @param config Wifi configuration object. + * @param scanResult Scan result matching the network. + */ + private void updateWifiConfigFromMatchingScanResult(WifiConfiguration config, + ScanResult scanResult) { + updateAllowedKeyManagementSchemesFromScanResult(config, scanResult); + if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256) + || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA384)) { + config.enterpriseConfig.setFieldValue(WifiEnterpriseConfig.EAP_ERP, "1"); + } + } + + /** + * Update the wifi configuration before sending connect to + * supplicant/driver. + * + * @param config wifi configuration object. + * @param bssid BSSID to assocaite with. + */ + void updateWifiConfigOnStartConnection(WifiConfiguration config, String bssid) { + boolean canUpgradePskToSae = false; + boolean isFrameworkWpa3SaeUpgradePossible = false; + boolean isLegacyWpa2ApInScanResult = false; + + setTargetBssid(config, bssid); + + if (isWpa3SaeUpgradeEnabled() && config.allowedKeyManagement.get( + WifiConfiguration.KeyMgmt.WPA_PSK)) { + isFrameworkWpa3SaeUpgradePossible = true; + } + + if (isFrameworkWpa3SaeUpgradePossible && isWpa3SaeUpgradeOffloadEnabled()) { // Driver offload of upgrading legacy WPA/WPA2 connection to WPA3 if (mVerboseLoggingEnabled) { Log.d(TAG, "Driver upgrade legacy WPA/WPA2 connection to WPA3"); @@ -6070,52 +6170,64 @@ public class ClientModeImpl extends StateMachine { config.allowedAuthAlgorithms.clear(); // Note: KeyMgmt.WPA2_PSK is already enabled, enable SAE as well config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE); - return config; + isFrameworkWpa3SaeUpgradePossible = false; } - - boolean canUpgradePskToSae = false; - // Check if network selection selected a good WPA3 candidate AP for a WPA2 // saved network. ScanResult scanResultCandidate = config.getNetworkSelectionStatus().getCandidate(); - if (scanResultCandidate != null) { + if (isFrameworkWpa3SaeUpgradePossible && scanResultCandidate != null) { ScanResultMatchInfo scanResultMatchInfo = ScanResultMatchInfo .fromScanResult(scanResultCandidate); if ((scanResultMatchInfo.networkType == WifiConfiguration.SECURITY_TYPE_SAE)) { canUpgradePskToSae = true; } else { // No SAE candidate - return config; + isFrameworkWpa3SaeUpgradePossible = false; } } - // Now check if there are any additional legacy WPA2 only APs in range. + /** + * Go through the matching scan results and update wifi config. + */ + ScanResultMatchInfo key1 = ScanResultMatchInfo.fromWifiConfiguration(config); ScanRequestProxy scanRequestProxy = mWifiInjector.getScanRequestProxy(); - for (ScanResult scanResult : scanRequestProxy.getScanResults()) { + List<ScanResult> scanResults = scanRequestProxy.getScanResults(); + for (ScanResult scanResult : scanResults) { if (!config.SSID.equals(ScanResultUtil.createQuotedSSID(scanResult.SSID))) { continue; } - if (ScanResultUtil.isScanResultForPskNetwork(scanResult) - && !ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { - // Found a legacy WPA2 AP in range. Do not upgrade the connection to WPA3 to - // allow seamless roaming within the ESS. - if (mVerboseLoggingEnabled) { - Log.d(TAG, "Found legacy WPA2 AP, do not upgrade to WPA3"); + if (isFrameworkWpa3SaeUpgradePossible && !isLegacyWpa2ApInScanResult) { + if (ScanResultUtil.isScanResultForPskNetwork(scanResult) + && !ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { + // Found a legacy WPA2 AP in range. Do not upgrade the connection to WPA3 to + // allow seamless roaming within the ESS. + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Found legacy WPA2 AP, do not upgrade to WPA3"); + } + isLegacyWpa2ApInScanResult = true; + canUpgradePskToSae = false; + } + if (ScanResultUtil.isScanResultForSaeNetwork(scanResult) + && scanResultCandidate == null) { + // When the user manually selected a network from the Wi-Fi picker, evaluate + // if to upgrade based on the scan results. The most typical use case during + // the WPA3 transition mode is to have a WPA2/WPA3 AP in transition mode. In + // this case, we would like to upgrade the connection. + canUpgradePskToSae = true; } - canUpgradePskToSae = false; - break; } - if (ScanResultUtil.isScanResultForSaeNetwork(scanResult) - && scanResultCandidate == null) { - // When the user manually selected a network from the Wi-Fi picker, evaluate - // if to upgrade based on the scan results. The most typical use case during - // the WPA3 transition mode is to have a WPA2/WPA3 AP in transition mode. In - // this case, we would like to upgrade the connection. - canUpgradePskToSae = true; + + ScanResultMatchInfo key2 = ScanResultMatchInfo.fromScanResult(scanResult); + if (!key1.equals(key2)) { + continue; } + updateWifiConfigFromMatchingScanResult(config, scanResult); } - if (canUpgradePskToSae) { + if (isFrameworkWpa3SaeUpgradePossible && canUpgradePskToSae + && !(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.FILS_SHA256) + || config.allowedKeyManagement.get( + WifiConfiguration.KeyMgmt.FILS_SHA384))) { // Upgrade legacy WPA/WPA2 connection to WPA3 if (mVerboseLoggingEnabled) { Log.d(TAG, "Upgrade legacy WPA/WPA2 connection to WPA3"); @@ -6123,6 +6235,121 @@ public class ClientModeImpl extends StateMachine { config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); } - return config; + if (config.macRandomizationSetting + == WifiConfiguration.RANDOMIZATION_PERSISTENT + && isConnectedMacRandomizationEnabled()) { + configureRandomizedMacAddress(config); + } else { + setCurrentMacToFactoryMac(config); + } + + if (config.enterpriseConfig != null + && config.enterpriseConfig.isAuthenticationSimBased() + && mTelephonyUtil.isImsiEncryptionInfoAvailable( + mTelephonyUtil.getBestMatchSubscriptionId(config)) + && TextUtils.isEmpty(config.enterpriseConfig.getAnonymousIdentity())) { + String anonAtRealm = mTelephonyUtil + .getAnonymousIdentityWith3GppRealm(config); + // Use anonymous@<realm> when pseudonym is not available + config.enterpriseConfig.setAnonymousIdentity(anonAtRealm); + } } + + private boolean startIpClient(WifiConfiguration config, boolean isFilsConnection) { + if (mIpClient == null) { + return false; + } + + final boolean isUsingStaticIp = + (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC); + if (mVerboseLoggingEnabled) { + final String key = config.getKey(); + log("startIpClient netId=" + Integer.toString(mLastNetworkId) + + " " + key + " " + + " roam=" + mIsAutoRoaming + + " static=" + isUsingStaticIp + + " isFilsConnection=" + isFilsConnection); + } + + if (isFilsConnection) { + stopIpClient(); + if (isUsingStaticIp) { + mWifiNative.flushAllHlp(mInterfaceName); + return false; + } + final ProvisioningConfiguration prov = + new ProvisioningConfiguration.Builder() + .withPreDhcpAction() + .withPreconnection() + .withApfCapabilities( + mWifiNative.getApfCapabilities(mInterfaceName)) + .build(); + mIpClient.startProvisioning(prov); + } else { + sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR); + // We must clear the config BSSID, as the wifi chipset may decide to roam + // from this point on and having the BSSID specified in the network block would + // cause the roam to fail and the device to disconnect. + clearTargetBssid("ObtainingIpAddress"); + + // Stop IpClient in case we're switching from DHCP to static + // configuration or vice versa. + // + // When we transition from static configuration to DHCP in + // particular, we must tell ConnectivityService that we're + // disconnected, because DHCP might take a long time during which + // connectivity APIs such as getActiveNetworkInfo should not return + // CONNECTED. + stopDhcpSetup(); + + mIpClient.setHttpProxy(config.getHttpProxy()); + if (!TextUtils.isEmpty(mContext.getResources().getString( + R.string.config_wifi_tcp_buffers))) { + mIpClient.setTcpBufferSizes(mContext.getResources().getString( + R.string.config_wifi_tcp_buffers)); + } + + ScanDetailCache scanDetailCache = + mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId); + ScanResult scanResult = null; + if (scanDetailCache != null && mLastBssid != null) { + scanResult = scanDetailCache.getScanResult(mLastBssid); + } + + final ProvisioningConfiguration 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, ies); + } + + if (!isUsingStaticIp) { + prov = new ProvisioningConfiguration.Builder() + .withPreDhcpAction() + .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)) + .withNetwork(getCurrentNetwork()) + .withDisplayName(config.SSID) + .withScanResultInfo(scanResultInfo) + .build(); + } else { + StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration(); + prov = new ProvisioningConfiguration.Builder() + .withStaticConfiguration(staticIpConfig) + .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName)) + .withNetwork(getCurrentNetwork()) + .withDisplayName(config.SSID) + .build(); + } + mIpClient.startProvisioning(prov); + } + + return true; + } + } diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java index 3d333c849..2d78514e4 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackImpl.java @@ -70,7 +70,7 @@ abstract class SupplicantStaIfaceCallbackImpl extends ISupplicantStaIfaceCallbac /** * Converts the supplicant state received from HIDL to the equivalent framework state. */ - private static SupplicantState supplicantHidlStateToFrameworkState(int state) { + protected static SupplicantState supplicantHidlStateToFrameworkState(int state) { switch (state) { case ISupplicantStaIfaceCallback.State.DISCONNECTED: return SupplicantState.DISCONNECTED; diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java index f3d72dc24..463881bbd 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java @@ -18,9 +18,13 @@ package com.android.server.wifi; import android.annotation.NonNull; import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; import android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback.BssTmData; +import android.net.wifi.SupplicantState; import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; import android.util.Log; +import com.android.server.wifi.util.NativeUtil; + import java.util.ArrayList; abstract class SupplicantStaIfaceCallbackV1_3Impl extends @@ -29,7 +33,9 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends private final SupplicantStaIfaceHal mStaIfaceHal; private final String mIfaceName; private final WifiMonitor mWifiMonitor; + private final SupplicantStaIfaceHal.SupplicantStaIfaceHalCallback mCallbackV10; private final SupplicantStaIfaceHal.SupplicantStaIfaceHalCallbackV1_2 mCallbackV12; + private boolean mStateIsFourwayV13 = false; // Used to help check for PSK password mismatch SupplicantStaIfaceCallbackV1_3Impl(@NonNull SupplicantStaIfaceHal staIfaceHal, @NonNull String ifaceName, @@ -40,6 +46,7 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends // Create an older callback for function delegation, // and it would cascadingly create older one. mCallbackV12 = mStaIfaceHal.new SupplicantStaIfaceHalCallbackV1_2(mIfaceName); + mCallbackV10 = mStaIfaceHal.new SupplicantStaIfaceHalCallback(mIfaceName); } @Override @@ -49,7 +56,9 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends @Override public void onNetworkRemoved(int id) { - mCallbackV12.onNetworkRemoved(id); + mStaIfaceHal.logCallback("onNetworkRemoved"); + // Reset 4way handshake state since network has been removed. + mStateIsFourwayV13 = false; } @Override @@ -86,7 +95,20 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends @Override public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) { - mCallbackV12.onDisconnected(bssid, locallyGenerated, reasonCode); + mStaIfaceHal.logCallback("onDisconnected"); + if (mStaIfaceHal.isVerboseLoggingEnabled()) { + Log.e(TAG, "onDisconnected 4way=" + mStateIsFourwayV13 + + " locallyGenerated=" + locallyGenerated + + " reasonCode=" + reasonCode); + } + if (mStateIsFourwayV13 + && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) { + mWifiMonitor.broadcastAuthenticationFailureEvent( + mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD, -1); + } + mWifiMonitor.broadcastNetworkDisconnectionEvent( + mIfaceName, locallyGenerated ? 1 : 0, reasonCode, + NativeUtil.macAddressFromByteArray(bssid)); } @Override @@ -333,7 +355,25 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends @Override public void onStateChanged_1_3(int newState, byte[/* 6 */] bssid, int id, ArrayList<Byte> ssid, boolean filsHlpSent) { - mCallbackV12.onStateChanged(newState, bssid, id, ssid); + mStaIfaceHal.logCallback("onStateChanged_1_3"); + SupplicantState newSupplicantState = + mCallbackV10.supplicantHidlStateToFrameworkState(newState); + WifiSsid wifiSsid = + WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid)); + String bssidStr = NativeUtil.macAddressFromByteArray(bssid); + mStateIsFourwayV13 = + (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE); + if (newSupplicantState == SupplicantState.COMPLETED) { + if (filsHlpSent) { + mWifiMonitor.broadcastFilsNetworkConnectionEvent( + mIfaceName, mStaIfaceHal.getCurrentNetworkId(mIfaceName), bssidStr); + } else { + mWifiMonitor.broadcastNetworkConnectionEvent( + mIfaceName, mStaIfaceHal.getCurrentNetworkId(mIfaceName), bssidStr); + } + } + mWifiMonitor.broadcastSupplicantStateChangeEvent( + mIfaceName, mStaIfaceHal.getCurrentNetworkId(mIfaceName), + wifiSsid, bssidStr, newSupplicantState); } - } diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java index bf2472935..717d0d7b5 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java @@ -16,6 +16,8 @@ package com.android.server.wifi; import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP; +import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256; +import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384; import static android.net.wifi.WifiManager.WIFI_FEATURE_MBO; import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE; import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; @@ -2129,6 +2131,88 @@ public class SupplicantStaIfaceHal { } /** + * Flush all previously configured HLPs. + * + * @param ifaceName Name of the interface. + * @return true if request is sent successfully, false otherwise. + */ + public boolean flushAllHlp(@NonNull String ifaceName) { + synchronized (mLock) { + final String methodStr = "filsHlpFlushRequest"; + if (isV1_3()) { + ISupplicantStaIface iface = + checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); + if (iface == null) { + return false; + } + + // Get a v1.3 supplicant STA Interface + android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = + getStaIfaceMockableV1_3(iface); + + if (staIfaceV13 == null) { + Log.e(TAG, methodStr + + ": ISupplicantStaIface is null, cannot flushAllHlp"); + return false; + } + try { + SupplicantStatus status = staIfaceV13.filsHlpFlushRequest(); + return checkStatusAndLogFailure(status, methodStr); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + return false; + } + } else { + Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); + return false; + } + } + } + + /** + * Set FILS HLP packet. + * + * @param ifaceName Name of the interface. + * @param dst Destination MAC address. + * @param hlpPacket Hlp Packet data in hex. + * @return true if request is sent successfully, false otherwise. + */ + public boolean addHlpReq(@NonNull String ifaceName, byte [] dst, byte [] hlpPacket) { + synchronized (mLock) { + final String methodStr = "filsHlpAddRequest"; + if (isV1_3()) { + ISupplicantStaIface iface = + checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr); + if (iface == null) { + return false; + } + + // Get a v1.3 supplicant STA Interface + android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface staIfaceV13 = + getStaIfaceMockableV1_3(iface); + + if (staIfaceV13 == null) { + Log.e(TAG, methodStr + + ": ISupplicantStaIface is null, cannot addHlpReq"); + return false; + } + try { + ArrayList<Byte> payload = NativeUtil.byteArrayToArrayList(hlpPacket); + SupplicantStatus status = staIfaceV13.filsHlpAddRequest(dst, payload); + return checkStatusAndLogFailure(status, methodStr); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + return false; + } + } else { + Log.e(TAG, "Method " + methodStr + " is not supported in existing HAL"); + return false; + } + } + } + + + /** * Start WPS pin registrar operation with the specified peer and pin. * * @param ifaceName Name of the interface. @@ -2658,6 +2742,23 @@ public class SupplicantStaIfaceHal { } } + if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork + .KeyMgmtMask.FILS_SHA256) != 0) { + advancedCapabilities |= WIFI_FEATURE_FILS_SHA256; + + if (mVerboseLoggingEnabled) { + Log.v(TAG, methodStr + ": FILS_SHA256 supported"); + } + } + if ((keyMgmtCapabilities & android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork + .KeyMgmtMask.FILS_SHA384) != 0) { + advancedCapabilities |= WIFI_FEATURE_FILS_SHA384; + + if (mVerboseLoggingEnabled) { + Log.v(TAG, methodStr + ": FILS_SHA384 supported"); + } + } + if (mVerboseLoggingEnabled) { Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities); } diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java index 02bda7e0f..f9ac13f52 100644 --- a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java +++ b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java @@ -384,7 +384,6 @@ public class SupplicantStaNetworkHal { Log.e(TAG, "failed to set Key Management"); return false; } - // Check and set SuiteB configurations. if (keyMgmtMask.get(WifiConfiguration.KeyMgmt.SUITE_B_192) && !saveSuiteBConfig(config)) { @@ -721,6 +720,15 @@ public class SupplicantStaNetworkHal { Log.e(TAG, "failed to set ocsp"); return false; } + /** EAP ERP */ + eapParam = eapConfig.getFieldValue(WifiEnterpriseConfig.EAP_ERP); + if (!TextUtils.isEmpty(eapParam) && eapParam.equals("1")) { + if (!setEapErp(true)) { + Log.e(TAG, ssid + ": failed to set eap erp"); + return false; + } + } + return true; } @@ -799,6 +807,14 @@ public class SupplicantStaNetworkHal { mask |= android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask .WAPI_CERT; break; + case WifiConfiguration.KeyMgmt.FILS_SHA256: + mask |= android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask + .FILS_SHA256; + break; + case WifiConfiguration.KeyMgmt.FILS_SHA384: + mask |= android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask + .FILS_SHA384; + break; case WifiConfiguration.KeyMgmt.WPA2_PSK: // This should never happen default: throw new IllegalArgumentException( @@ -1054,6 +1070,12 @@ public class SupplicantStaNetworkHal { mask = supplicantMaskValueToWifiConfigurationBitSet( mask, android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask .WAPI_CERT, bitset, WifiConfiguration.KeyMgmt.WAPI_CERT); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask + .FILS_SHA256, bitset, WifiConfiguration.KeyMgmt.FILS_SHA256); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork.KeyMgmtMask + .FILS_SHA384, bitset, WifiConfiguration.KeyMgmt.FILS_SHA384); if (mask != 0) { throw new IllegalArgumentException( "invalid key mgmt mask from supplicant: " + mask); @@ -1925,6 +1947,29 @@ public class SupplicantStaNetworkHal { } /** See ISupplicantStaNetwork.hal for documentation */ + private boolean setEapErp(boolean enable) { + synchronized (mLock) { + final String methodStr = "setEapErp"; + if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; + try { + android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork + iSupplicantStaNetworkV13; + + iSupplicantStaNetworkV13 = getV1_3StaNetwork(); + if (iSupplicantStaNetworkV13 != null) { + /* Support for set ERP Requires HAL v1.3 or higher */ + SupplicantStatus status = iSupplicantStaNetworkV13.setEapErp(enable); + return checkStatusAndLogFailure(status, methodStr); + } else { + return false; + } + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + return false; + } + } + } + /** See ISupplicantStaNetwork.hal for documentation */ private boolean getSaePasswordId() { synchronized (mLock) { final String methodStr = "getSaePasswordId"; diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java index 72d8db21c..3ed456b01 100644 --- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java +++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java @@ -496,8 +496,8 @@ public class WifiConfigurationUtil { private static boolean validateKeyMgmt(BitSet keyMgmnt) { if (keyMgmnt.cardinality() > 1) { - if (keyMgmnt.cardinality() > 3) { - Log.e(TAG, "validateKeyMgmt failed: cardinality > 3"); + if (keyMgmnt.cardinality() > 4) { + Log.e(TAG, "validateKeyMgmt failed: cardinality > 4"); return false; } if (!keyMgmnt.get(WifiConfiguration.KeyMgmt.WPA_EAP)) { @@ -509,9 +509,11 @@ public class WifiConfigurationUtil { Log.e(TAG, "validateKeyMgmt failed: not PSK or 8021X"); return false; } - if (keyMgmnt.cardinality() == 3 - && !keyMgmnt.get(WifiConfiguration.KeyMgmt.SUITE_B_192)) { - Log.e(TAG, "validateKeyMgmt failed: not SUITE_B_192"); + if (keyMgmnt.cardinality() == 4 + && (!keyMgmnt.get(WifiConfiguration.KeyMgmt.SUITE_B_192) + && !keyMgmnt.get(WifiConfiguration.KeyMgmt.FILS_SHA256) + && !keyMgmnt.get(WifiConfiguration.KeyMgmt.FILS_SHA384))) { + Log.e(TAG, "validateKeyMgmt failed: neither SUITE_B_192 nor FILS"); return false; } } diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java index 2ca87921c..4e006a2fc 100644 --- a/service/java/com/android/server/wifi/WifiMonitor.java +++ b/service/java/com/android/server/wifi/WifiMonitor.java @@ -100,6 +100,9 @@ public class WifiMonitor { /* MBO/OCE events */ public static final int MBO_OCE_BSS_TM_HANDLING_DONE = BASE + 71; + /* Fils network connection completed */ + public static final int FILS_NETWORK_CONNECTION_EVENT = BASE + 62; + /* WPS config errrors */ private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12; private static final int CONFIG_AUTH_FAILURE = 18; @@ -504,6 +507,17 @@ public class WifiMonitor { } /** + * Broadcast the fils network connection event to all the handlers registered for this event. + * + * @param iface Name of iface on which this occurred. + * @param networkId ID of the network in wpa_supplicant. + * @param bssid BSSID of the access point. + */ + public void broadcastFilsNetworkConnectionEvent(String iface, int networkId, String bssid) { + sendMessage(iface, FILS_NETWORK_CONNECTION_EVENT, networkId, 0, bssid); + } + + /** * Broadcast the network disconnection event to all the handlers registered for this event. * * @param iface Name of iface on which this occurred. diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index fb3459131..53be67d44 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -1985,6 +1985,26 @@ public class WifiNative { } /** + * Flush all previously configured HLPs. + * + * @return true if request is sent successfully, false otherwise. + */ + public boolean flushAllHlp(@NonNull String ifaceName) { + return mSupplicantStaIfaceHal.flushAllHlp(ifaceName); + } + + /** + * Set FILS HLP packet. + * + * @param dst Destination MAC address. + * @param hlpPacket Hlp Packet data in hex. + * @return true if request is sent successfully, false otherwise. + */ + public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) { + return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket); + } + + /** * Initiate TDLS discover and setup or teardown with the specified peer. * * @param ifaceName Name of the interface. diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java index 917f1f7a0..fd548fd40 100644 --- a/service/java/com/android/server/wifi/util/InformationElementUtil.java +++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java @@ -914,6 +914,8 @@ public class InformationElementUtil { private static final int RSN_AKM_OWE = 0x12ac0f00; private static final int RSN_AKM_EAP_SUITE_B_192 = 0x0cac0f00; private static final int RSN_OSEN = 0x019a6f50; + private static final int RSN_AKM_FILS_SHA256 = 0x0eac0f00; + private static final int RSN_AKM_FILS_SHA384 = 0x0fac0f00; private static final int WPA_CIPHER_NONE = 0x00f25000; private static final int WPA_CIPHER_TKIP = 0x02f25000; @@ -1016,6 +1018,12 @@ public class InformationElementUtil { case RSN_OSEN: rsnKeyManagement.add(ScanResult.KEY_MGMT_OSEN); break; + case RSN_AKM_FILS_SHA256: + rsnKeyManagement.add(ScanResult.KEY_MGMT_FILS_SHA256); + break; + case RSN_AKM_FILS_SHA384: + rsnKeyManagement.add(ScanResult.KEY_MGMT_FILS_SHA384); + break; default: // do nothing break; @@ -1294,6 +1302,10 @@ public class InformationElementUtil { return "WAPI-PSK"; case ScanResult.KEY_MGMT_WAPI_CERT: return "WAPI-CERT"; + case ScanResult.KEY_MGMT_FILS_SHA256: + return "FILS-SHA256"; + case ScanResult.KEY_MGMT_FILS_SHA384: + return "FILS-SHA384"; default: return "?"; } diff --git a/service/java/com/android/server/wifi/util/ScanResultUtil.java b/service/java/com/android/server/wifi/util/ScanResultUtil.java index 2e9a00a6f..320490c0b 100644 --- a/service/java/com/android/server/wifi/util/ScanResultUtil.java +++ b/service/java/com/android/server/wifi/util/ScanResultUtil.java @@ -127,6 +127,22 @@ public class ScanResultUtil { } /** + * Helper method to check if the provided |scanResult| corresponds to FILS SHA256 network. + * This checks if the provided capabilities string contains FILS-SHA256 or not. + */ + public static boolean isScanResultForFilsSha256Network(ScanResult scanResult) { + return scanResult.capabilities.contains("FILS-SHA256"); + } + + /** + * Helper method to check if the provided |scanResult| corresponds to FILS SHA384 network. + * This checks if the provided capabilities string contains FILS-SHA384 or not. + */ + public static boolean isScanResultForFilsSha384Network(ScanResult scanResult) { + return scanResult.capabilities.contains("FILS-SHA384"); + } + + /** * Helper method to check if the provided |scanResult| corresponds to an open network or not. * This checks if the provided capabilities string does not contain either of WEP, PSK, SAE * or EAP encryption types or not. |