Merge "Remove unused driver management JNI calls"
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 1e288ef..f93c8bd 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -49,6 +49,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.KeyStore;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
@@ -403,7 +404,8 @@
         mWriter = new DelayedDiskWrite();
         mIpconfigStore = new IpConfigStore(mWriter);
         mWifiNetworkHistory = new WifiNetworkHistory(mContext, mLocalLog, mWriter);
-        mWifiSupplicantControl = new WifiSupplicantControl(mContext, wifiNative, mLocalLog);
+        TelephonyManager tm = TelephonyManager.from(mContext);
+        mWifiSupplicantControl = new WifiSupplicantControl(tm, wifiNative, mLocalLog);
         mWifiKeyStore = new WifiKeyStore(keyStore);
         mBackupManagerProxy = new BackupManagerProxy();
     }
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 63cc35c..971e69e 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -28,6 +28,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.KeyStore;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.R;
 import com.android.server.am.BatteryStatsService;
@@ -212,6 +213,11 @@
         return mWifiMulticastLockManager;
     }
 
+    public TelephonyManager makeTelephonyManager() {
+        // may not be available when WiFi starts
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
     public IWificond makeWificond() {
         // We depend on being able to refresh our binder in WifiStateMachine, so don't cache it.
         IBinder binder = ServiceManager.getService(WIFICOND_SERVICE_NAME);
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 8c0d36a..18c67e4 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -30,21 +30,19 @@
 import android.os.Message;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.Base64;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.util.Protocol;
+import com.android.internal.util.StateMachine;
 import com.android.server.wifi.hotspot2.IconEvent;
 import com.android.server.wifi.hotspot2.Utils;
 import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
-
-import com.android.internal.util.Protocol;
-import com.android.internal.util.StateMachine;
+import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -1338,8 +1336,7 @@
         } else if (requestName.startsWith(SIM_STR)) {
             Matcher matchGsm = mRequestGsmAuthPattern.matcher(requestName);
             Matcher matchUmts = mRequestUmtsAuthPattern.matcher(requestName);
-            WifiStateMachine.SimAuthRequestData data =
-                    new WifiStateMachine.SimAuthRequestData();
+            SimAuthRequestData data = new SimAuthRequestData();
             if (matchGsm.find()) {
                 data.networkId = Integer.parseInt(matchGsm.group(1));
                 data.protocol = WifiEnterpriseConfig.Eap.SIM;
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 0a3c0ab..131d2b0 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -111,6 +111,8 @@
 import com.android.server.wifi.hotspot2.Utils;
 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
 import com.android.server.wifi.util.TelephonyUtil;
+import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
+import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
 
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
@@ -878,15 +880,6 @@
     /* Soft ap state */
     private State mSoftApState = new SoftApState();
 
-    public static class SimAuthRequestData {
-        int networkId;
-        int protocol;
-        String ssid;
-        // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
-        // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
-        String[] data;
-    }
-
     /**
      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
      * {@link WifiManager#WIFI_STATE_DISABLING},
@@ -930,6 +923,14 @@
      */
     private final WorkSource mLastRunningWifiUids = new WorkSource();
 
+    private TelephonyManager mTelephonyManager;
+    private TelephonyManager getTelephonyManager() {
+        if (mTelephonyManager == null) {
+            mTelephonyManager = mWifiInjector.makeTelephonyManager();
+        }
+        return mTelephonyManager;
+    }
+
     private final IBatteryStats mBatteryStats;
 
     private final String mTcpBufferSizes;
@@ -5445,7 +5446,8 @@
                             && targetWificonfiguration.allowedKeyManagement
                                     .get(WifiConfiguration.KeyMgmt.IEEE8021X)
                             && TelephonyUtil.isSimEapMethod(eapMethod)) {
-                        String identity = TelephonyUtil.getSimIdentity(mContext, eapMethod);
+                        String identity =
+                                TelephonyUtil.getSimIdentity(getTelephonyManager(), eapMethod);
                         if (identity != null) {
                             mWifiNative.simIdentityResponse(networkId, identity);
                             identitySent = true;
@@ -7594,142 +7596,6 @@
         }
     }
 
-    private static int parseHex(char ch) {
-        if ('0' <= ch && ch <= '9') {
-            return ch - '0';
-        } else if ('a' <= ch && ch <= 'f') {
-            return ch - 'a' + 10;
-        } else if ('A' <= ch && ch <= 'F') {
-            return ch - 'A' + 10;
-        } else {
-            throw new NumberFormatException("" + ch + " is not a valid hex digit");
-        }
-    }
-
-    private byte[] parseHex(String hex) {
-        /* This only works for good input; don't throw bad data at it */
-        if (hex == null) {
-            return new byte[0];
-        }
-
-        if (hex.length() % 2 != 0) {
-            throw new NumberFormatException(hex + " is not a valid hex string");
-        }
-
-        byte[] result = new byte[(hex.length())/2 + 1];
-        result[0] = (byte) ((hex.length())/2);
-        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
-            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
-            byte b = (byte) (val & 0xFF);
-            result[j] = b;
-        }
-
-        return result;
-    }
-
-    private static String makeHex(byte[] bytes) {
-        StringBuilder sb = new StringBuilder();
-        for (byte b : bytes) {
-            sb.append(String.format("%02x", b));
-        }
-        return sb.toString();
-    }
-
-    private static String makeHex(byte[] bytes, int from, int len) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < len; i++) {
-            sb.append(String.format("%02x", bytes[from+i]));
-        }
-        return sb.toString();
-    }
-
-    private static byte[] concatHex(byte[] array1, byte[] array2) {
-
-        int len = array1.length + array2.length;
-
-        byte[] result = new byte[len];
-
-        int index = 0;
-        if (array1.length != 0) {
-            for (byte b : array1) {
-                result[index] = b;
-                index++;
-            }
-        }
-
-        if (array2.length != 0) {
-            for (byte b : array2) {
-                result[index] = b;
-                index++;
-            }
-        }
-
-        return result;
-    }
-
-    // TODO move to TelephonyUtil, same with utilities above
-    String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
-        StringBuilder sb = new StringBuilder();
-        for (String challenge : requestData) {
-            if (challenge == null || challenge.isEmpty()) {
-                continue;
-            }
-            logd("RAND = " + challenge);
-
-            byte[] rand = null;
-            try {
-                rand = parseHex(challenge);
-            } catch (NumberFormatException e) {
-                loge("malformed challenge");
-                continue;
-            }
-
-            String base64Challenge = android.util.Base64.encodeToString(
-                    rand, android.util.Base64.NO_WRAP);
-
-            // Try USIM first for authentication.
-            String tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
-                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
-            if (tmResponse == null) {
-                /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
-                 */
-                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
-                        TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
-            }
-            logv("Raw Response - " + tmResponse);
-
-            if (tmResponse == null || tmResponse.length() <= 4) {
-                loge("bad response - " + tmResponse);
-                return null;
-            }
-
-            byte[] result = android.util.Base64.decode(tmResponse, android.util.Base64.DEFAULT);
-            logv("Hex Response -" + makeHex(result));
-            int sres_len = result[0];
-            if (sres_len >= result.length) {
-                loge("malfomed response - " + tmResponse);
-                return null;
-            }
-            String sres = makeHex(result, 1, sres_len);
-            int kc_offset = 1 + sres_len;
-            if (kc_offset >= result.length) {
-                loge("malfomed response - " + tmResponse);
-                return null;
-            }
-            int kc_len = result[kc_offset];
-            if (kc_offset + kc_len > result.length) {
-                loge("malfomed response - " + tmResponse);
-                return null;
-            }
-            String kc = makeHex(result, 1 + kc_offset, kc_len);
-            sb.append(":" + kc + ":" + sres);
-            logv("kc:" + kc + " sres:" + sres);
-        }
-
-        return sb.toString();
-    }
-
-    // TODO move to TelephonyUtil
     void handleGsmAuthRequest(SimAuthRequestData requestData) {
         if (targetWificonfiguration == null
                 || targetWificonfiguration.networkId == requestData.networkId) {
@@ -7739,16 +7605,8 @@
             return;
         }
 
-        TelephonyManager tm = (TelephonyManager)
-                mContext.getSystemService(Context.TELEPHONY_SERVICE);
-
-        if (tm == null) {
-            loge("could not get telephony manager");
-            mWifiNative.simAuthFailedResponse(requestData.networkId);
-            return;
-        }
-
-        String response = getGsmSimAuthResponse(requestData.data, tm);
+        String response =
+                TelephonyUtil.getGsmSimAuthResponse(requestData.data, getTelephonyManager());
         if (response == null) {
             mWifiNative.simAuthFailedResponse(requestData.networkId);
         } else {
@@ -7757,13 +7615,7 @@
         }
     }
 
-    // TODO move to TelephonyUtil
     void handle3GAuthRequest(SimAuthRequestData requestData) {
-        StringBuilder sb = new StringBuilder();
-        byte[] rand = null;
-        byte[] authn = null;
-        String res_type = "UMTS-AUTH";
-
         if (targetWificonfiguration == null
                 || targetWificonfiguration.networkId == requestData.networkId) {
             logd("id matches targetWifiConfiguration");
@@ -7771,69 +7623,11 @@
             logd("id does not match targetWifiConfiguration");
             return;
         }
-        if (requestData.data.length == 2) {
-            try {
-                rand = parseHex(requestData.data[0]);
-                authn = parseHex(requestData.data[1]);
-            } catch (NumberFormatException e) {
-                loge("malformed challenge");
-            }
-        } else {
-               loge("malformed challenge");
-        }
 
-        String tmResponse = "";
-        if (rand != null && authn != null) {
-            String base64Challenge = android.util.Base64.encodeToString(
-                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
-
-            TelephonyManager tm = (TelephonyManager)
-                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
-            if (tm != null) {
-                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
-                        TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge);
-                logv("Raw Response - " + tmResponse);
-            } else {
-                loge("could not get telephony manager");
-            }
-        }
-
-        boolean good_response = false;
-        if (tmResponse != null && tmResponse.length() > 4) {
-            byte[] result = android.util.Base64.decode(tmResponse,
-                    android.util.Base64.DEFAULT);
-            loge("Hex Response - " + makeHex(result));
-            byte tag = result[0];
-            if (tag == (byte) 0xdb) {
-                logv("successful 3G authentication ");
-                int res_len = result[1];
-                String res = makeHex(result, 2, res_len);
-                int ck_len = result[res_len + 2];
-                String ck = makeHex(result, res_len + 3, ck_len);
-                int ik_len = result[res_len + ck_len + 3];
-                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
-                sb.append(":" + ik + ":" + ck + ":" + res);
-                logv("ik:" + ik + "ck:" + ck + " res:" + res);
-                good_response = true;
-            } else if (tag == (byte) 0xdc) {
-                loge("synchronisation failure");
-                int auts_len = result[1];
-                String auts = makeHex(result, 2, auts_len);
-                res_type = "UMTS-AUTS";
-                sb.append(":" + auts);
-                logv("auts:" + auts);
-                good_response = true;
-            } else {
-                loge("bad response - unknown tag = " + tag);
-            }
-        } else {
-            loge("bad response - " + tmResponse);
-        }
-
-        if (good_response) {
-            String response = sb.toString();
-            logv("Supplicant Response -" + response);
-            mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
+        SimAuthResponseData response =
+                TelephonyUtil.get3GAuthResponse(requestData, getTelephonyManager());
+        if (response != null) {
+            mWifiNative.simAuthResponse(requestData.networkId, response.type, response.response);
         } else {
             mWifiNative.umtsAuthFailedResponse(requestData.networkId);
         }
diff --git a/service/java/com/android/server/wifi/WifiSupplicantControl.java b/service/java/com/android/server/wifi/WifiSupplicantControl.java
index d05f3ef..15422d3 100644
--- a/service/java/com/android/server/wifi/WifiSupplicantControl.java
+++ b/service/java/com/android/server/wifi/WifiSupplicantControl.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wifi;
 
-import android.content.Context;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.wifi.WifiConfiguration;
@@ -25,6 +24,7 @@
 import android.net.wifi.WpsInfo;
 import android.net.wifi.WpsResult;
 import android.os.FileObserver;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
@@ -70,13 +70,14 @@
     private static final String TAG = "WifiSupplicantControl";
     private final LocalLog mLocalLog;
     private final WpaConfigFileObserver mFileObserver;
-    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
     private final WifiNative mWifiNative;
 
     private boolean mVerboseLoggingEnabled = false;
 
-    WifiSupplicantControl(Context context, WifiNative wifiNative, LocalLog localLog) {
-        mContext = context;
+    WifiSupplicantControl(TelephonyManager telephonyManager, WifiNative wifiNative,
+            LocalLog localLog) {
+        mTelephonyManager = telephonyManager;
         mWifiNative = wifiNative;
 
         mLocalLog = localLog;
@@ -885,7 +886,7 @@
         if (mVerboseLoggingEnabled) localLog("resetSimNetworks");
         for (WifiConfiguration config : configs) {
             if (TelephonyUtil.isSimConfig(config)) {
-                String currentIdentity = TelephonyUtil.getSimIdentity(mContext,
+                String currentIdentity = TelephonyUtil.getSimIdentity(mTelephonyManager,
                         config.enterpriseConfig.getEapMethod());
                 String supplicantIdentity =
                         mWifiNative.getNetworkVariable(config.networkId, "identity");
diff --git a/service/java/com/android/server/wifi/util/TelephonyUtil.java b/service/java/com/android/server/wifi/util/TelephonyUtil.java
index 3d7ce45..c8f292c 100644
--- a/service/java/com/android/server/wifi/util/TelephonyUtil.java
+++ b/service/java/com/android/server/wifi/util/TelephonyUtil.java
@@ -16,33 +16,34 @@
 
 package com.android.server.wifi.util;
 
-import android.content.Context;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiEnterpriseConfig;
 import android.telephony.TelephonyManager;
+import android.util.Base64;
+import android.util.Log;
 
 /**
  * Utilities for the Wifi Service to interact with telephony.
  */
 public class TelephonyUtil {
+    public static final String TAG = "TelephonyUtil";
 
     /**
      * Get the identity for the current SIM or null if the sim is not available
      */
-    public static String getSimIdentity(Context context, int eapMethod) {
-        TelephonyManager tm = TelephonyManager.from(context);
-        if (tm != null) {
-            String imsi = tm.getSubscriberId();
-            String mccMnc = "";
-
-            if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
-                mccMnc = tm.getSimOperator();
-            }
-
-            return buildIdentity(eapMethod, imsi, mccMnc);
-        } else {
+    public static String getSimIdentity(TelephonyManager tm, int eapMethod) {
+        if (tm == null) {
+            Log.e(TAG, "No valid TelephonyManager");
             return null;
         }
+        String imsi = tm.getSubscriberId();
+        String mccMnc = "";
+
+        if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
+            mccMnc = tm.getSimOperator();
+        }
+
+        return buildIdentity(eapMethod, imsi, mccMnc);
     }
 
     /**
@@ -112,4 +113,244 @@
                 || eapMethod == WifiEnterpriseConfig.Eap.AKA
                 || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME;
     }
+
+    // TODO replace some of this code with Byte.parseByte
+    private static int parseHex(char ch) {
+        if ('0' <= ch && ch <= '9') {
+            return ch - '0';
+        } else if ('a' <= ch && ch <= 'f') {
+            return ch - 'a' + 10;
+        } else if ('A' <= ch && ch <= 'F') {
+            return ch - 'A' + 10;
+        } else {
+            throw new NumberFormatException("" + ch + " is not a valid hex digit");
+        }
+    }
+
+    private static byte[] parseHex(String hex) {
+        /* This only works for good input; don't throw bad data at it */
+        if (hex == null) {
+            return new byte[0];
+        }
+
+        if (hex.length() % 2 != 0) {
+            throw new NumberFormatException(hex + " is not a valid hex string");
+        }
+
+        byte[] result = new byte[(hex.length()) / 2 + 1];
+        result[0] = (byte) ((hex.length()) / 2);
+        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
+            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i + 1));
+            byte b = (byte) (val & 0xFF);
+            result[j] = b;
+        }
+
+        return result;
+    }
+
+    private static String makeHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+
+    private static String makeHex(byte[] bytes, int from, int len) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            sb.append(String.format("%02x", bytes[from + i]));
+        }
+        return sb.toString();
+    }
+
+    private static byte[] concatHex(byte[] array1, byte[] array2) {
+
+        int len = array1.length + array2.length;
+
+        byte[] result = new byte[len];
+
+        int index = 0;
+        if (array1.length != 0) {
+            for (byte b : array1) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        if (array2.length != 0) {
+            for (byte b : array2) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        return result;
+    }
+
+    public static String getGsmSimAuthResponse(String[] requestData, TelephonyManager tm) {
+        if (tm == null) {
+            Log.e(TAG, "No valid TelephonyManager");
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (String challenge : requestData) {
+            if (challenge == null || challenge.isEmpty()) {
+                continue;
+            }
+            Log.d(TAG, "RAND = " + challenge);
+
+            byte[] rand = null;
+            try {
+                rand = parseHex(challenge);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "malformed challenge");
+                continue;
+            }
+
+            String base64Challenge = Base64.encodeToString(rand, Base64.NO_WRAP);
+
+            // Try USIM first for authentication.
+            String tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
+            if (tmResponse == null) {
+                // Then, in case of failure, issue may be due to sim type, retry as a simple sim
+                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
+            }
+            Log.v(TAG, "Raw Response - " + tmResponse);
+
+            if (tmResponse == null || tmResponse.length() <= 4) {
+                Log.e(TAG, "bad response - " + tmResponse);
+                return null;
+            }
+
+            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
+            Log.v(TAG, "Hex Response -" + makeHex(result));
+            int sresLen = result[0];
+            if (sresLen >= result.length) {
+                Log.e(TAG, "malfomed response - " + tmResponse);
+                return null;
+            }
+            String sres = makeHex(result, 1, sresLen);
+            int kcOffset = 1 + sresLen;
+            if (kcOffset >= result.length) {
+                Log.e(TAG, "malfomed response - " + tmResponse);
+                return null;
+            }
+            int kcLen = result[kcOffset];
+            if (kcOffset + kcLen > result.length) {
+                Log.e(TAG, "malfomed response - " + tmResponse);
+                return null;
+            }
+            String kc = makeHex(result, 1 + kcOffset, kcLen);
+            sb.append(":" + kc + ":" + sres);
+            Log.v(TAG, "kc:" + kc + " sres:" + sres);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Data supplied when making a SIM Auth Request
+     */
+    public static class SimAuthRequestData {
+        public SimAuthRequestData() {}
+        public SimAuthRequestData(int networkId, int protocol, String ssid, String[] data) {
+            this.networkId = networkId;
+            this.protocol = protocol;
+            this.ssid = ssid;
+            this.data = data;
+        }
+
+        public int networkId;
+        public int protocol;
+        public String ssid;
+        // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
+        // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
+        public String[] data;
+    }
+
+    /**
+     * The response to a SIM Auth request if successful
+     */
+    public static class SimAuthResponseData {
+        public SimAuthResponseData(String type, String response) {
+            this.type = type;
+            this.response = response;
+        }
+
+        public String type;
+        public String response;
+    }
+
+    public static SimAuthResponseData get3GAuthResponse(SimAuthRequestData requestData,
+            TelephonyManager tm) {
+        StringBuilder sb = new StringBuilder();
+        byte[] rand = null;
+        byte[] authn = null;
+        String resType = "UMTS-AUTH";
+
+        if (requestData.data.length == 2) {
+            try {
+                rand = parseHex(requestData.data[0]);
+                authn = parseHex(requestData.data[1]);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "malformed challenge");
+            }
+        } else {
+            Log.e(TAG, "malformed challenge");
+        }
+
+        String tmResponse = "";
+        if (rand != null && authn != null) {
+            String base64Challenge = Base64.encodeToString(concatHex(rand, authn), Base64.NO_WRAP);
+            if (tm != null) {
+                tmResponse = tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, base64Challenge);
+                Log.v(TAG, "Raw Response - " + tmResponse);
+            } else {
+                Log.e(TAG, "No valid TelephonyManager");
+            }
+        }
+
+        boolean goodReponse = false;
+        if (tmResponse != null && tmResponse.length() > 4) {
+            byte[] result = Base64.decode(tmResponse, Base64.DEFAULT);
+            Log.e(TAG, "Hex Response - " + makeHex(result));
+            byte tag = result[0];
+            if (tag == (byte) 0xdb) {
+                Log.v(TAG, "successful 3G authentication ");
+                int resLen = result[1];
+                String res = makeHex(result, 2, resLen);
+                int ckLen = result[resLen + 2];
+                String ck = makeHex(result, resLen + 3, ckLen);
+                int ikLen = result[resLen + ckLen + 3];
+                String ik = makeHex(result, resLen + ckLen + 4, ikLen);
+                sb.append(":" + ik + ":" + ck + ":" + res);
+                Log.v(TAG, "ik:" + ik + "ck:" + ck + " res:" + res);
+                goodReponse = true;
+            } else if (tag == (byte) 0xdc) {
+                Log.e(TAG, "synchronisation failure");
+                int autsLen = result[1];
+                String auts = makeHex(result, 2, autsLen);
+                resType = "UMTS-AUTS";
+                sb.append(":" + auts);
+                Log.v(TAG, "auts:" + auts);
+                goodReponse = true;
+            } else {
+                Log.e(TAG, "bad response - unknown tag = " + tag);
+            }
+        } else {
+            Log.e(TAG, "bad response - " + tmResponse);
+        }
+
+        if (goodReponse) {
+            String response = sb.toString();
+            Log.v(TAG, "Supplicant Response -" + response);
+            return new SimAuthResponseData(resType, response);
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index dbd8e32..5531eea 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -22,8 +22,8 @@
 import static org.mockito.Mockito.*;
 
 import android.app.ActivityManager;
-import android.app.test.TestAlarmManager;
 import android.app.test.MockAnswerUtil.AnswerWithArguments;
+import android.app.test.TestAlarmManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -63,7 +63,6 @@
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Base64;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -1057,59 +1056,6 @@
         assertEquals(true, result);
     }
 
-    private String createSimChallengeRequest(byte[] challengeValue) {
-        // Produce a base64 encoded length byte + data.
-        byte[] challengeLengthAndValue = new byte[challengeValue.length + 1];
-        challengeLengthAndValue[0] = (byte) challengeValue.length;
-        for (int i = 0; i < challengeValue.length; ++i) {
-            challengeLengthAndValue[i + 1] = challengeValue[i];
-        }
-        return Base64.encodeToString(challengeLengthAndValue, android.util.Base64.NO_WRAP);
-    }
-
-    private String createSimAuthResponse(byte[] sresValue, byte[] kcValue) {
-        // Produce a base64 encoded sres length byte + sres + kc length byte + kc.
-        int overallLength = sresValue.length + kcValue.length + 2;
-        byte[] result = new byte[sresValue.length + kcValue.length + 2];
-        int idx = 0;
-        result[idx++] = (byte) sresValue.length;
-        for (int i = 0; i < sresValue.length; ++i) {
-            result[idx++] = sresValue[i];
-        }
-        result[idx++] = (byte) kcValue.length;
-        for (int i = 0; i < kcValue.length; ++i) {
-            result[idx++] = kcValue[i];
-        }
-        return Base64.encodeToString(result, Base64.NO_WRAP);
-    }
-
-    /** Verifies function getGsmSimAuthResponse method. */
-    @Test
-    public void getGsmSimAuthResponseTest() throws Exception {
-        TelephonyManager tm = mock(TelephonyManager.class);
-        final String[] invalidRequests = { null, "", "XXXX" };
-        assertEquals("", mWsm.getGsmSimAuthResponse(invalidRequests, tm));
-
-        final String[] failedRequests = { "5E5F" };
-        when(tm.getIccAuthentication(anyInt(), anyInt(),
-                eq(createSimChallengeRequest(new byte[] { 0x5e, 0x5f })))).thenReturn(null);
-        assertEquals(null, mWsm.getGsmSimAuthResponse(failedRequests, tm));
-
-        when(tm.getIccAuthentication(2, tm.AUTHTYPE_EAP_SIM,
-                createSimChallengeRequest(new byte[] { 0x1a, 0x2b })))
-                .thenReturn(null);
-        when(tm.getIccAuthentication(1, tm.AUTHTYPE_EAP_SIM,
-                createSimChallengeRequest(new byte[] { 0x1a, 0x2b })))
-                .thenReturn(createSimAuthResponse(new byte[] { 0x1D, 0x2C },
-                       new byte[] { 0x3B, 0x4A }));
-        when(tm.getIccAuthentication(1, tm.AUTHTYPE_EAP_SIM,
-                createSimChallengeRequest(new byte[] { 0x01, 0x23 })))
-                .thenReturn(createSimAuthResponse(new byte[] { 0x33, 0x22 },
-                        new byte[] { 0x11, 0x00 }));
-        assertEquals(":3b4a:1d2c:1100:3322", mWsm.getGsmSimAuthResponse(
-                new String[] { "1A2B", "0123" }, tm));
-    }
-
     /**
      * Verifies that, by default, we allow only the "normal" number of log records.
      */
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiSupplicantControlTest.java b/tests/wifitests/src/com/android/server/wifi/WifiSupplicantControlTest.java
index ceb4b42..884d89f 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiSupplicantControlTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiSupplicantControlTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.content.Context;
+import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Before;
@@ -157,7 +157,7 @@
             + "}\n";
 
     @Mock private WifiNative mWifiNative;
-    @Mock private Context mContext;
+    @Mock private TelephonyManager mTelephonyManager;
     private WifiSupplicantControl mWifiSupplicantControl;
 
     /**
@@ -166,7 +166,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mWifiSupplicantControl = new WifiSupplicantControl(mContext, mWifiNative, null);
+        mWifiSupplicantControl = new WifiSupplicantControl(mTelephonyManager, mWifiNative, null);
     }
 
     /**
diff --git a/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java
new file mode 100644
index 0000000..e58d545
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/util/TelephonyUtilTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2016 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.util;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.net.wifi.WifiEnterpriseConfig;
+import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
+import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.util.TelephonyUtil}.
+ */
+@SmallTest
+public class TelephonyUtilTest {
+
+    @Test
+    public void getSimIdentityEapSim() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getSubscriberId()).thenReturn("3214561234567890");
+        when(tm.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(tm.getSimOperator()).thenReturn("321456");
+        assertEquals("13214561234567890@wlan.mnc456.mcc321.3gppnetwork.org",
+                TelephonyUtil.getSimIdentity(tm, WifiEnterpriseConfig.Eap.SIM));
+    }
+
+    @Test
+    public void getSimIdentityEapAka() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getSubscriberId()).thenReturn("3214561234567890");
+        when(tm.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(tm.getSimOperator()).thenReturn("321456");
+        assertEquals("03214561234567890@wlan.mnc456.mcc321.3gppnetwork.org",
+                TelephonyUtil.getSimIdentity(tm, WifiEnterpriseConfig.Eap.AKA));
+    }
+
+    @Test
+    public void getSimIdentityEapAkaPrime() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getSubscriberId()).thenReturn("3214561234567890");
+        when(tm.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(tm.getSimOperator()).thenReturn("321456");
+        assertEquals("63214561234567890@wlan.mnc456.mcc321.3gppnetwork.org",
+                TelephonyUtil.getSimIdentity(tm, WifiEnterpriseConfig.Eap.AKA_PRIME));
+    }
+
+    @Test
+    public void getSimIdentity2DigitMnc() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getSubscriberId()).thenReturn("321560123456789");
+        when(tm.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(tm.getSimOperator()).thenReturn("32156");
+        assertEquals("1321560123456789@wlan.mnc056.mcc321.3gppnetwork.org",
+                TelephonyUtil.getSimIdentity(tm, WifiEnterpriseConfig.Eap.SIM));
+    }
+
+    @Test
+    public void getSimIdentityUnknownMccMnc() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getSubscriberId()).thenReturn("3214560123456789");
+        when(tm.getSimState()).thenReturn(TelephonyManager.SIM_STATE_UNKNOWN);
+        when(tm.getSimOperator()).thenReturn(null);
+        assertEquals("13214560123456789@wlan.mnc456.mcc321.3gppnetwork.org",
+                TelephonyUtil.getSimIdentity(tm, WifiEnterpriseConfig.Eap.SIM));
+    }
+
+
+
+
+    /**
+     * Produce a base64 encoded length byte + data.
+     */
+    private static String createSimChallengeRequest(byte[] challengeValue) {
+        byte[] challengeLengthAndValue = new byte[challengeValue.length + 1];
+        challengeLengthAndValue[0] = (byte) challengeValue.length;
+        for (int i = 0; i < challengeValue.length; ++i) {
+            challengeLengthAndValue[i + 1] = challengeValue[i];
+        }
+        return Base64.encodeToString(challengeLengthAndValue, android.util.Base64.NO_WRAP);
+    }
+
+    /**
+     * Produce a base64 encoded sres length byte + sres + kc length byte + kc.
+     */
+    private static String createGsmSimAuthResponse(byte[] sresValue, byte[] kcValue) {
+        int overallLength = sresValue.length + kcValue.length + 2;
+        byte[] result = new byte[sresValue.length + kcValue.length + 2];
+        int idx = 0;
+        result[idx++] = (byte) sresValue.length;
+        for (int i = 0; i < sresValue.length; ++i) {
+            result[idx++] = sresValue[i];
+        }
+        result[idx++] = (byte) kcValue.length;
+        for (int i = 0; i < kcValue.length; ++i) {
+            result[idx++] = kcValue[i];
+        }
+        return Base64.encodeToString(result, Base64.NO_WRAP);
+    }
+
+    @Test
+    public void getGsmSimAuthResponseInvalidRequest() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        final String[] invalidRequests = { null, "", "XXXX" };
+        assertEquals("", TelephonyUtil.getGsmSimAuthResponse(invalidRequests, tm));
+    }
+
+    @Test
+    public void getGsmSimAuthResponseFailedSimResponse() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        final String[] failedRequests = { "5E5F" };
+        when(tm.getIccAuthentication(anyInt(), anyInt(),
+                eq(createSimChallengeRequest(new byte[] { 0x5e, 0x5f })))).thenReturn(null);
+
+        assertEquals(null, TelephonyUtil.getGsmSimAuthResponse(failedRequests, tm));
+    }
+
+    @Test
+    public void getGsmSimAuthResponseUsim() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x1b, 0x2b })))
+                .thenReturn(createGsmSimAuthResponse(new byte[] { 0x1D, 0x2C },
+                                new byte[] { 0x3B, 0x4A }));
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x01, 0x22 })))
+                .thenReturn(createGsmSimAuthResponse(new byte[] { 0x11, 0x11 },
+                                new byte[] { 0x12, 0x34 }));
+
+        assertEquals(":3b4a:1d2c:1234:1111", TelephonyUtil.getGsmSimAuthResponse(
+                        new String[] { "1B2B", "0122" }, tm));
+    }
+
+    @Test
+    public void getGsmSimAuthResponseSimpleSim() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x1a, 0x2b })))
+                .thenReturn(null);
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x1a, 0x2b })))
+                .thenReturn(createGsmSimAuthResponse(new byte[] { 0x1D, 0x2C },
+                                new byte[] { 0x3B, 0x4A }));
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x01, 0x23 })))
+                .thenReturn(null);
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_SIM,
+                        TelephonyManager.AUTHTYPE_EAP_SIM,
+                        createSimChallengeRequest(new byte[] { 0x01, 0x23 })))
+                .thenReturn(createGsmSimAuthResponse(new byte[] { 0x33, 0x22 },
+                                new byte[] { 0x11, 0x00 }));
+
+        assertEquals(":3b4a:1d2c:1100:3322", TelephonyUtil.getGsmSimAuthResponse(
+                        new String[] { "1A2B", "0123" }, tm));
+    }
+
+    /**
+     * Produce a base64 encoded tag + res length byte + res + ck length byte + ck + ik length byte +
+     * ik.
+     */
+    private static String create3GSimAuthUmtsAuthResponse(byte[] res, byte[] ck, byte[] ik) {
+        byte[] result = new byte[res.length + ck.length + ik.length + 4];
+        int idx = 0;
+        result[idx++] = (byte) 0xdb;
+        result[idx++] = (byte) res.length;
+        for (int i = 0; i < res.length; ++i) {
+            result[idx++] = res[i];
+        }
+        result[idx++] = (byte) ck.length;
+        for (int i = 0; i < ck.length; ++i) {
+            result[idx++] = ck[i];
+        }
+        result[idx++] = (byte) ik.length;
+        for (int i = 0; i < ik.length; ++i) {
+            result[idx++] = ik[i];
+        }
+        return Base64.encodeToString(result, Base64.NO_WRAP);
+    }
+
+    private static String create3GSimAuthUmtsAutsResponse(byte[] auts) {
+        byte[] result = new byte[auts.length + 2];
+        int idx = 0;
+        result[idx++] = (byte) 0xdc;
+        result[idx++] = (byte) auts.length;
+        for (int i = 0; i < auts.length; ++i) {
+            result[idx++] = auts[i];
+        }
+        return Base64.encodeToString(result, Base64.NO_WRAP);
+    }
+
+    @Test
+    public void get3GAuthResponseInvalidRequest() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+        assertEquals(null, TelephonyUtil.get3GAuthResponse(
+                        new SimAuthRequestData(0, 0, "SSID", new String[] {"0123"}), tm));
+        assertEquals(null, TelephonyUtil.get3GAuthResponse(
+                        new SimAuthRequestData(0, 0, "SSID", new String[] {"xyz2", "1234"}), tm));
+        verifyNoMoreInteractions(tm);
+    }
+
+    @Test
+    public void get3GAuthResponseNullIccAuthentication() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "AgEjAkVn")).thenReturn(null);
+
+        SimAuthResponseData response = TelephonyUtil.get3GAuthResponse(
+                new SimAuthRequestData(0, 0, "SSID", new String[] {"0123", "4567"}), tm);
+        assertNull(response);
+    }
+
+    @Test
+    public void get3GAuthResponseIccAuthenticationTooShort() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "AgEjAkVn"))
+                .thenReturn(Base64.encodeToString(new byte[] {(byte) 0xdc}, Base64.NO_WRAP));
+
+        SimAuthResponseData response = TelephonyUtil.get3GAuthResponse(
+                new SimAuthRequestData(0, 0, "SSID", new String[] {"0123", "4567"}), tm);
+        assertNull(response);
+    }
+
+    @Test
+    public void get3GAuthResponseBadTag() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "AgEjAkVn"))
+                .thenReturn(Base64.encodeToString(new byte[] {0x31, 0x1, 0x2, 0x3, 0x4},
+                                Base64.NO_WRAP));
+
+        SimAuthResponseData response = TelephonyUtil.get3GAuthResponse(
+                new SimAuthRequestData(0, 0, "SSID", new String[] {"0123", "4567"}), tm);
+        assertNull(response);
+    }
+
+    @Test
+    public void get3GAuthResponseUmtsAuth() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "AgEjAkVn"))
+                .thenReturn(create3GSimAuthUmtsAuthResponse(new byte[] {0x11, 0x12},
+                                new byte[] {0x21, 0x22, 0x23}, new byte[] {0x31}));
+
+        SimAuthResponseData response = TelephonyUtil.get3GAuthResponse(
+                new SimAuthRequestData(0, 0, "SSID", new String[] {"0123", "4567"}), tm);
+        assertNotNull(response);
+        assertEquals("UMTS-AUTH", response.type);
+        assertEquals(":31:212223:1112", response.response);
+    }
+
+    @Test
+    public void get3GAuthResponseUmtsAuts() {
+        TelephonyManager tm = mock(TelephonyManager.class);
+
+        when(tm.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "AgEjAkVn"))
+                .thenReturn(create3GSimAuthUmtsAutsResponse(new byte[] {0x22, 0x33}));
+
+        SimAuthResponseData response = TelephonyUtil.get3GAuthResponse(
+                new SimAuthRequestData(0, 0, "SSID", new String[] {"0123", "4567"}), tm);
+        assertNotNull(response);
+        assertEquals("UMTS-AUTS", response.type);
+        assertEquals(":2233", response.response);
+    }
+}