diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-01-11 14:34:34 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-01-11 14:34:34 +0000 |
commit | 55ec406d188b3234c93bc35d1ad548b29937c79d (patch) | |
tree | 3b74ee9e0aceba08f60ca09eed3102bc4db4a057 | |
parent | f962d5a97b28ab265ce5de1c85f09b7f410dabf5 (diff) | |
parent | 4a5579017051ca6bc567186db346ef4e5536166c (diff) |
Merge "softap: Add blocked/allowed client list support"
6 files changed, 390 insertions, 46 deletions
diff --git a/service/java/com/android/server/wifi/HostapdHal.java b/service/java/com/android/server/wifi/HostapdHal.java index 2f461667e..45c02af43 100644 --- a/service/java/com/android/server/wifi/HostapdHal.java +++ b/service/java/com/android/server/wifi/HostapdHal.java @@ -28,6 +28,7 @@ import android.hidl.manager.V1_0.IServiceNotification; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.BandType; +import android.net.wifi.WifiManager; import android.os.Handler; import android.os.IHwBinder.DeathRecipient; import android.os.RemoteException; @@ -585,10 +586,10 @@ public class HostapdHal { byte[] clientMacByteArray = client.toByteArray(); short disconnectReason; switch (reasonCode) { - case ApConfigUtil.DISCONNECT_REASON_CODE_INVALID_AUTHENTICATION: + case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER: disconnectReason = Ieee80211ReasonCode.WLAN_REASON_PREV_AUTH_NOT_VALID; break; - case ApConfigUtil.DISCONNECT_REASON_CODE_NO_MORE_STAS: + case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS: disconnectReason = Ieee80211ReasonCode.WLAN_REASON_DISASSOC_AP_BUSY; break; default: diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index 742a3d05d..58b33553c 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -59,9 +59,11 @@ import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Set; /** * Manage WiFi in AP mode. @@ -117,6 +119,12 @@ public class SoftApManager implements ActiveModeManager { private @Role int mRole = ROLE_UNSPECIFIED; + @NonNull + private Set<MacAddress> mBlockedClientList = new HashSet<>(); + + @NonNull + private Set<MacAddress> mAllowedClientList = new HashSet<>(); + /** * Listener for soft AP events. */ @@ -181,6 +189,10 @@ public class SoftApManager implements ActiveModeManager { mSarManager = sarManager; mWifiDiagnostics = wifiDiagnostics; mStateMachine = new SoftApStateMachine(looper); + if (softApConfig != null) { + mBlockedClientList = new HashSet<>(softApConfig.getBlockedClientList()); + mAllowedClientList = new HashSet<>(softApConfig.getAllowedClientList()); + } } /** @@ -394,20 +406,11 @@ public class SoftApManager implements ActiveModeManager { Log.d(TAG, "SoftAP is a hidden network"); } - if (config.getMaxNumberOfClients() != 0 - && !mCurrentSoftApCapability.isFeatureSupported( - SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { - Log.d(TAG, "Error, Max Client control requires HAL support"); + if (!ApConfigUtil.checkSupportAllConfiguration(config, mCurrentSoftApCapability)) { + Log.d(TAG, "Unsupported Configuration detect! config = " + config); return ERROR_UNSUPPORTED_CONFIGURATION; } - if ((config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION - || config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) - && !mCurrentSoftApCapability.isFeatureSupported( - SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { - Log.d(TAG, "Error, SAE requires HAL support"); - return ERROR_UNSUPPORTED_CONFIGURATION; - } if (!mWifiNative.startSoftAp(mApInterfaceName, localConfigBuilder.build(), mSoftApListener)) { Log.e(TAG, "Soft AP start failed"); @@ -430,24 +433,39 @@ public class SoftApManager implements ActiveModeManager { Log.d(TAG, "Soft AP is stopped"); } - private boolean checkSoftApMaxClient(SoftApConfiguration config, WifiClient newClient) { - boolean isAllow = true; + private boolean checkSoftApClient(SoftApConfiguration config, WifiClient newClient) { + if (!mCurrentSoftApCapability.isFeatureSupported( + SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { + return true; + } + + if (config.isClientControlByUserEnabled() + && !mAllowedClientList.contains(newClient.getMacAddress())) { + if (!mBlockedClientList.contains(newClient.getMacAddress())) { + mSoftApCallback.onBlockedClientConnecting(newClient, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + } + Log.d(TAG, "Force disconnect for unauthorized client: " + newClient); + mWifiNative.forceClientDisconnect( + mApInterfaceName, newClient.getMacAddress(), + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + return false; + } int maxConfig = mCurrentSoftApCapability.getMaxSupportedClients(); if (config.getMaxNumberOfClients() > 0) { maxConfig = Math.min(maxConfig, config.getMaxNumberOfClients()); } - if (mConnectedClients.size() == maxConfig) { + + if (mConnectedClients.size() >= maxConfig) { Log.i(TAG, "No more room for new client:" + newClient); - if (mCurrentSoftApCapability.isFeatureSupported( - SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { - Log.d(TAG, "Force disconnect for client: " + newClient); - mWifiNative.forceClientDisconnect( - mApInterfaceName, newClient.getMacAddress(), - ApConfigUtil.DISCONNECT_REASON_CODE_NO_MORE_STAS); - } - isAllow = false; + mWifiNative.forceClientDisconnect( + mApInterfaceName, newClient.getMacAddress(), + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS); + mSoftApCallback.onBlockedClientConnecting(newClient, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS); + return false; } - return isAllow; + return true; } private class SoftApStateMachine extends StateMachine { @@ -555,8 +573,11 @@ public class SoftApManager implements ActiveModeManager { break; case CMD_UPDATE_CONFIG: SoftApConfiguration newConfig = (SoftApConfiguration) message.obj; + Log.d(TAG, "Configuration changed to " + newConfig); mApConfig = new SoftApModeConfiguration(mApConfig.getTargetMode(), newConfig, mCurrentSoftApCapability); + mBlockedClientList = new HashSet<>(newConfig.getBlockedClientList()); + mAllowedClientList = new HashSet<>(newConfig.getAllowedClientList()); break; default: // Ignore all other commands. @@ -630,6 +651,10 @@ public class SoftApManager implements ActiveModeManager { * configuration. */ private void updateClientConnection() { + if (!mCurrentSoftApCapability.isFeatureSupported( + SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { + return; + } final int maxAllowedClientsByHardwareAndCarrier = mCurrentSoftApCapability.getMaxSupportedClients(); final int userApConfigMaxClientCount = @@ -639,22 +664,39 @@ public class SoftApManager implements ActiveModeManager { finalMaxClientCount = Math.min(userApConfigMaxClientCount, maxAllowedClientsByHardwareAndCarrier); } - if (mConnectedClients.size() > finalMaxClientCount) { - Log.d(TAG, "Capability Changed, update connected client"); + int targetDisconnectClientNumber = mConnectedClients.size() - finalMaxClientCount; + List<WifiClient> allowedConnectedList = new ArrayList<>(); + if (mApConfig.getSoftApConfiguration().isClientControlByUserEnabled()) { + // Check allow list first Iterator<WifiClient> iterator = mConnectedClients.iterator(); - int remove_count = mConnectedClients.size() - finalMaxClientCount; - if (mCurrentSoftApCapability.isFeatureSupported( - SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { - while (iterator.hasNext()) { - if (remove_count == 0) break; - WifiClient client = iterator.next(); - Log.d(TAG, "Force disconnect for client: " + client); + while (iterator.hasNext()) { + WifiClient client = iterator.next(); + if (mAllowedClientList.contains(client.getMacAddress())) { + allowedConnectedList.add(client); + } else { + Log.d(TAG, "Force disconnect for not allowed client: " + client); mWifiNative.forceClientDisconnect( mApInterfaceName, client.getMacAddress(), - ApConfigUtil.DISCONNECT_REASON_CODE_NO_MORE_STAS); - remove_count--; + WifiManager + .SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + targetDisconnectClientNumber--; } } + } else { + allowedConnectedList = new ArrayList<>(mConnectedClients); + } + if (targetDisconnectClientNumber > 0) { + Iterator<WifiClient> allowedClientIterator = allowedConnectedList.iterator(); + while (allowedClientIterator.hasNext()) { + if (targetDisconnectClientNumber == 0) break; + WifiClient allowedClient = allowedClientIterator.next(); + Log.d(TAG, "Force disconnect for client due to no more room: " + + allowedClient); + mWifiNative.forceClientDisconnect( + mApInterfaceName, allowedClient.getMacAddress(), + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS); + targetDisconnectClientNumber--; + } } } @@ -676,7 +718,7 @@ public class SoftApManager implements ActiveModeManager { return; } if (isConnected) { - boolean isAllow = checkSoftApMaxClient( + boolean isAllow = checkSoftApClient( mApConfig.getSoftApConfiguration(), client); if (isAllow) { mConnectedClients.add(client); @@ -926,6 +968,8 @@ public class SoftApManager implements ActiveModeManager { boolean needRescheduleTimer = mApConfig.getSoftApConfiguration().getShutdownTimeoutMillis() != newConfig.getShutdownTimeoutMillis(); + mBlockedClientList = new HashSet<>(newConfig.getBlockedClientList()); + mAllowedClientList = new HashSet<>(newConfig.getAllowedClientList()); mApConfig = new SoftApModeConfiguration(mApConfig.getTargetMode(), newConfig, mCurrentSoftApCapability); updateClientConnection(); diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index b9dc498ab..4bd2927e6 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -1127,6 +1127,27 @@ public class WifiServiceImpl extends BaseWifiService { } } } + + /** + * Called when client trying to connect but device blocked the client with specific reason. + * + * @param client the currently blocked client. + * @param blockedReason one of blocked reason from + * {@link WifiManager.SapClientBlockedReason} + */ + @Override + public void onBlockedClientConnecting(WifiClient client, int blockedReason) { + Iterator<ISoftApCallback> iterator = + mRegisteredSoftApCallbacks.getCallbacks().iterator(); + while (iterator.hasNext()) { + ISoftApCallback callback = iterator.next(); + try { + callback.onBlockedClientConnecting(client, blockedReason); + } catch (RemoteException e) { + Log.e(TAG, "onBlockedClientConnecting: remote exception -- " + e); + } + } + } } /** @@ -1483,6 +1504,18 @@ public class WifiServiceImpl extends BaseWifiService { public void onCapabilityChanged(SoftApCapability capability) { // Nothing to do } + + /** + * Called when client trying to connect but device blocked the client with specific reason. + * + * @param client the currently blocked client. + * @param blockedReason one of blocked reason from + * {@link WifiManager.SapClientBlockedReason} + */ + @Override + public void onBlockedClientConnecting(WifiClient client, int blockedReason) { + // Nothing to do + } } /** @@ -1508,6 +1541,7 @@ public class WifiServiceImpl extends BaseWifiService { throw new IllegalArgumentException("Callback must not be null"); } + enforceNetworkSettingsPermission(); if (mVerboseLoggingEnabled) { mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush(); diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java index 45d3a9a12..77d0a5500 100644 --- a/service/java/com/android/server/wifi/util/ApConfigUtil.java +++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java @@ -50,11 +50,6 @@ public class ApConfigUtil { public static final int ERROR_GENERIC = 2; public static final int ERROR_UNSUPPORTED_CONFIGURATION = 3; - /* Reason code in IEEE Std 802.11-2016, 9.4.1.7, Table 9-45. */ - public static final int DISCONNECT_REASON_CODE_UNSPECIFIED_REASON = 1; - public static final int DISCONNECT_REASON_CODE_INVALID_AUTHENTICATION = 2; - public static final int DISCONNECT_REASON_CODE_NO_MORE_STAS = 5; - /* Random number generator used for AP channel selection. */ private static final Random sRandom = new Random(); @@ -410,6 +405,9 @@ public class ApConfigUtil { * Helper function for converting SoftapConfiguration to WifiConfiguration. * Note that WifiConfiguration only Supports 2GHz, 5GHz, 2GHz+5GHz bands, * so conversion is limited to these bands. + * + * @param softApConfig the SoftApConfiguration which need to convert. + * @return the WifiConfiguration which convert from SoftApConfiguration. */ @NonNull public static WifiConfiguration convertToWifiConfiguration( @@ -454,6 +452,9 @@ public class ApConfigUtil { * Only Support None and WPA2 configuration conversion. * Note that WifiConfiguration only Supports 2GHz, 5GHz, 2GHz+5GHz bands, * so conversion is limited to these bands. + * + * @param wifiConfig the WifiConfiguration which need to convert. + * @return the SoftApConfiguration which convert from WifiConfiguration. */ @NonNull public static SoftApConfiguration fromWifiConfiguration( @@ -492,6 +493,9 @@ public class ApConfigUtil { /** * Helper function to creating SoftApCapability instance with initial field from resource file. + * + * @param context the caller context used to get value from resource file. + * @return SoftApCapability which updated the feature support or not from resource. */ @NonNull public static SoftApCapability updateCapabilityFromResource(@NonNull Context context) { @@ -525,6 +529,9 @@ public class ApConfigUtil { /** * Helper function to get SAE support or not. + * + * @param context the caller context used to get value from resource file. + * @return true if supported, false otherwise. */ public static boolean isWpa3SaeSupported(@NonNull Context context) { return context.getResources().getBoolean( @@ -534,7 +541,10 @@ public class ApConfigUtil { /** * Helper function for comparing two SoftApConfiguration. * - * Return true if the difference between the two configurations requires a restart to apply. + * @param currentConfig the original configuration. + * @param newConfig the new configuration which plan to apply. + * @return true if the difference between the two configurations requires a restart to apply, + * false otherwise. */ public static boolean checkConfigurationChangeNeedToRestart( SoftApConfiguration currentConfig, SoftApConfiguration newConfig) { @@ -546,4 +556,31 @@ public class ApConfigUtil { || currentConfig.getBand() != newConfig.getBand() || currentConfig.getChannel() != newConfig.getChannel(); } + + + /** + * Helper function for checking all of the configuration are supported or not. + * + * @param config target configuration want to check. + * @param capability the capability which indicate feature support or not. + * @return true if supported, false otherwise. + */ + public static boolean checkSupportAllConfiguration(SoftApConfiguration config, + SoftApCapability capability) { + if (!capability.isFeatureSupported( + SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT) + && (config.getMaxNumberOfClients() != 0 || config.isClientControlByUserEnabled())) { + Log.d(TAG, "Error, Client control requires HAL support"); + return false; + } + + if (!capability.isFeatureSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE) + && (config.getSecurityType() + == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION + || config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)) { + Log.d(TAG, "Error, SAE requires HAL support"); + return false; + } + return true; + } } diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java index d46f7dd1b..66043dddf 100644 --- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java @@ -70,7 +70,6 @@ import android.provider.Settings; import androidx.test.filters.SmallTest; import com.android.internal.util.WakeupMessage; -import com.android.server.wifi.util.ApConfigUtil; import com.android.wifi.resources.R; import org.junit.Before; @@ -1149,6 +1148,217 @@ public class SoftApManagerTest extends WifiBaseTest { } @Test + public void testForceClientDisconnectInvokeBecauseClientAuthorizationEnabled() + throws Exception { + mTestSoftApCapability.setMaxSupportedClients(10); + Builder configBuilder = new SoftApConfiguration.Builder(); + configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); + configBuilder.setSsid(TEST_SSID); + configBuilder.enableClientControlByUser(true); + SoftApModeConfiguration apConfig = + new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, + configBuilder.build(), mTestSoftApCapability); + startSoftApAndVerifyEnabled(apConfig); + + verify(mCallback).onConnectedClientsChanged(new ArrayList<>()); + + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + + // Client is not allow verify + verify(mWifiNative).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + verify(mCallback, never()).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + + } + + @Test + public void testClientConnectedAfterUpdateToAllowListwhenClientAuthorizationEnabled() + throws Exception { + mTestSoftApCapability.setMaxSupportedClients(10); + ArrayList<MacAddress> allowedClientList = new ArrayList<>(); + Builder configBuilder = new SoftApConfiguration.Builder(); + configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); + configBuilder.setSsid(TEST_SSID); + configBuilder.enableClientControlByUser(true); + SoftApModeConfiguration apConfig = + new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, + configBuilder.build(), mTestSoftApCapability); + startSoftApAndVerifyEnabled(apConfig); + + verify(mCallback).onConnectedClientsChanged(new ArrayList<>()); + + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + + // Client is not allow verify + verify(mWifiNative).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + verify(mCallback, never()).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + verify(mCallback).onBlockedClientConnecting(TEST_CONNECTED_CLIENT, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + reset(mCallback); + reset(mWifiNative); + // Update configuration + allowedClientList.add(TEST_MAC_ADDRESS); + configBuilder.setClientList(new ArrayList<MacAddress>(), allowedClientList); + mSoftApManager.updateConfiguration(configBuilder.build()); + mLooper.dispatchAll(); + // Client connected again + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + verify(mWifiNative, never()).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + verify(mCallback).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + verify(mCallback, never()).onBlockedClientConnecting(TEST_CONNECTED_CLIENT, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + } + + @Test + public void testClientConnectedAfterUpdateToBlockListwhenClientAuthorizationEnabled() + throws Exception { + mTestSoftApCapability.setMaxSupportedClients(10); + ArrayList<MacAddress> blockedClientList = new ArrayList<>(); + Builder configBuilder = new SoftApConfiguration.Builder(); + configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); + configBuilder.setSsid(TEST_SSID); + configBuilder.enableClientControlByUser(true); + SoftApModeConfiguration apConfig = + new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, + configBuilder.build(), mTestSoftApCapability); + startSoftApAndVerifyEnabled(apConfig); + + verify(mCallback).onConnectedClientsChanged(new ArrayList<>()); + + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + + // Client is not allow verify + verify(mWifiNative).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + verify(mCallback, never()).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + verify(mCallback).onBlockedClientConnecting(TEST_CONNECTED_CLIENT, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + reset(mCallback); + reset(mWifiNative); + // Update configuration + blockedClientList.add(TEST_MAC_ADDRESS); + configBuilder.setClientList(blockedClientList, new ArrayList<MacAddress>()); + mSoftApManager.updateConfiguration(configBuilder.build()); + mLooper.dispatchAll(); + // Client connected again + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + verify(mWifiNative).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + verify(mCallback, never()).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + verify(mCallback, never()).onBlockedClientConnecting(TEST_CONNECTED_CLIENT, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + } + + @Test + public void testConfigChangeToSmallAndClientAddBlockListCauseClientDisconnect() + throws Exception { + mTestSoftApCapability.setMaxSupportedClients(10); + ArrayList<MacAddress> allowedClientList = new ArrayList<>(); + allowedClientList.add(TEST_MAC_ADDRESS); + allowedClientList.add(TEST_MAC_ADDRESS_2); + ArrayList<MacAddress> blockedClientList = new ArrayList<>(); + + Builder configBuilder = new SoftApConfiguration.Builder(); + configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); + configBuilder.setSsid(TEST_SSID); + configBuilder.enableClientControlByUser(true); + configBuilder.setMaxNumberOfClients(2); + configBuilder.setClientList(new ArrayList<MacAddress>(), allowedClientList); + SoftApModeConfiguration apConfig = + new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, + configBuilder.build(), mTestSoftApCapability); + startSoftApAndVerifyEnabled(apConfig); + + verify(mCallback).onConnectedClientsChanged(new ArrayList<>()); + + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT, true); + mLooper.dispatchAll(); + + verify(mCallback, times(2)).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT)) + ); + + verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent( + 1, apConfig.getTargetMode()); + // Verify timer is canceled at this point + verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class)); + + // Second client connect and max client set is 1. + mSoftApListenerCaptor.getValue().onConnectedClientsChanged( + TEST_NATIVE_CLIENT_2, true); + mLooper.dispatchAll(); + + verify(mCallback, times(3)).onConnectedClientsChanged( + Mockito.argThat((List<WifiClient> clients) -> + clients.contains(TEST_CONNECTED_CLIENT_2)) + ); + verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent( + 2, apConfig.getTargetMode()); + reset(mCallback); + reset(mWifiNative); + // Update configuration + allowedClientList.clear(); + allowedClientList.add(TEST_MAC_ADDRESS_2); + + blockedClientList.add(TEST_MAC_ADDRESS); + configBuilder.setClientList(blockedClientList, allowedClientList); + configBuilder.setMaxNumberOfClients(1); + mSoftApManager.updateConfiguration(configBuilder.build()); + mLooper.dispatchAll(); + verify(mWifiNative).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER); + verify(mWifiNative, never()).forceClientDisconnect( + TEST_INTERFACE_NAME, TEST_MAC_ADDRESS, + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS); + } + + + @Test public void schedulesTimeoutTimerOnStart() throws Exception { SoftApModeConfiguration apConfig = new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null, @@ -1410,7 +1620,7 @@ public class SoftApManagerTest extends WifiBaseTest { mLooper.dispatchAll(); verify(mWifiNative).forceClientDisconnect( TEST_INTERFACE_NAME, TEST_MAC_ADDRESS_2, - ApConfigUtil.DISCONNECT_REASON_CODE_NO_MORE_STAS); + WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS); verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( 2, apConfig.getTargetMode()); } @@ -1616,9 +1826,11 @@ public class SoftApManagerTest extends WifiBaseTest { mSoftApListenerCaptor.getValue().onConnectedClientsChanged( TEST_NATIVE_CLIENT_2, true); mLooper.dispatchAll(); + // feature not support thus it should not trigger disconnect verify(mWifiNative, never()).forceClientDisconnect( any(), any(), anyInt()); - verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent( + // feature not support thus client still allow connected. + verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent( 2, apConfig.getTargetMode()); } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index dbba907a7..ff7711848 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -2275,6 +2275,7 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_DISABLED, 0); verify(mClientSoftApCallback, never()).onConnectedClientsChanged(any()); verify(mClientSoftApCallback, never()).onInfoChanged(any()); + verify(mClientSoftApCallback, never()).onCapabilityChanged(any()); } @@ -2298,6 +2299,9 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(callback).onStateChanged(WIFI_AP_STATE_DISABLED, 0); verify(callback).onConnectedClientsChanged(Mockito.<WifiClient>anyList()); verify(callback).onInfoChanged(new SoftApInfo()); + verify(callback).onCapabilityChanged(ApConfigUtil.updateCapabilityFromResource(mContext)); + // Don't need to invoke callback when register. + verify(callback, never()).onBlockedClientConnecting(any(), anyInt()); } /** @@ -2371,14 +2375,18 @@ public class WifiServiceImplTest extends WifiBaseTest { @Test public void correctCallbackIsCalledAfterAddingTwoCallbacksAndRemovingOne() throws Exception { final int callbackIdentifier = 1; + WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77")); mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, callbackIdentifier); + mLooper.dispatchAll(); // Change state from default before registering the second callback final List<WifiClient> testClients = new ArrayList(); mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); mStateMachineSoftApCallback.onInfoChanged(mTestSoftApInfo); + mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); + // Register another callback and verify the new state is returned in the immediate callback final int anotherUid = 2; @@ -2387,6 +2395,10 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); verify(mAnotherSoftApCallback).onConnectedClientsChanged(testClients); verify(mAnotherSoftApCallback).onInfoChanged(mTestSoftApInfo); + // Verify only first callback will receive onBlockedClientConnecting since it call after + // first callback register but before another callback register. + verify(mClientSoftApCallback).onBlockedClientConnecting(testWifiClient, 0); + verify(mAnotherSoftApCallback, never()).onBlockedClientConnecting(testWifiClient, 0); // unregister the fisrt callback mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); @@ -2472,9 +2484,11 @@ public class WifiServiceImplTest extends WifiBaseTest { @Test public void updatesSoftApStateAndConnectedClientsOnSoftApEvents() throws Exception { final List<WifiClient> testClients = new ArrayList(); + WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77")); mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); mStateMachineSoftApCallback.onInfoChanged(mTestSoftApInfo); + mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); // Register callback after num clients and soft AP are changed. final int callbackIdentifier = 1; @@ -2484,6 +2498,8 @@ public class WifiServiceImplTest extends WifiBaseTest { verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); verify(mClientSoftApCallback).onConnectedClientsChanged(testClients); verify(mClientSoftApCallback).onInfoChanged(mTestSoftApInfo); + // Don't need to invoke callback when register. + verify(mClientSoftApCallback, never()).onBlockedClientConnecting(any(), anyInt()); } private class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> { |