diff options
6 files changed, 1282 insertions, 41 deletions
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java index 18f850c60..08afb3a55 100644 --- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java +++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java @@ -25,6 +25,7 @@ import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; import android.hidl.manager.V1_0.IServiceManager; import android.hidl.manager.V1_0.IServiceNotification; +import android.net.wifi.WifiConfiguration; import android.os.HandlerThread; import android.os.RemoteException; import android.util.Log; @@ -33,6 +34,7 @@ import android.util.MutableBoolean; import libcore.util.HexEncoding; import java.util.ArrayList; +//import android.net.wifi.WifiEnterpriseConfig; /** * Hal calls for bring up/shut down of the supplicant daemon and for * sending requests to the supplicant daemon @@ -216,6 +218,83 @@ public class SupplicantStaIfaceHal { } /** + * Imitation of WifiSupplicantControl.addNetwork() + * + * Add a network configuration to wpa_supplicant, via HAL + * @param config Config corresponding to the network. + * @return SupplicantStaNetwork of the added network in wpa_supplicant. + */ + public SupplicantStaNetworkHal addNetwork(WifiConfiguration config) { + logi("addSupplicantStaNetwork via HIDL"); + if (config == null) { + loge("Cannot add NULL network!"); + return null; + } + SupplicantStaNetworkHal network = addNetwork(); + if (network == null) { + loge("Failed to add a network!"); + return null; + } + if (network.saveWifiConfiguration(config)) { + return network; + } else { + loge("Failed to save variables for: " + config.configKey()); + return null; + } + } + + /** + * Imitation of WifiSupplicantControl.connectToNetwork + */ + public boolean connectToNetwork(WifiConfiguration configuration, boolean shouldDisconnect) { + logd("connectToNetwork " + configuration.configKey() + + " (shouldDisconnect " + shouldDisconnect + ")"); + if (shouldDisconnect && !disconnect()) { + loge("Failed to trigger disconnect"); + return false; + } + if (!removeAllNetworks()) { + loge("Failed to remove existing networks"); + return false; + } + SupplicantStaNetworkHal network = addNetwork(configuration); + if (network == null) { + loge("Failed to add/save network configuration: " + configuration.configKey()); + return false; + } + if (!network.getId()) { + loge("Failed to get network id for configuration: " + configuration.configKey()); + return false; + } + if (!network.select()) { + loge("Failed to select network configuration: " + configuration.configKey()); + return false; + } + return true; + } + + /** + * Remove all networks from supplicant + * TODO(b/34454675) use ISupplicantIface.removeAllNetworks when it exists + */ + public boolean removeAllNetworks() { + synchronized (mLock) { + ArrayList<Integer> networks = listNetworks(); + if (networks == null) { + Log.e(TAG, "removeAllNetworks failed, got null networks"); + return false; + } + for (int id : networks) { + if (!removeNetwork(id)) { + Log.e(TAG, "removeAllNetworks failed to remove network: " + id); + return false; + } + } + } + return true; + } + + /** * @return returns the name of Iface or null if the call fails */ private String getName() { @@ -301,7 +380,7 @@ public class SupplicantStaIfaceHal { } if (statusSuccess.value) { return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( - newNetwork.value.asBinder())); + newNetwork.value.asBinder()), mHandlerThread); } else { return null; } @@ -353,7 +432,7 @@ public class SupplicantStaIfaceHal { } if (statusSuccess.value) { return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( - gotNetwork.value.asBinder())); + gotNetwork.value.asBinder()), mHandlerThread); } else { return null; } @@ -770,4 +849,16 @@ public class SupplicantStaIfaceHal { this.value = value; } } + + private void logd(String s) { + Log.d(TAG, s); + } + + private void logi(String s) { + Log.i(TAG, s); + } + + private void loge(String s) { + Log.e(TAG, s); + } } diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java index d2aff6f58..f501f6b84 100644 --- a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java +++ b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java @@ -19,11 +19,24 @@ import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetworkCallback; import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiEnterpriseConfig; +import android.os.HandlerThread; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; import android.util.MutableBoolean; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; + +import libcore.util.HexEncoding; + +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashMap; +import java.util.Map; /** * Wrapper class for ISupplicantStaNetwork HAL calls. Gets and sets supplicant sta network variables * and interacts with networks. @@ -33,14 +46,23 @@ import java.util.ArrayList; public class SupplicantStaNetworkHal { private static final String TAG = "SupplicantStaNetworkHal"; private static final boolean DBG = false; + private static final String ANY_BSSID_STR = "any"; + private static final byte[] ANY_BSSID_BYTES = {0, 0, 0, 0, 0, 0}; + private static final int BSSID_LENGTH = 6; + @VisibleForTesting + public static final String ID_STRING_KEY_FQDN = "fqdn"; + @VisibleForTesting + public static final String ID_STRING_KEY_CREATOR_UID = "creatorUid"; + @VisibleForTesting + public static final String ID_STRING_KEY_CONFIG_KEY = "configKey"; private final Object mLock = new Object(); private ISupplicantStaNetwork mISupplicantStaNetwork = null; - private int mId; - private String mName; - private int mType; - private ArrayList<Byte> mApSsid; - private byte[/* 6 */] mApBssid; + private final HandlerThread mHandlerThread; + private int mNetworkId; + private String mIfaceName; + private ArrayList<Byte> mSsid; + private byte[/* 6 */] mBssid; private boolean mScanSsid; private int mKeyMgmtMask; private int mProtoMask; @@ -67,12 +89,580 @@ public class SupplicantStaNetworkHal { private String mEapDomainSuffixMatch; private String mIdStr; - SupplicantStaNetworkHal(ISupplicantStaNetwork iSupplicantStaNetwork) { + SupplicantStaNetworkHal(ISupplicantStaNetwork iSupplicantStaNetwork, + HandlerThread handlerThread) { mISupplicantStaNetwork = iSupplicantStaNetwork; + mHandlerThread = handlerThread; + } + + /** + * Read network variables from wpa_supplicant into the provided WifiConfiguration object. + * + * @param config WifiConfiguration object to be populated. + * @param networkExtras Map of network extras parsed from wpa_supplicant. + * @return true if succeeds, false otherwise. + */ + public boolean loadWifiConfiguration(WifiConfiguration config, + Map<String, String> networkExtras) { + if (config == null) return false; + /** SSID */ + config.SSID = null; + if (getSsid() && !ArrayUtils.isEmpty(mSsid)) { + config.SSID = decodeSsid(mSsid); + } else { + Log.e(TAG, "Failed to read ssid"); + return false; + } + /** BSSID */ + config.getNetworkSelectionStatus().setNetworkSelectionBSSID(null); + if (getBssid() && !ArrayUtils.isEmpty(mBssid)) { + config.getNetworkSelectionStatus().setNetworkSelectionBSSID( + macAddressFromByteArray(mBssid)); + } + /** Scan SSID (Is Hidden Network?) */ + config.hiddenSSID = false; + if (getScanSsid()) { + config.hiddenSSID = mScanSsid; + } + /** Require PMF*/ + config.requirePMF = false; + if (getRequirePmf()) { + config.requirePMF = mRequirePmf; + } + /** WEP keys **/ + config.wepTxKeyIndex = -1; + if (getWepTxKeyIdx()) { + config.wepTxKeyIndex = mWepTxKeyIdx; + } + for (int i = 0; i < 4; i++) { + config.wepKeys[i] = null; + if (getWepKey(i) && !ArrayUtils.isEmpty(mWepKey)) { + config.wepKeys[i] = stringFromByteArrayList(mWepKey); + } + } + /** PSK pass phrase */ + config.preSharedKey = null; + if (getPskPassphrase() && !TextUtils.isEmpty(mPskPassphrase)) { + config.preSharedKey = mPskPassphrase; + } + /** allowedKeyManagement */ + if (getKeyMgmt()) { + config.allowedKeyManagement = + supplicantToWifiConfigurationKeyMgmtMask(mKeyMgmtMask); + } + /** allowedProtocols */ + if (getProto()) { + config.allowedProtocols = + supplicantToWifiConfigurationProtoMask(mProtoMask); + } + /** allowedAuthAlgorithms */ + if (getAuthAlg()) { + config.allowedAuthAlgorithms = + supplicantToWifiConfigurationAuthAlgMask(mAuthAlgMask); + } + /** allowedGroupCiphers */ + if (getGroupCipher()) { + config.allowedGroupCiphers = + supplicantToWifiConfigurationGroupCipherMask(mGroupCipherMask); + } + /** allowedPairwiseCiphers */ + if (getPairwiseCipher()) { + config.allowedPairwiseCiphers = + supplicantToWifiConfigurationPairwiseCipherMask(mPairwiseCipherMask); + } + /** metadata: idstr */ + if (getIdStr() && !TextUtils.isEmpty(mIdStr)) { + Map<String, String> metadata = WifiNative.parseNetworkExtra(mIdStr); + networkExtras.putAll(metadata); + } else { + Log.e(TAG, "getIdStr failed"); + return false; + } + return loadWifiEnterpriseConfig(config.SSID, config.enterpriseConfig); + } + + /** + * Save an entire WifiConfiguration to wpa_supplicant via HIDL. + * + * @param config WifiConfiguration object to be saved. + * @return true if succeeds, false otherwise. + */ + public boolean saveWifiConfiguration(WifiConfiguration config) { + if (config == null) return false; + /** SSID */ + if (config.SSID != null) { + if (!setSsid(encodeSsid(config.SSID))) { + Log.e(TAG, "Failed to set SSID: " + config.SSID); + return false; + } + } + /** BSSID */ + String bssidStr = config.getNetworkSelectionStatus().getNetworkSelectionBSSID(); + if (bssidStr != null) { + byte[] bssid = macAddressToByteArray(bssidStr); + if (!setBssid(bssid)) { + Log.e(TAG, "Failed to set BSSID: " + bssidStr); + return false; + } + } + /** Pre Shared Key */ + if (config.preSharedKey != null && !setPskPassphrase(config.preSharedKey)) { + Log.e(TAG, "failed to set psk"); + return false; + } + /** Wep Keys */ + boolean hasSetKey = false; + if (config.wepKeys != null) { + for (int i = 0; i < config.wepKeys.length; i++) { + // Prevent client screw-up by passing in a WifiConfiguration we gave it + // by preventing "*" as a key. + if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { + if (!setWepKey(i, stringToByteArrayList(config.wepKeys[i]))) { + Log.e(TAG, "failed to set wep_key " + i); + return false; + } + hasSetKey = true; + } + } + } + /** Wep Tx Key Idx */ + if (hasSetKey) { + if (!setWepTxKeyIdx(config.wepTxKeyIndex)) { + Log.e(TAG, "failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); + return false; + } + } + /** HiddenSSID */ + if (!setScanSsid(config.hiddenSSID)) { + Log.e(TAG, config.SSID + ": failed to set hiddenSSID: " + config.hiddenSSID); + return false; + } + /** RequirePMF */ + if (!setRequirePmf(config.requirePMF)) { + Log.e(TAG, config.SSID + ": failed to set requirePMF: " + config.requirePMF); + return false; + } + /** Key Management Scheme */ + if (config.allowedKeyManagement.cardinality() != 0 + && !setKeyMgmt(wifiConfigurationToSupplicantKeyMgmtMask( + config.allowedKeyManagement))) { + Log.e(TAG, "Failed to set Key Management"); + return false; + } + /** Security Protocol */ + if (config.allowedProtocols.cardinality() != 0 + && !setProto(wifiConfigurationToSupplicantProtoMask(config.allowedProtocols))) { + Log.e(TAG, "Failed to set Security Protocol"); + return false; + } + /** Auth Algorithm */ + if (config.allowedAuthAlgorithms.cardinality() != 0 + && !setAuthAlg(wifiConfigurationToSupplicantAuthAlgMask( + config.allowedAuthAlgorithms))) { + Log.e(TAG, "Failed to set AuthAlgorithm"); + return false; + } + /** Group Cipher */ + if (config.allowedGroupCiphers.cardinality() != 0 + && !setGroupCipher(wifiConfigurationToSupplicantGroupCipherMask( + config.allowedGroupCiphers))) { + Log.e(TAG, "Failed to set Group Cipher"); + return false; + } + /** Pairwise Cipher*/ + if (config.allowedPairwiseCiphers.cardinality() != 0 + && !setPairwiseCipher(wifiConfigurationToSupplicantPairwiseCipherMask( + config.allowedPairwiseCiphers))) { + Log.e(TAG, "Failed to set PairwiseCipher"); + return false; + } + /** metadata: FQDN + ConfigKey + CreatorUid */ + final Map<String, String> metadata = new HashMap<String, String>(); + if (config.isPasspoint()) { + metadata.put(ID_STRING_KEY_FQDN, config.FQDN); + } + metadata.put(ID_STRING_KEY_CONFIG_KEY, config.configKey()); + metadata.put(ID_STRING_KEY_CREATOR_UID, Integer.toString(config.creatorUid)); + if (!setIdStr(WifiNative.createNetworkExtra(metadata))) { + Log.e(TAG, "Failed to set id string"); + return false; + } + /** UpdateIdentifier */ + if (config.updateIdentifier != null + && !setUpdateIdentifier(Integer.parseInt(config.updateIdentifier))) { + Log.e(TAG, "Failed to set update identifier"); + return false; + } + // Finish here if no EAP config to set + if (config.enterpriseConfig == null + || config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE) { + return true; + } else { + return saveWifiEnterpriseConfig(config.SSID, config.enterpriseConfig); + } + } + + /** + * Read network variables from wpa_supplicant into the provided WifiEnterpriseConfig object. + * + * @param ssid SSID of the network. (Used for logging purposes only) + * @param eapConfig WifiEnterpriseConfig object to be populated. + * @return true if succeeds, false otherwise. + */ + private boolean loadWifiEnterpriseConfig(String ssid, WifiEnterpriseConfig eapConfig) { + // TBD + return true; + } + + /** + * Save network variables from the provided WifiEnterpriseConfig object to wpa_supplicant. + * + * @param ssid SSID of the network. (Used for logging purposes only) + * @param eapConfig WifiEnterpriseConfig object to be saved. + * @return true if succeeds, false otherwise. + */ + private boolean saveWifiEnterpriseConfig(String ssid, WifiEnterpriseConfig eapConfig) { + // TBD + return true; + } + + /** + * Maps WifiConfiguration Key Management BitSet to Supplicant HIDL bitmask int + * TODO(b/32571829): Update mapping when fast transition keys are added + * @return bitmask int describing the allowed Key Management schemes, readable by the Supplicant + * HIDL hal + */ + private static int wifiConfigurationToSupplicantKeyMgmtMask(BitSet keyMgmt) { + int mask = 0; + for (int bit = keyMgmt.nextSetBit(0); bit != -1; bit = keyMgmt.nextSetBit(bit + 1)) { + switch (bit) { + case WifiConfiguration.KeyMgmt.NONE: + mask |= ISupplicantStaNetwork.KeyMgmtMask.NONE; + break; + case WifiConfiguration.KeyMgmt.WPA_PSK: + mask |= ISupplicantStaNetwork.KeyMgmtMask.WPA_PSK; + break; + case WifiConfiguration.KeyMgmt.WPA_EAP: + mask |= ISupplicantStaNetwork.KeyMgmtMask.WPA_EAP; + break; + case WifiConfiguration.KeyMgmt.IEEE8021X: + mask |= ISupplicantStaNetwork.KeyMgmtMask.IEEE8021X; + break; + case WifiConfiguration.KeyMgmt.OSEN: + mask |= ISupplicantStaNetwork.KeyMgmtMask.OSEN; + break; + case WifiConfiguration.KeyMgmt.FT_PSK: + mask |= ISupplicantStaNetwork.KeyMgmtMask.FT_PSK; + break; + case WifiConfiguration.KeyMgmt.FT_EAP: + mask |= ISupplicantStaNetwork.KeyMgmtMask.FT_EAP; + break; + case WifiConfiguration.KeyMgmt.WPA2_PSK: // This should never happen + default: + throw new IllegalArgumentException( + "Invalid protoMask bit in keyMgmt: " + bit); + } + } + return mask; + } + + private static int wifiConfigurationToSupplicantProtoMask(BitSet protoMask) { + int mask = 0; + for (int bit = protoMask.nextSetBit(0); bit != -1; bit = protoMask.nextSetBit(bit + 1)) { + switch (bit) { + case WifiConfiguration.Protocol.WPA: + mask |= ISupplicantStaNetwork.ProtoMask.WPA; + break; + case WifiConfiguration.Protocol.RSN: + mask |= ISupplicantStaNetwork.ProtoMask.RSN; + break; + case WifiConfiguration.Protocol.OSEN: + mask |= ISupplicantStaNetwork.ProtoMask.OSEN; + break; + default: + throw new IllegalArgumentException( + "Invalid protoMask bit in wificonfig: " + bit); + } + } + return mask; + }; + + private static int wifiConfigurationToSupplicantAuthAlgMask(BitSet authAlgMask) { + int mask = 0; + for (int bit = authAlgMask.nextSetBit(0); bit != -1; + bit = authAlgMask.nextSetBit(bit + 1)) { + switch (bit) { + case WifiConfiguration.AuthAlgorithm.OPEN: + mask |= ISupplicantStaNetwork.AuthAlgMask.OPEN; + break; + case WifiConfiguration.AuthAlgorithm.SHARED: + mask |= ISupplicantStaNetwork.AuthAlgMask.SHARED; + break; + case WifiConfiguration.AuthAlgorithm.LEAP: + mask |= ISupplicantStaNetwork.AuthAlgMask.LEAP; + break; + default: + throw new IllegalArgumentException( + "Invalid authAlgMask bit in wificonfig: " + bit); + } + } + return mask; + }; + + private static int wifiConfigurationToSupplicantGroupCipherMask(BitSet groupCipherMask) { + int mask = 0; + for (int bit = groupCipherMask.nextSetBit(0); bit != -1; bit = + groupCipherMask.nextSetBit(bit + 1)) { + switch (bit) { + case WifiConfiguration.GroupCipher.WEP40: + mask |= ISupplicantStaNetwork.GroupCipherMask.WEP40; + break; + case WifiConfiguration.GroupCipher.WEP104: + mask |= ISupplicantStaNetwork.GroupCipherMask.WEP104; + break; + case WifiConfiguration.GroupCipher.TKIP: + mask |= ISupplicantStaNetwork.GroupCipherMask.TKIP; + break; + case WifiConfiguration.GroupCipher.CCMP: + mask |= ISupplicantStaNetwork.GroupCipherMask.CCMP; + break; + case WifiConfiguration.GroupCipher.GTK_NOT_USED: + mask |= ISupplicantStaNetwork.GroupCipherMask.GTK_NOT_USED; + break; + default: + throw new IllegalArgumentException( + "Invalid GroupCipherMask bit in wificonfig: " + bit); + } + } + return mask; + }; + + private static int wifiConfigurationToSupplicantPairwiseCipherMask(BitSet pairwiseCipherMask) { + int mask = 0; + for (int bit = pairwiseCipherMask.nextSetBit(0); bit != -1; + bit = pairwiseCipherMask.nextSetBit(bit + 1)) { + switch (bit) { + case WifiConfiguration.PairwiseCipher.NONE: + mask |= ISupplicantStaNetwork.PairwiseCipherMask.NONE; + break; + case WifiConfiguration.PairwiseCipher.TKIP: + mask |= ISupplicantStaNetwork.PairwiseCipherMask.TKIP; + break; + case WifiConfiguration.PairwiseCipher.CCMP: + mask |= ISupplicantStaNetwork.PairwiseCipherMask.CCMP; + break; + default: + throw new IllegalArgumentException( + "Invalid pairwiseCipherMask bit in wificonfig: " + bit); + } + } + return mask; + }; + + private static int supplicantToWifiConfigurationEapMethod(int value) { + switch (value) { + case ISupplicantStaNetwork.EapMethod.PEAP: + return WifiEnterpriseConfig.Eap.PEAP; + case ISupplicantStaNetwork.EapMethod.TLS: + return WifiEnterpriseConfig.Eap.TLS; + case ISupplicantStaNetwork.EapMethod.TTLS: + return WifiEnterpriseConfig.Eap.TTLS; + case ISupplicantStaNetwork.EapMethod.PWD: + return WifiEnterpriseConfig.Eap.PWD; + case ISupplicantStaNetwork.EapMethod.SIM: + return WifiEnterpriseConfig.Eap.SIM; + case ISupplicantStaNetwork.EapMethod.AKA: + return WifiEnterpriseConfig.Eap.AKA; + case ISupplicantStaNetwork.EapMethod.AKA_PRIME: + return WifiEnterpriseConfig.Eap.AKA_PRIME; + case ISupplicantStaNetwork.EapMethod.WFA_UNAUTH_TLS: + return WifiEnterpriseConfig.Eap.UNAUTH_TLS; + // WifiEnterpriseConfig.Eap.NONE: + default: + Log.e(TAG, "invalid eap method value from supplicant: " + value); + return -1; + } + }; + + private static int supplicantToWifiConfigurationEapPhase2Method(int value) { + switch (value) { + case ISupplicantStaNetwork.EapPhase2Method.NONE: + return WifiEnterpriseConfig.Phase2.NONE; + case ISupplicantStaNetwork.EapPhase2Method.PAP: + return WifiEnterpriseConfig.Phase2.PAP; + case ISupplicantStaNetwork.EapPhase2Method.MSPAP: + return WifiEnterpriseConfig.Phase2.MSCHAP; + case ISupplicantStaNetwork.EapPhase2Method.MSPAPV2: + return WifiEnterpriseConfig.Phase2.MSCHAPV2; + case ISupplicantStaNetwork.EapPhase2Method.GTC: + return WifiEnterpriseConfig.Phase2.GTC; + default: + Log.e(TAG, "invalid eap phase2 method value from supplicant: " + value); + return -1; + } + }; + + private static int supplicantMaskValueToWifiConfigurationBitSet(int supplicantMask, + int supplicantValue, BitSet bitset, + int bitSetPosition) { + bitset.set(bitSetPosition, (supplicantMask & supplicantValue) == supplicantValue); + int modifiedSupplicantMask = supplicantMask & ~supplicantValue; + return modifiedSupplicantMask; } + private static BitSet supplicantToWifiConfigurationKeyMgmtMask(int mask) { + BitSet bitset = new BitSet(); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.NONE, bitset, + WifiConfiguration.KeyMgmt.NONE); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.WPA_PSK, bitset, + WifiConfiguration.KeyMgmt.WPA_PSK); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.WPA_EAP, bitset, + WifiConfiguration.KeyMgmt.WPA_EAP); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.IEEE8021X, bitset, + WifiConfiguration.KeyMgmt.IEEE8021X); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.OSEN, bitset, + WifiConfiguration.KeyMgmt.OSEN); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.FT_PSK, bitset, + WifiConfiguration.KeyMgmt.FT_PSK); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.KeyMgmtMask.FT_EAP, bitset, + WifiConfiguration.KeyMgmt.FT_EAP); + if (mask != 0) { + throw new IllegalArgumentException( + "invalid key mgmt mask from supplicant: " + mask); + } + return bitset; + } + + private static BitSet supplicantToWifiConfigurationProtoMask(int mask) { + BitSet bitset = new BitSet(); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.ProtoMask.WPA, bitset, + WifiConfiguration.Protocol.WPA); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.ProtoMask.RSN, bitset, + WifiConfiguration.Protocol.RSN); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.ProtoMask.OSEN, bitset, + WifiConfiguration.Protocol.OSEN); + if (mask != 0) { + throw new IllegalArgumentException( + "invalid proto mask from supplicant: " + mask); + } + return bitset; + }; + + private static BitSet supplicantToWifiConfigurationAuthAlgMask(int mask) { + BitSet bitset = new BitSet(); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.AuthAlgMask.OPEN, bitset, + WifiConfiguration.AuthAlgorithm.OPEN); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.AuthAlgMask.SHARED, bitset, + WifiConfiguration.AuthAlgorithm.SHARED); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.AuthAlgMask.LEAP, bitset, + WifiConfiguration.AuthAlgorithm.LEAP); + if (mask != 0) { + throw new IllegalArgumentException( + "invalid auth alg mask from supplicant: " + mask); + } + return bitset; + }; + + private static BitSet supplicantToWifiConfigurationGroupCipherMask(int mask) { + BitSet bitset = new BitSet(); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.GroupCipherMask.WEP40, bitset, + WifiConfiguration.GroupCipher.WEP40); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.GroupCipherMask.WEP104, bitset, + WifiConfiguration.GroupCipher.WEP104); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.GroupCipherMask.TKIP, bitset, + WifiConfiguration.GroupCipher.TKIP); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.GroupCipherMask.CCMP, bitset, + WifiConfiguration.GroupCipher.CCMP); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.GroupCipherMask.GTK_NOT_USED, bitset, + WifiConfiguration.GroupCipher.GTK_NOT_USED); + if (mask != 0) { + throw new IllegalArgumentException( + "invalid group cipher mask from supplicant: " + mask); + } + return bitset; + }; + + private static BitSet supplicantToWifiConfigurationPairwiseCipherMask(int mask) { + BitSet bitset = new BitSet(); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.PairwiseCipherMask.NONE, bitset, + WifiConfiguration.PairwiseCipher.NONE); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.PairwiseCipherMask.TKIP, bitset, + WifiConfiguration.PairwiseCipher.TKIP); + mask = supplicantMaskValueToWifiConfigurationBitSet( + mask, ISupplicantStaNetwork.PairwiseCipherMask.CCMP, bitset, + WifiConfiguration.PairwiseCipher.CCMP); + if (mask != 0) { + throw new IllegalArgumentException( + "invalid pairwise cipher mask from supplicant: " + mask); + } + return bitset; + }; + + private static int wifiConfigurationToSupplicantEapMethod(int value) { + switch (value) { + case WifiEnterpriseConfig.Eap.PEAP: + return ISupplicantStaNetwork.EapMethod.PEAP; + case WifiEnterpriseConfig.Eap.TLS: + return ISupplicantStaNetwork.EapMethod.TLS; + case WifiEnterpriseConfig.Eap.TTLS: + return ISupplicantStaNetwork.EapMethod.TTLS; + case WifiEnterpriseConfig.Eap.PWD: + return ISupplicantStaNetwork.EapMethod.PWD; + case WifiEnterpriseConfig.Eap.SIM: + return ISupplicantStaNetwork.EapMethod.SIM; + case WifiEnterpriseConfig.Eap.AKA: + return ISupplicantStaNetwork.EapMethod.AKA; + case WifiEnterpriseConfig.Eap.AKA_PRIME: + return ISupplicantStaNetwork.EapMethod.AKA_PRIME; + case WifiEnterpriseConfig.Eap.UNAUTH_TLS: + return ISupplicantStaNetwork.EapMethod.WFA_UNAUTH_TLS; + // WifiEnterpriseConfig.Eap.NONE: + default: + Log.e(TAG, "invalid eap method value from WifiConfiguration: " + value); + return -1; + } + }; + + private static int wifiConfigurationToSupplicantEapPhase2Method(int value) { + switch (value) { + case WifiEnterpriseConfig.Phase2.NONE: + return ISupplicantStaNetwork.EapPhase2Method.NONE; + case WifiEnterpriseConfig.Phase2.PAP: + return ISupplicantStaNetwork.EapPhase2Method.PAP; + case WifiEnterpriseConfig.Phase2.MSCHAP: + return ISupplicantStaNetwork.EapPhase2Method.MSPAP; + case WifiEnterpriseConfig.Phase2.MSCHAPV2: + return ISupplicantStaNetwork.EapPhase2Method.MSPAPV2; + case WifiEnterpriseConfig.Phase2.GTC: + return ISupplicantStaNetwork.EapPhase2Method.GTC; + default: + Log.e(TAG, "invalid eap phase2 method value from WifiConfiguration: " + value); + return -1; + } + }; + /** See ISupplicantNetwork.hal for documentation */ - private boolean getId() { + public boolean getId() { synchronized (mLock) { final String methodStr = "getId"; if (DBG) Log.i(TAG, methodStr); @@ -82,7 +672,7 @@ public class SupplicantStaNetworkHal { mISupplicantStaNetwork.getId((SupplicantStatus status, int idValue) -> { statusOk.value = status.code == SupplicantStatusCode.SUCCESS; if (statusOk.value) { - this.mId = idValue; + this.mNetworkId = idValue; } else { logFailureStatus(status, methodStr); } @@ -106,30 +696,7 @@ public class SupplicantStaNetworkHal { String nameValue) -> { statusOk.value = status.code == SupplicantStatusCode.SUCCESS; if (statusOk.value) { - this.mName = nameValue; - } else { - logFailureStatus(status, methodStr); - } - }); - return statusOk.value; - } catch (RemoteException e) { - handleRemoteException(e, methodStr); - return false; - } - } - } - - /** See ISupplicantNetwork.hal for documentation */ - private boolean getType() { - synchronized (mLock) { - final String methodStr = "getType"; - if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; - try { - MutableBoolean statusOk = new MutableBoolean(false); - mISupplicantStaNetwork.getType((SupplicantStatus status, int typeValue) -> { - statusOk.value = status.code == SupplicantStatusCode.SUCCESS; - if (statusOk.value) { - this.mType = typeValue; + this.mIfaceName = nameValue; } else { logFailureStatus(status, methodStr); } @@ -327,6 +894,20 @@ public class SupplicantStaNetworkHal { } } /** See ISupplicantStaNetwork.hal for documentation */ + private boolean setUpdateIdentifier(int identifier) { + synchronized (mLock) { + final String methodStr = "setUpdateIdentifier"; + if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; + try { + SupplicantStatus status = mISupplicantStaNetwork.setUpdateIdentifier(identifier); + return checkStatusAndLogFailure(status, methodStr); + } catch (RemoteException e) { + handleRemoteException(e, methodStr); + return false; + } + } + } + /** See ISupplicantStaNetwork.hal for documentation */ private boolean setEapMethod(int method) { synchronized (mLock) { final String methodStr = "setEapMethod"; @@ -547,7 +1128,7 @@ public class SupplicantStaNetworkHal { java.util.ArrayList<Byte> ssidValue) -> { statusOk.value = status.code == SupplicantStatusCode.SUCCESS; if (statusOk.value) { - this.mApSsid = ssidValue; + this.mSsid = ssidValue; } else { logFailureStatus(status, methodStr); } @@ -570,7 +1151,7 @@ public class SupplicantStaNetworkHal { byte[/* 6 */] bssidValue) -> { statusOk.value = status.code == SupplicantStatusCode.SUCCESS; if (statusOk.value) { - this.mApBssid = bssidValue; + this.mBssid = bssidValue; } else { logFailureStatus(status, methodStr); } @@ -743,7 +1324,7 @@ public class SupplicantStaNetworkHal { } } /** See ISupplicantStaNetwork.hal for documentation */ - private boolean getWepKeyCallback(int keyIdx) { + private boolean getWepKey(int keyIdx) { synchronized (mLock) { final String methodStr = "keyIdx"; if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; @@ -1181,7 +1762,7 @@ public class SupplicantStaNetworkHal { } } /** See ISupplicantStaNetwork.hal for documentation */ - private boolean select() { + public boolean select() { synchronized (mLock) { final String methodStr = "select"; if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; @@ -1319,4 +1900,97 @@ public class SupplicantStaNetworkHal { private void logFailureStatus(SupplicantStatus status, String methodStr) { Log.e(TAG, methodStr + " failed: " + status.debugMessage); } + + /** + * @return the UTF_8 char byte values of str, as an ArrayList + */ + private static ArrayList<Byte> stringToByteArrayList(String str) { + ArrayList<Byte> byteArrayList = new ArrayList<Byte>(); + for (byte b : str.getBytes(StandardCharsets.UTF_8)) { + byteArrayList.add(new Byte(b)); + } + return byteArrayList; + } + + /** + * @return the string decoded from UTF_8 byte values in byteArrayList + * returns null for null input + */ + private static String stringFromByteArrayList(ArrayList<Byte> byteArrayList) { + if (byteArrayList == null) return null; + byte[] byteArray = new byte[byteArrayList.size()]; + int i = 0; + for (Byte b : byteArrayList) { + byteArray[i] = b; + i++; + } + return new String(byteArray, StandardCharsets.UTF_8); + } + + /** + * Converts a mac address string to an array of Byes + * @param bssidStr string of format: "XX:XX:XX:XX:XX:XX", where X is any hexadecimal digit. + * Passing "any" is the same as 00:00:00:00:00:00 + * @throws IllegalArgumentException for various malformed inputs + */ + private static byte[] macAddressToByteArray(String bssidStr) { + if (bssidStr == null) { + throw new IllegalArgumentException("null bssid String"); + } + if (ANY_BSSID_STR.equals(bssidStr)) return ANY_BSSID_BYTES; + String cleanBssid = bssidStr.replace(":", ""); + if (cleanBssid.length() != 12) { + throw new IllegalArgumentException("invalid bssid String length: " + cleanBssid); + } + return HexEncoding.decode(cleanBssid.toCharArray(), false); + } + + /** + * Converts an array of 6 bytes to a HexEncoded String with format: "XX:XX:XX:XX:XX:XX", where X + * is any hexadecimal digit. + * @param macArray byte array of bssid values, must have length 6 + * @throws IllegalArgumentException for malformed inputs + */ + private static String macAddressFromByteArray(byte[] macArray) { + if (macArray == null) { + throw new IllegalArgumentException("null macArray"); + } + if (macArray.length != 6) { + throw new IllegalArgumentException("invalid macArray length: " + macArray.length); + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < macArray.length; i++) { + sb.append(new String(HexEncoding.encode(macArray, i, 1))).append(":"); + } + String mac = sb.toString(); + return mac.substring(0, mac.length() - 1); //remove trailing ':' + } + + /** + * Converts an ssid string to an arraylist of UTF_8 byte values. + * Removes encapsulating quotation marks if they exist + */ + private static ArrayList<Byte> encodeSsid(String ssid) { + int length = ssid.length(); + if ((length > 1) && (ssid.charAt(0) == '"') && (ssid.charAt(length - 1) == '"')) { + ssid = ssid.substring(1, ssid.length() - 1); + } + return stringToByteArrayList(ssid); + } + + /** + * Converts an ArrayList<Byte> of UTF_8 byte values to an SSID String, encapsulated in quotes + * Will return null given null ssidBytes + */ + private static String decodeSsid(ArrayList<Byte> ssidBytes) { + if (ssidBytes == null) return null; + if (ssidBytes.size() == 0) return "\"\""; + byte[] ssidArray = new byte[ssidBytes.size()]; + int i = 0; + for (Byte b : ssidBytes) { + ssidArray[i] = b; + i++; + } + return "\"" + (new String(ssidArray, StandardCharsets.UTF_8)) + "\""; + } } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index c0afb9bc4..5eb71b751 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -491,7 +491,7 @@ public class WifiNative { if (encoded == null) { return false; } - return setNetworkVariable(netId, name, "\"" + encoded + "\""); + return setNetworkVariable(netId, name, encoded); } @VisibleForTesting @@ -506,7 +506,7 @@ public class WifiNative { Log.e(TAG, "Unable to serialize networkExtra: " + e.toString()); return null; } - return encoded; + return "\"" + encoded + "\""; } public boolean setNetworkVariable(int netId, String name, String value) { diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java new file mode 100644 index 000000000..640e27423 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.wifi; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +import android.app.test.MockAnswerUtil.AnswerWithArguments; +import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; +import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; +import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; +import android.net.wifi.WifiConfiguration; +import android.os.HandlerThread; +import android.os.RemoteException; +import android.os.test.TestLooper; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Unit tests for SupplicantStaNetworkHal + */ +public class SupplicantStaNetworkHalTest { + private static final String TAG = "SupplicantStaNetworkHalTest"; + + private SupplicantStaNetworkHal mSupplicantNetwork; + private SupplicantStatus mStatusSuccess; + private SupplicantStatus mStatusFailure; + @Mock + private ISupplicantStaNetwork mISupplicantStaNetworkMock; + @Mock + private HandlerThread mHandlerThread; + private TestLooper mTestLooper; + private SupplicantNetworkVariables mSupplicantVariables; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mTestLooper = new TestLooper(); + mStatusSuccess = createSupplicantStatus(SupplicantStatusCode.SUCCESS); + mStatusFailure = createSupplicantStatus(SupplicantStatusCode.FAILURE_UNKNOWN); + when(mHandlerThread.getLooper()).thenReturn(mTestLooper.getLooper()); + mSupplicantVariables = new SupplicantNetworkVariables(); + setupISupplicantNetworkMock(); + + mSupplicantNetwork = + new SupplicantStaNetworkHal(mISupplicantStaNetworkMock, mHandlerThread); + } + + /** + * Tests the saving of WifiConfiguration to wpa_supplicant. + */ + @Test + public void testOpenNetworkWifiConfigurationSaveLoad() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createOpenHiddenNetwork(); + config.updateIdentifier = "45"; + testWifiConfigurationSaveLoad(config); + } + + /** + * Tests the saving/loading of WifiConfiguration to wpa_supplicant. + */ + @Test + public void testPskNetworkWifiConfigurationSaveLoad() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createPskNetwork(); + config.requirePMF = true; + testWifiConfigurationSaveLoad(config); + } + + /** + * Tests the saving/loading of WifiConfiguration to wpa_supplicant. + */ + @Test + public void testWepNetworkWifiConfigurationSaveLoad() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + config.BSSID = "34:45:19:09:45"; + testWifiConfigurationSaveLoad(config); + } + + /** + * Tests the failure to load ssid aborts the loading of network variables. + */ + @Test + public void testSsidLoadFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + assertTrue(mSupplicantNetwork.saveWifiConfiguration(config)); + + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getSsidCallback cb) throws RemoteException { + cb.onValues(mStatusFailure, mSupplicantVariables.ssid); + } + }).when(mISupplicantStaNetworkMock) + .getSsid(any(ISupplicantStaNetwork.getSsidCallback.class)); + + WifiConfiguration loadConfig = new WifiConfiguration(); + Map<String, String> networkExtras = new HashMap<>(); + assertFalse(mSupplicantNetwork.loadWifiConfiguration(loadConfig, networkExtras)); + } + + /** + * Tests the failure to save ssid. + */ + @Test + public void testSsidSaveFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(ArrayList<Byte> ssid) throws RemoteException { + return mStatusFailure; + } + }).when(mISupplicantStaNetworkMock).setSsid(any(ArrayList.class)); + + assertFalse(mSupplicantNetwork.saveWifiConfiguration(config)); + } + + /** + * Tests the failure to save invalid key mgmt (unknown bit set in the + * {@link WifiConfiguration#allowedKeyManagement} being saved). + */ + @Test + public void testInvalidKeyMgmtSaveFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + config.allowedKeyManagement.set(10); + try { + assertFalse(mSupplicantNetwork.saveWifiConfiguration(config)); + } catch (IllegalArgumentException e) { + return; + } + assertTrue(false); + } + + /** + * Tests the failure to load invalid key mgmt (unkown bit set in the supplicant network key_mgmt + * variable read). + */ + @Test + public void testInvalidKeyMgmtLoadFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + assertTrue(mSupplicantNetwork.saveWifiConfiguration(config)); + + // Modify the supplicant variable directly. + mSupplicantVariables.keyMgmtMask = 0xFFFFF; + WifiConfiguration loadConfig = new WifiConfiguration(); + Map<String, String> networkExtras = new HashMap<>(); + try { + assertFalse(mSupplicantNetwork.loadWifiConfiguration(loadConfig, networkExtras)); + } catch (IllegalArgumentException e) { + return; + } + assertTrue(false); + } + + /** + * Tests the failure to save invalid bssid (less than 6 bytes in the + * {@link WifiConfiguration#BSSID} being saved). + */ + @Test + public void testInvalidBssidSaveFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + config.getNetworkSelectionStatus().setNetworkSelectionBSSID("45:34:23:12"); + try { + assertFalse(mSupplicantNetwork.saveWifiConfiguration(config)); + } catch (IllegalArgumentException e) { + return; + } + assertTrue(false); + } + /** + * Tests the failure to load invalid bssid (less than 6 bytes in the supplicant bssid variable + * read). + */ + @Test + public void testInvalidBssidLoadFailure() throws Exception { + WifiConfiguration config = WifiConfigurationTestUtil.createWepHiddenNetwork(); + assertTrue(mSupplicantNetwork.saveWifiConfiguration(config)); + + // Modify the supplicant variable directly. + mSupplicantVariables.bssid = new byte[3]; + WifiConfiguration loadConfig = new WifiConfiguration(); + Map<String, String> networkExtras = new HashMap<>(); + try { + assertFalse(mSupplicantNetwork.loadWifiConfiguration(loadConfig, networkExtras)); + } catch (IllegalArgumentException e) { + return; + } + assertTrue(false); + } + + private void testWifiConfigurationSaveLoad(WifiConfiguration config) { + assertTrue(mSupplicantNetwork.saveWifiConfiguration(config)); + WifiConfiguration loadConfig = new WifiConfiguration(); + Map<String, String> networkExtras = new HashMap<>(); + assertTrue(mSupplicantNetwork.loadWifiConfiguration(loadConfig, networkExtras)); + WifiConfigurationTestUtil.assertConfigurationEqualForSupplicant(config, loadConfig); + assertEquals(config.configKey(), + networkExtras.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY)); + assertEquals( + config.creatorUid, + Integer.parseInt(networkExtras.get( + SupplicantStaNetworkHal.ID_STRING_KEY_CREATOR_UID))); + // There is no getter for this one, so check the supplicant variable. + if (config.updateIdentifier != null) { + assertEquals(Integer.parseInt(config.updateIdentifier), + mSupplicantVariables.updateIdentifier); + } + } + + /** + * Sets up the HIDL interface mock with all the setters/getter values. + * Note: This only sets up the mock to return success on all methods. + */ + private void setupISupplicantNetworkMock() throws Exception { + /** SSID */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(ArrayList<Byte> ssid) throws RemoteException { + mSupplicantVariables.ssid = ssid; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setSsid(any(ArrayList.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getSsidCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.ssid); + } + }).when(mISupplicantStaNetworkMock) + .getSsid(any(ISupplicantStaNetwork.getSsidCallback.class)); + + /** BSSID */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(byte[] bssid) throws RemoteException { + mSupplicantVariables.bssid = bssid; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setBssid(any(byte[].class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getBssidCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.bssid); + } + }).when(mISupplicantStaNetworkMock) + .getBssid(any(ISupplicantStaNetwork.getBssidCallback.class)); + + /** Scan SSID (Is Hidden Network?) */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(boolean enable) throws RemoteException { + mSupplicantVariables.scanSsid = enable; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setScanSsid(any(boolean.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getScanSsidCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.scanSsid); + } + }).when(mISupplicantStaNetworkMock) + .getScanSsid(any(ISupplicantStaNetwork.getScanSsidCallback.class)); + + /** Require PMF*/ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(boolean enable) throws RemoteException { + mSupplicantVariables.requirePmf = enable; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setRequirePmf(any(boolean.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getRequirePmfCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.requirePmf); + } + }).when(mISupplicantStaNetworkMock) + .getRequirePmf(any(ISupplicantStaNetwork.getRequirePmfCallback.class)); + + /** PSK pass phrase*/ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(String pskPassphrase) throws RemoteException { + mSupplicantVariables.pskPassphrase = pskPassphrase; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setPskPassphrase(any(String.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getPskPassphraseCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.pskPassphrase); + } + }).when(mISupplicantStaNetworkMock) + .getPskPassphrase(any(ISupplicantStaNetwork.getPskPassphraseCallback.class)); + + /** WEP keys **/ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int keyIdx, ArrayList<Byte> key) throws RemoteException { + mSupplicantVariables.wepKey[keyIdx] = key; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setWepKey(any(int.class), any(ArrayList.class)); + doAnswer(new AnswerWithArguments() { + public void answer(int keyIdx, ISupplicantStaNetwork.getWepKeyCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.wepKey[keyIdx]); + } + }).when(mISupplicantStaNetworkMock) + .getWepKey(any(int.class), any(ISupplicantStaNetwork.getWepKeyCallback.class)); + + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int keyIdx) throws RemoteException { + mSupplicantVariables.wepTxKeyIdx = keyIdx; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setWepTxKeyIdx(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getWepTxKeyIdxCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.wepTxKeyIdx); + } + }).when(mISupplicantStaNetworkMock) + .getWepTxKeyIdx(any(ISupplicantStaNetwork.getWepTxKeyIdxCallback.class)); + + /** allowedKeyManagement */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int mask) throws RemoteException { + mSupplicantVariables.keyMgmtMask = mask; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setKeyMgmt(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getKeyMgmtCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.keyMgmtMask); + } + }).when(mISupplicantStaNetworkMock) + .getKeyMgmt(any(ISupplicantStaNetwork.getKeyMgmtCallback.class)); + + /** allowedProtocols */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int mask) throws RemoteException { + mSupplicantVariables.protoMask = mask; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setProto(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getProtoCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.protoMask); + } + }).when(mISupplicantStaNetworkMock) + .getProto(any(ISupplicantStaNetwork.getProtoCallback.class)); + + /** allowedAuthAlgorithms */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int mask) throws RemoteException { + mSupplicantVariables.authAlgMask = mask; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setAuthAlg(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getAuthAlgCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.authAlgMask); + } + }).when(mISupplicantStaNetworkMock) + .getAuthAlg(any(ISupplicantStaNetwork.getAuthAlgCallback.class)); + + /** allowedGroupCiphers */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int mask) throws RemoteException { + mSupplicantVariables.groupCipherMask = mask; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setGroupCipher(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getGroupCipherCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.groupCipherMask); + } + }).when(mISupplicantStaNetworkMock) + .getGroupCipher(any(ISupplicantStaNetwork.getGroupCipherCallback.class)); + + /** allowedPairwiseCiphers */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int mask) throws RemoteException { + mSupplicantVariables.pairwiseCipherMask = mask; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setPairwiseCipher(any(int.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getPairwiseCipherCallback cb) + throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.pairwiseCipherMask); + } + }).when(mISupplicantStaNetworkMock) + .getPairwiseCipher(any(ISupplicantStaNetwork.getPairwiseCipherCallback.class)); + + /** metadata: idstr */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(String idStr) throws RemoteException { + mSupplicantVariables.idStr = idStr; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setIdStr(any(String.class)); + doAnswer(new AnswerWithArguments() { + public void answer(ISupplicantStaNetwork.getIdStrCallback cb) throws RemoteException { + cb.onValues(mStatusSuccess, mSupplicantVariables.idStr); + } + }).when(mISupplicantStaNetworkMock) + .getIdStr(any(ISupplicantStaNetwork.getIdStrCallback.class)); + + /** UpdateIdentifier */ + doAnswer(new AnswerWithArguments() { + public SupplicantStatus answer(int identifier) throws RemoteException { + mSupplicantVariables.updateIdentifier = identifier; + return mStatusSuccess; + } + }).when(mISupplicantStaNetworkMock).setUpdateIdentifier(any(int.class)); + } + + private SupplicantStatus createSupplicantStatus(int code) { + SupplicantStatus status = new SupplicantStatus(); + status.code = code; + return status; + } + + // Private class to to store/inspect values set via the HIDL mock. + private class SupplicantNetworkVariables { + public ArrayList<Byte> ssid; + public byte[/* 6 */] bssid; + public int keyMgmtMask; + public int protoMask; + public int authAlgMask; + public int groupCipherMask; + public int pairwiseCipherMask; + public boolean scanSsid; + public boolean requirePmf; + public String idStr; + public int updateIdentifier; + public String pskPassphrase; + public ArrayList<Byte>[] wepKey = new ArrayList[4]; + public int wepTxKeyIdx; + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java index a8fdefe78..a069e4130 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java @@ -716,7 +716,6 @@ public class WifiBackupRestoreTest { Integer.toString(configuration.creatorUid)); String idString = WifiNative.createNetworkExtra(extras); if (idString != null) { - idString = "\"" + idString + "\""; out.write(" " + "id_str=" + idString + "\n"); } out.write("}\n"); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java index ca2569b5c..96fd180df 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java @@ -468,6 +468,29 @@ public class WifiConfigurationTestUtil { } /** + * Asserts that the 2 WifiConfigurations are equal. This compares all the elements that are + * saved into wpa_supplicant by SupplicantStaNetwork. + */ + public static void assertConfigurationEqualForSupplicant( + WifiConfiguration expected, WifiConfiguration actual) { + assertNotNull(expected); + assertNotNull(actual); + assertEquals(expected.SSID, actual.SSID); + assertEquals(expected.getNetworkSelectionStatus().getNetworkSelectionBSSID(), + actual.getNetworkSelectionStatus().getNetworkSelectionBSSID()); + assertEquals(expected.preSharedKey, actual.preSharedKey); + assertEquals(expected.wepKeys, actual.wepKeys); + assertEquals(expected.wepTxKeyIndex, actual.wepTxKeyIndex); + assertEquals(expected.hiddenSSID, actual.hiddenSSID); + assertEquals(expected.requirePMF, actual.requirePMF); + assertEquals(expected.allowedKeyManagement, actual.allowedKeyManagement); + assertEquals(expected.allowedProtocols, actual.allowedProtocols); + assertEquals(expected.allowedAuthAlgorithms, actual.allowedAuthAlgorithms); + assertEquals(expected.allowedGroupCiphers, actual.allowedGroupCiphers); + assertEquals(expected.allowedPairwiseCiphers, actual.allowedPairwiseCiphers); + } + + /** * Asserts that the 2 WifiConfigurations are equal. This is a generic version of the comparator * which is used in QNS tests for comparing the network selections. * This importantly checks that the networkId's of the 2 configs are equal. |