diff options
author | Glen Kuhne <kuh@google.com> | 2017-02-03 13:36:11 -0800 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2017-02-09 14:26:39 -0800 |
commit | 66e9f4ab597136cbf4accadb8e009fc68ff071a7 (patch) | |
tree | 6d08fad8debbc7dcaca5d2b7d551f68225219334 /service/java | |
parent | 7c2c34319905b2122f124134a9f6f2064f1a2ea5 (diff) | |
download | wifi-66e9f4ab597136cbf4accadb8e009fc68ff071a7.tar.gz |
ISupplicantStaNetwork save & load WifiConfigs
Methods to set/get network variables from wpa_supplicant to
WifiConfiguration & vice versa.
TODO: Enterprise config params will be added in a further CL.
Test: Unit tests
Bug: 33383725
Change-Id: Ib002266a93b4738d0634cd1bbc925b61a86c1df7
Diffstat (limited to 'service/java')
3 files changed, 805 insertions, 40 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) { |