merge in lmp-release history after reset to 8e6144b4059fc2117be23d7222893bc57a33f64d
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 0760605..e2046a3 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -114,6 +114,8 @@
 
     private static final String IDENTITY_STR = "IDENTITY";
 
+    private static final String SIM_STR = "SIM";
+
 
     //used to debug and detect if we miss an event
     private static int eventLogCounter = 0;
@@ -231,11 +233,27 @@
     /**
      * Regex pattern for extracting SSIDs from request identity string.
      * Matches a strings like the following:<pre>
+     * CTRL-REQ-SIM-<network id>:GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>] needed for SSID <SSID>
+     * This pattern should find
+     *    0 - id
+     *    1 - Rand1
+     *    2 - Rand2
+     *    3 - Rand3
+     *    4 - SSID
+     */
+    private static Pattern mRequestSimAuthPattern =
+            Pattern.compile("SIM-([0-9]*):GSM-AUTH(:[0-9a-f]*)(:[0-9a-f]*)(:[0-9a-f]*)?"
+                    + " needed for SSID (.+)");
+
+    /**
+     * Regex pattern for extracting SSIDs from request identity string.
+     * Matches a strings like the following:<pre>
      * CTRL-REQ-IDENTITY-1:Identity needed for SSID XXXX</pre>
      */
     private static Pattern mRequestIdentityPattern =
             Pattern.compile("IDENTITY-[0-9]:Identity needed for SSID (.+)");
 
+
     /** P2P events */
     private static final String P2P_EVENT_PREFIX_STR = "P2P";
 
@@ -385,6 +403,9 @@
     /* Request Identity */
     public static final int SUP_REQUEST_IDENTITY                 = BASE + 15;
 
+    /* Request SIM Auth */
+    public static final int SUP_REQUEST_SIM_AUTH                 = BASE + 16;
+
     /* P2P events */
     public static final int P2P_DEVICE_FOUND_EVENT               = BASE + 21;
     public static final int P2P_DEVICE_LOST_EVENT                = BASE + 22;
@@ -1091,9 +1112,25 @@
             if (match.find()) {
                 SSID = match.group(1);
             } else {
-                Log.e(TAG, "didnt find SSID " + requestName);
+                Log.e(TAG, "didn't find SSID " + requestName);
             }
             mStateMachine.sendMessage(SUP_REQUEST_IDENTITY, eventLogCounter, 0, SSID);
+        } if (requestName.startsWith(SIM_STR)) {
+            Matcher match = mRequestSimAuthPattern.matcher(requestName);
+            if (match.find()) {
+                WifiStateMachine.SimAuthRequestData data =
+                        new WifiStateMachine.SimAuthRequestData();
+                data.networkId = Integer.parseInt(match.group(1));
+                data.ssid = match.group(5);
+                data.rand1 = match.group(2).substring(1);
+                data.rand2 = match.group(3).substring(1);
+                data.rand3 = match.group(4).substring(1);
+
+                mStateMachine.sendMessage(SUP_REQUEST_SIM_AUTH, data);
+            } else {
+                Log.e(TAG, "couldn't parse SIM auth request - " + requestName);
+            }
+
         } else {
             if (DBG) Log.w(TAG, "couldn't identify request type - " + dataString);
         }
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 253a53e..1381d8a 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -672,6 +672,19 @@
         }
     }
 
+    public boolean setExternalSim(boolean external) {
+        synchronized (mLock) {
+            String value = external ? "1" : "0";
+            return doBooleanCommand("set external_sim " + value);
+        }
+    }
+
+    public boolean simAuthResponse(int id, String response) {
+        synchronized (mLock) {
+            return doBooleanCommand("SIM " + id + ":GSM-AUTH:" + response);
+        }
+    }
+
     /* Configures an access point connection */
     public boolean startWpsRegistrar(String bssid, String pin) {
         if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 9ab8e3f..f5eb08b 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1228,6 +1228,10 @@
     }
 
     public void enableTdls(String remoteAddress, boolean enable) {
+        if (remoteAddress == null) {
+          throw new IllegalArgumentException("remoteAddress cannot be null");
+        }
+
         TdlsTaskParams params = new TdlsTaskParams();
         params.remoteIpAddress = remoteAddress;
         params.enable = enable;
@@ -1236,6 +1240,10 @@
 
 
     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
+        if (remoteMacAddress == null) {
+          throw new IllegalArgumentException("remoteMacAddress cannot be null");
+        }
+
         mWifiStateMachine.enableTdls(remoteMacAddress, enable);
     }
 
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index f148c02..d0dafae 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -76,6 +76,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.util.LruCache;
 import android.text.TextUtils;
 import android.util.Log;
@@ -692,6 +693,23 @@
         }
     }
 
+    public static class SimAuthRequestData {
+        int networkId;
+        String ssid;
+        String rand1;
+        String rand2;
+        String rand3;
+    }
+
+    public static class SimAuthResponseData {
+        int id;
+        String Kc1;
+        String SRES1;
+        String Kc2;
+        String SRES2;
+        String Kc3;
+        String SRES3;
+    }
 
     /**
      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
@@ -3892,6 +3910,7 @@
                 case WifiMonitor.SUP_REQUEST_IDENTITY:
                 case CMD_TEST_NETWORK_DISCONNECT:
                 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
+                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
                     break;
                 case DhcpStateMachine.CMD_ON_QUIT:
                     mDhcpStateMachine = null;
@@ -4154,6 +4173,7 @@
                     defaultInterval);
 
             mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
+            mWifiNative.setExternalSim(true);
 
             if (mFrameworkAutoJoin.get()) {
                 mWifiNative.enableAutoConnect(false);
@@ -5314,6 +5334,15 @@
                             (WifiConfiguration.INVALID_NETWORK_ID);
                     mWifiNative.disconnect();
                     break;
+                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
+                    logd("Received SUP_REQUEST_SIM_AUTH");
+                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
+                    if (requestData != null) {
+                        handleSimAuthRequest(requestData);
+                    } else {
+                        loge("Invalid sim auth request");
+                    }
+                    break;
                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
                     replyToMessage(message, message.what,
                             mWifiConfigStore.getPrivilegedConfiguredNetworks());
@@ -6924,4 +6953,151 @@
         msg.arg2 = srcMsg.arg2;
         return msg;
     }
+
+    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];
+        for (int i = 0, j = 0; 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 byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
+
+        int len = array1.length + array2.length + array3.length;
+
+        if (array1.length != 0) {
+            len++;                      /* add another byte for size */
+        }
+
+        if (array2.length != 0) {
+            len++;                      /* add another byte for size */
+        }
+
+        if (array3.length != 0) {
+            len++;                      /* add another byte for size */
+        }
+
+        byte[] result = new byte[len];
+
+        int index = 0;
+        if (array1.length != 0) {
+            result[index] = (byte) (array1.length & 0xFF);
+            index++;
+            for (byte b : array1) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        if (array2.length != 0) {
+            result[index] = (byte) (array2.length & 0xFF);
+            index++;
+            for (byte b : array2) {
+                result[index] = b;
+                index++;
+            }
+        }
+
+        if (array3.length != 0) {
+            result[index] = (byte) (array3.length & 0xFF);
+            index++;
+            for (byte b : array3) {
+                result[index] = b;
+                index++;
+            }
+        }
+        return result;
+    }
+
+    void handleSimAuthRequest(SimAuthRequestData requestData) {
+        if (targetWificonfiguration == null
+                || targetWificonfiguration.networkId == requestData.networkId) {
+            logd("id matches targetWifiConfiguration");
+        } else {
+            logd("id does not match targetWifiConfiguration");
+        }
+
+        logd("rand1 = " + requestData.rand1);
+        logd("rand2 = " + requestData.rand2);
+        logd("rand3 = " + requestData.rand3);
+
+        byte[] rand1, rand2, rand3;
+
+        try {
+            rand1 = parseHex(requestData.rand1);
+            rand2 = parseHex(requestData.rand2);
+            rand3 = parseHex(requestData.rand3);
+        } catch (NumberFormatException e) {
+            loge("malformed challenge");
+            return;
+        }
+
+        byte[] c = concat(rand1, rand2, rand3);
+
+        String challenge = android.util.Base64.encodeToString(c, android.util.Base64.NO_WRAP);
+
+        logd("challenge = " + challenge);
+        logd("challenge length = " + challenge.length());
+
+        TelephonyManager tm = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+        if (tm != null) {
+            /*
+             * appType = 1 => SIM, 2 => USIM according to
+             * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
+             */
+
+            int appType = 2;
+            String response = tm.getIccSimChallengeResponse(appType, challenge);
+            logd("Raw Response - " + response);
+
+            if (response != null) {
+                byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
+                response = makeHex(result);
+                logd("Sim Response - " + response);
+                mWifiNative.simAuthResponse(requestData.networkId, response);
+            } else {
+                logd("bad response - " + response);
+            }
+
+        } else {
+            loge("could not get telephony manager");
+        }
+
+    }
 }