summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java33
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java8
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaIfaceHal.java40
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java9
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java77
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java57
6 files changed, 214 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index cf8acb4f0..7314bb853 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -2985,6 +2985,31 @@ public class ClientModeImpl extends StateMachine {
handleConnectionAttemptEndForDiagnostics(level2FailureCode);
}
+ /* If this connection attempt fails after 802.1x stage, clear intermediate cached data. */
+ void clearNetworkCachedDataIfNeeded(WifiConfiguration config, int reason) {
+ if (config == null) return;
+
+ switch(reason) {
+ case 14: // MICHAEL_MIC_FAILURE
+ case 15: // 4WAY_HANDSHAKE_TIMEOUT
+ case 16: // GROUP_KEY_UPDATE_TIMEOUT
+ case 17: // IE_IN_4WAY_DIFFERS
+ case 18: // GROUP_CIPHER_NOT_VALID
+ case 19: // PAIRWISE_CIPHER_NOT_VALID
+ case 20: // AKMP_NOT_VALID
+ case 23: // IEEE_802_1X_AUTH_FAILED
+ case 24: // CIPHER_SUITE_REJECTED
+ case 29: // BAD_CIPHER_OR_AKM
+ case 45: // PEERKEY_MISMATCH
+ case 49: // INVALID_PMKID
+ mWifiNative.removeNetworkCachedData(config.networkId);
+ break;
+ default:
+ logi("Keep PMK cache for network disconnection reason " + reason);
+ break;
+ }
+ }
+
/**
* Returns the sufficient RSSI for the frequency that this network is last seen on.
*/
@@ -3247,6 +3272,9 @@ public class ClientModeImpl extends StateMachine {
mWifiMetrics.logStaEvent(StaEvent.TYPE_MAC_CHANGE, config);
boolean setMacSuccess =
mWifiNative.setMacAddress(mInterfaceName, newMac);
+ if (setMacSuccess) {
+ mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, newMac);
+ }
Log.d(TAG, "ConnectedMacRandomization SSID(" + config.getPrintableSsid()
+ "). setMacAddress(" + newMac.toString() + ") from "
+ currentMacString + " = " + setMacSuccess);
@@ -3265,6 +3293,7 @@ public class ClientModeImpl extends StateMachine {
String currentMacStr = mWifiNative.getMacAddress(mInterfaceName);
if (!TextUtils.equals(currentMacStr, factoryMac.toString())) {
if (mWifiNative.setMacAddress(mInterfaceName, factoryMac)) {
+ mWifiNative.removeNetworkCachedDataIfNeeded(config.networkId, factoryMac);
mWifiMetrics.logStaEvent(StaEvent.TYPE_MAC_CHANGE, config);
} else {
Log.e(TAG, "Failed to set MAC address to " + "'" + factoryMac.toString() + "'");
@@ -4213,6 +4242,7 @@ public class ClientModeImpl extends StateMachine {
// idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
// at the chip etc...
if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
+ clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
break;
@@ -5242,6 +5272,7 @@ public class ClientModeImpl extends StateMachine {
+ " BSSID=" + bssid
+ " target=" + target);
}
+ clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
if (bssid != null && bssid.equals(mTargetBssid)) {
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
@@ -5397,6 +5428,7 @@ public class ClientModeImpl extends StateMachine {
mWifiDiagnostics.captureBugReportData(
WifiDiagnostics.REPORT_REASON_UNEXPECTED_DISCONNECT);
}
+
boolean localGen = message.arg1 == 1;
if (!localGen) { // ignore disconnects initiated by wpa_supplicant.
mWifiScoreCard.noteNonlocalDisconnect(message.arg2);
@@ -5600,6 +5632,7 @@ public class ClientModeImpl extends StateMachine {
getTargetSsid(), bssid,
WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
}
+ clearNetworkCachedDataIfNeeded(getTargetWifiConfiguration(), message.arg2);
break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java
index 5af65d0a5..cac84b543 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceCallbackV1_3Impl.java
@@ -199,9 +199,13 @@ abstract class SupplicantStaIfaceCallbackV1_3Impl extends
if (WifiConfigurationUtil.isConfigForPskNetwork(curConfig)) return;
- mStaIfaceHal.addPmkCacheEntry(curConfig.networkId, expirationTimeInSec, serializedEntry);
+ mStaIfaceHal.addPmkCacheEntry(mIfaceName,
+ curConfig.networkId, expirationTimeInSec, serializedEntry);
mStaIfaceHal.logCallback(
- "onPmkCacheAdded: update pmk cache for config id " + curConfig.networkId);
+ "onPmkCacheAdded: update pmk cache for config id "
+ + curConfig.networkId
+ + " on "
+ + mIfaceName);
}
@Override
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
index 4380f6ab4..657b081dd 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
@@ -43,6 +43,7 @@ import android.hardware.wifi.supplicant.V1_3.WifiTechnology;
import android.hardware.wifi.supplicant.V1_3.WpaDriverCapabilitiesMask;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
+import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiAnnotations.WifiStandard;
import android.net.wifi.WifiConfiguration;
@@ -170,10 +171,12 @@ public class SupplicantStaIfaceHal {
static class PmkCacheStoreData {
public long expirationTimeInSec;
public ArrayList<Byte> data;
+ public MacAddress macAddress;
- PmkCacheStoreData(long timeInSec, ArrayList<Byte> serializedData) {
+ PmkCacheStoreData(long timeInSec, ArrayList<Byte> serializedData, MacAddress macAddress) {
expirationTimeInSec = timeInSec;
data = serializedData;
+ this.macAddress = macAddress;
}
}
@@ -1053,6 +1056,24 @@ public class SupplicantStaIfaceHal {
}
/**
+ * Clear HAL cached data if MAC address is changed.
+ *
+ * @param networkId network id of the network to be checked.
+ * @param curMacAddress current MAC address
+ */
+ public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
+ synchronized (mLock) {
+ PmkCacheStoreData pmkData = mPmkCacheEntries.get(networkId);
+
+ if (pmkData == null) return;
+
+ if (curMacAddress.equals(pmkData.macAddress)) return;
+
+ removeNetworkCachedData(networkId);
+ }
+ }
+
+ /**
* Remove all networks from supplicant
*
* @param ifaceName Name of the interface.
@@ -2636,10 +2657,21 @@ public class SupplicantStaIfaceHal {
}
protected void addPmkCacheEntry(
+ String ifaceName,
int networkId, long expirationTimeInSec, ArrayList<Byte> serializedEntry) {
- mPmkCacheEntries.put(networkId,
- new PmkCacheStoreData(expirationTimeInSec, serializedEntry));
- updatePmkCacheExpiration();
+ String macAddressStr = getMacAddress(ifaceName);
+ if (macAddressStr == null) {
+ Log.w(TAG, "Omit PMK cache due to no valid MAC address on " + ifaceName);
+ return;
+ }
+ try {
+ MacAddress macAddress = MacAddress.fromString(macAddressStr);
+ mPmkCacheEntries.put(networkId,
+ new PmkCacheStoreData(expirationTimeInSec, serializedEntry, macAddress));
+ updatePmkCacheExpiration();
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "Invalid MAC address string " + macAddressStr);
+ }
}
protected void removePmkCacheEntry(int networkId) {
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 08abafa61..d0f2753a5 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -2416,6 +2416,15 @@ public class WifiNative {
mSupplicantStaIfaceHal.removeNetworkCachedData(networkId);
}
+ /** Clear HAL cached data for |networkId| if MAC address is changed.
+ *
+ * @param networkId network id of the network to be checked.
+ * @param curMacAddress current MAC address
+ */
+ public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
+ mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress);
+ }
+
/*
* DPP
*/
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 0c48521e1..8f36770e6 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -4997,4 +4997,81 @@ public class ClientModeImplTest extends WifiBaseTest {
verifyNoMoreInteractions(mNetworkAgentHandler);
}
+
+ /*
+ * Verify that network cached data is cleared correctly in
+ * disconnected state.
+ */
+ @Test
+ public void testNetworkCachedDataIsClearedCorrectlyInDisconnectedState() throws Exception {
+ // Setup CONNECT_MODE & a WifiConfiguration
+ initializeAndAddNetworkAndVerifySuccess();
+ mCmi.sendMessage(ClientModeImpl.CMD_START_CONNECT, 0, 0, sBSSID);
+ mLooper.dispatchAll();
+
+ // got UNSPECIFIED during this connection attempt
+ mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 1, sBSSID);
+ mLooper.dispatchAll();
+
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ verify(mWifiNative, never()).removeNetworkCachedData(anyInt());
+
+ // got 4WAY_HANDSHAKE_TIMEOUT during this connection attempt
+ mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 15, sBSSID);
+ mLooper.dispatchAll();
+
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
+ }
+
+ /*
+ * Verify that network cached data is cleared correctly in
+ * disconnected state.
+ */
+ @Test
+ public void testNetworkCachedDataIsClearedCorrectlyInObtainingIpState() throws Exception {
+ initializeAndAddNetworkAndVerifySuccess();
+
+ verify(mWifiNative).removeAllNetworks(WIFI_IFACE_NAME);
+
+ IActionListener connectActionListener = mock(IActionListener.class);
+ mCmi.connect(null, 0, mock(Binder.class), connectActionListener, 0, Binder.getCallingUid());
+ mLooper.dispatchAll();
+ verify(connectActionListener).onSuccess();
+
+ verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt(), any());
+
+ mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
+ mLooper.dispatchAll();
+
+ mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
+ mLooper.dispatchAll();
+
+ assertEquals("ObtainingIpState", getCurrentState().getName());
+
+ // got 4WAY_HANDSHAKE_TIMEOUT during this connection attempt
+ mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 15, sBSSID);
+ mLooper.dispatchAll();
+
+ verify(mWifiNative).removeNetworkCachedData(FRAMEWORK_NETWORK_ID);
+ }
+
+ /*
+ * Verify that network cached data is NOT cleared in ConnectedState.
+ */
+ @Test
+ public void testNetworkCachedDataIsClearedIf4WayHandshakeFailure() throws Exception {
+ when(mWifiScoreCard.detectAbnormalDisconnection())
+ .thenReturn(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL);
+ InOrder inOrderWifiLockManager = inOrder(mWifiLockManager);
+ connect();
+ inOrderWifiLockManager.verify(mWifiLockManager).updateWifiClientConnected(true);
+
+ // got 4WAY_HANDSHAKE_TIMEOUT
+ mCmi.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, 0, 15, sBSSID);
+ mLooper.dispatchAll();
+ verify(mWifiNative, never()).removeNetworkCachedData(anyInt());
+ }
+
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
index facb7f9ad..95f88bbf1 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
@@ -52,6 +52,7 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.test.MockAnswerUtil;
+import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.content.Context;
import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
import android.hardware.wifi.supplicant.V1_0.ISupplicant;
@@ -69,6 +70,7 @@ import android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback.BssTmDa
import android.hardware.wifi.supplicant.V1_3.WifiTechnology;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
+import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
@@ -126,6 +128,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
private static final int ICON_FILE_SIZE = 72;
private static final String HS20_URL = "http://blahblah";
private static final long PMK_CACHE_EXPIRATION_IN_SEC = 1024;
+ private static final byte[] CONNECTED_MAC_ADDRESS_BYTES =
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
private @Mock IServiceManager mServiceManagerMock;
private @Mock ISupplicant mISupplicantMock;
@@ -251,6 +255,13 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
any(IServiceNotification.Stub.class))).thenReturn(true);
when(mISupplicantMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
anyLong())).thenReturn(true);
+ doAnswer(new AnswerWithArguments() {
+ public void answer(ISupplicantStaIface.getMacAddressCallback cb) {
+ cb.onValues(mStatusSuccess, CONNECTED_MAC_ADDRESS_BYTES);
+ }
+ })
+ .when(mISupplicantStaIfaceMock)
+ .getMacAddress(any(ISupplicantStaIface.getMacAddressCallback.class));
mHandler = spy(new Handler(mLooper.getLooper()));
mDut = new SupplicantStaIfaceHalSpy();
}
@@ -1759,7 +1770,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
config.networkId = testFrameworkNetworkId;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
PmkCacheStoreData pmkCacheData =
- new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>(),
+ MacAddress.fromBytes(CONNECTED_MAC_ADDRESS_BYTES));
mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
@@ -1820,7 +1832,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
config.networkId = testFrameworkNetworkId;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
PmkCacheStoreData pmkCacheData =
- new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>(),
+ MacAddress.fromBytes(CONNECTED_MAC_ADDRESS_BYTES));
mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
@@ -1850,7 +1863,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
config.networkId = testFrameworkNetworkId;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
PmkCacheStoreData pmkCacheData =
- new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>(),
+ MacAddress.fromBytes(CONNECTED_MAC_ADDRESS_BYTES));
mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
@@ -1877,7 +1891,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
config.networkId = testFrameworkNetworkId;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
PmkCacheStoreData pmkCacheData =
- new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>(),
+ MacAddress.fromBytes(CONNECTED_MAC_ADDRESS_BYTES));
mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
@@ -1896,6 +1911,40 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
}
/**
+ * Tests the PMK cache is removed and not set if MAC address is changed.
+ */
+ @Test
+ public void testRemovePmkEntryOnMacAddressChanged() throws Exception {
+ int testFrameworkNetworkId = 9;
+ long testStartSeconds = PMK_CACHE_EXPIRATION_IN_SEC / 2;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = testFrameworkNetworkId;
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ // Assume we have a PMK cache with a different MAC address.
+ final byte[] previouisConnectedMacAddressBytes =
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x09};
+ PmkCacheStoreData pmkCacheData =
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>(),
+ MacAddress.fromBytes(previouisConnectedMacAddressBytes));
+ mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
+
+ setupMocksForHalV1_3();
+ setupMocksForPmkCache();
+ setupMocksForConnectSequence(false);
+
+ // When MAC is not changed, PMK cache should NOT be removed.
+ mDut.removeNetworkCachedDataIfNeeded(testFrameworkNetworkId,
+ MacAddress.fromBytes(previouisConnectedMacAddressBytes));
+ assertEquals(pmkCacheData, mDut.mPmkCacheEntries.get(testFrameworkNetworkId));
+
+ // When MAC is changed, PMK cache should be removed.
+ mDut.removeNetworkCachedDataIfNeeded(testFrameworkNetworkId,
+ MacAddress.fromBytes(CONNECTED_MAC_ADDRESS_BYTES));
+ assertNull(mDut.mPmkCacheEntries.get(testFrameworkNetworkId));
+ }
+
+ /**
* Test getConnectionCapabilities
* Should fail if running HAL lower than V1_3
*/