Merge "Use correct P2P GO intent value"
diff --git a/libwifi_hal/Android.mk b/libwifi_hal/Android.mk
index a34075d..b06171f 100644
--- a/libwifi_hal/Android.mk
+++ b/libwifi_hal/Android.mk
@@ -64,9 +64,11 @@
 # ============================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libwifi-hal-common
+LOCAL_VENDOR_MODULE := true
 LOCAL_CFLAGS := $(wifi_hal_cflags)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := libbase
+LOCAL_HEADER_LIBRARIES := libcutils_headers
 LOCAL_SRC_FILES := wifi_hal_common.cpp
 include $(BUILD_STATIC_LIBRARY)
 
@@ -75,6 +77,7 @@
 # ============================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libwifi-hal-fallback
+LOCAL_VENDOR_MODULE := true
 LOCAL_CFLAGS := $(wifi_hal_cflags)
 LOCAL_SRC_FILES := wifi_hal_fallback.cpp
 LOCAL_HEADER_LIBRARIES := libhardware_legacy_headers
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index c5f3675..b81878d 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -703,6 +703,29 @@
     }
 
     /**
+     * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
+     *
+     * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
+     *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
+     *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
+     *
+     * @param ifaceName String name of the updated interface
+     * @param mode new operating mode of the interface
+     *
+     * @throws SecurityException if the caller does not have permission to call update
+     */
+    @Override
+    public void updateInterfaceIpState(String ifaceName, int mode) {
+        // NETWORK_STACK is a signature only permission.
+        enforceNetworkStackPermission();
+
+        Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode);
+        // TODO: keep track of modes in a datastructure - protect it with a lock of some sort.
+        // TODO: check the mode when startLOHS comes in in case it is already active
+        // TODO: if mode == LOCAL_ONLY, trigger onStarted callbacks
+    }
+
+    /**
      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
      * @param wifiConfig SSID, security and channel details as
      *        part of WifiConfiguration
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index ccd1d46..21d6be1 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -5800,7 +5800,9 @@
         // If this network was explicitly selected by the user, evaluate whether to call
         // explicitlySelected() so the system can treat it appropriately.
         WifiConfiguration config = getCurrentWifiConfiguration();
-        if (mWifiConfigManager.getLastSelectedNetwork() == config.networkId) {
+        if (config == null) {
+            Log.wtf(TAG, "Current WifiConfiguration is null, but IP provisioning just succeeded");
+        } else if (mWifiConfigManager.getLastSelectedNetwork() == config.networkId) {
             boolean prompt =
                     mWifiPermissionsUtil.checkConfigOverridePermission(config.lastConnectUid);
             if (mVerboseLoggingEnabled) {
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
index 14d855e..723828d 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
@@ -592,8 +592,6 @@
                 return true;
             }
 
-            // TODO: validate that the client ID actually comes from the correct process and is
-            // not faked?
             nnri = AwareNetworkRequestInformation.processNetworkSpecifier(networkSpecifier, mMgr);
             if (nnri == null) {
                 Log.e(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
@@ -903,6 +901,13 @@
                 }
             }
 
+            // validate UID
+            if (ns.requestorUid != uid) {
+                Log.e(TAG, "processNetworkSpecifier: networkSpecifier=" + ns.toString()
+                        + " -- UID mismatch to clientId's uid=" + uid);
+                return null;
+            }
+
             // create container and populate
             AwareNetworkRequestInformation nnri = new AwareNetworkRequestInformation();
             nnri.state = (ns.role == WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR)
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index 6de39ac..8b687db 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -81,7 +81,8 @@
      * @param context Context object of the caller.
      */
     public void enforceTetherChangePermission(Context context) {
-        ConnectivityManager.enforceTetherChangePermission(context);
+        String pkgName = context.getOpPackageName();
+        ConnectivityManager.enforceTetherChangePermission(context, pkgName);
     }
 
     /**
diff --git a/tests/wifitests/Android.mk b/tests/wifitests/Android.mk
index b285db6..5dbd756 100644
--- a/tests/wifitests/Android.mk
+++ b/tests/wifitests/Android.mk
@@ -100,7 +100,6 @@
 	libstagefright_foundation \
 	libstdc++ \
 	libsync \
-	libwifi-hal \
 	libwifi-system \
 	libui \
 	libunwind \
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
index e7a383c..a2e7c77 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -57,6 +57,7 @@
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.Messenger;
+import android.os.Process;
 import android.os.test.TestLooper;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
@@ -302,6 +303,23 @@
         testDataPathInitiatorResponderMismatchUtility(true);
     }
 
+    /**
+     * Validate the fail flow of an Initiator (subscriber) with its UID unset
+     */
+    @Test
+    public void testDataPathInitiatorUidUnsetError() throws Exception {
+        testDataPathInitiatorResponderInvalidUidUtility(false, false);
+    }
+
+    /**
+     * Validate the fail flow of an Initiator (subscriber) with its UID set as a malicious
+     * attacker (i.e. mismatched to its requested client's UID).
+     */
+    @Test
+    public void testDataPathInitiatorUidSetIncorrectlyError() throws Exception {
+        testDataPathInitiatorResponderInvalidUidUtility(false, true);
+    }
+
     /*
      * Responder tests
      */
@@ -395,6 +413,23 @@
         testDataPathInitiatorResponderMismatchUtility(false);
     }
 
+    /**
+     * Validate the fail flow of an Initiator (subscriber) with its UID unset
+     */
+    @Test
+    public void testDataPathResponderUidUnsetError() throws Exception {
+        testDataPathInitiatorResponderInvalidUidUtility(true, false);
+    }
+
+    /**
+     * Validate the fail flow of an Initiator (subscriber) with its UID set as a malicious
+     * attacker (i.e. mismatched to its requested client's UID).
+     */
+    @Test
+    public void testDataPathResponderUidSetIncorrectlyError() throws Exception {
+        testDataPathInitiatorResponderInvalidUidUtility(true, true);
+    }
+
     /*
      * Utilities
      */
@@ -428,8 +463,8 @@
                 ns.peerId,
                 ns.peerMac,
                 ns.pmk,
-                ns.passphrase
-                );
+                ns.passphrase,
+                ns.requestorUid);
         nr.networkCapabilities.setNetworkSpecifier(ns);
 
         Message reqNetworkMsg = Message.obtain();
@@ -453,6 +488,62 @@
         verifyNoMoreInteractions(mMockNative, mMockCm);
     }
 
+    private void testDataPathInitiatorResponderInvalidUidUtility(boolean doPublish,
+            boolean isUidSet) throws Exception {
+        final int clientId = 123;
+        final int pubSubId = 11234;
+        final int ndpId = 2;
+        final byte[] pmk = "some bytes".getBytes();
+        final PeerHandle peerHandle = new PeerHandle(1341234);
+        final byte[] peerDiscoveryMac = HexEncoding.decode("000102030405".toCharArray(), false);
+
+        InOrder inOrder = inOrder(mMockNative, mMockCm, mMockCallback, mMockSessionCallback);
+
+        // (0) initialize
+        Pair<Integer, Messenger> res = initDataPathEndPoint(clientId, pubSubId, peerHandle,
+                peerDiscoveryMac, inOrder, doPublish);
+
+        // (1) create network request
+        NetworkRequest nr = getSessionNetworkRequest(clientId, res.first, peerHandle, pmk,
+                doPublish);
+
+        // (2) corrupt request's UID
+        WifiAwareNetworkSpecifier ns =
+                (WifiAwareNetworkSpecifier) nr.networkCapabilities.getNetworkSpecifier();
+        ns = new WifiAwareNetworkSpecifier(
+                ns.type,
+                ns.role,
+                ns.clientId,
+                ns.sessionId,
+                ns.peerId,
+                ns.peerMac,
+                ns.pmk,
+                ns.passphrase,
+                ns.requestorUid + 1); // corruption hack
+        nr.networkCapabilities.setNetworkSpecifier(ns);
+
+        // (3) request network
+        Message reqNetworkMsg = Message.obtain();
+        reqNetworkMsg.what = NetworkFactory.CMD_REQUEST_NETWORK;
+        reqNetworkMsg.obj = nr;
+        reqNetworkMsg.arg1 = 0;
+        res.second.send(reqNetworkMsg);
+        mMockLooper.dispatchAll();
+
+        // consequences of failure:
+        //   Responder (publisher): responds with a rejection to any data-path requests
+        //   Initiator (subscribe): doesn't initiate (i.e. no HAL requests)
+        if (doPublish) {
+            // (2) get request & respond
+            mDut.onDataPathRequestNotification(pubSubId, peerDiscoveryMac, ndpId);
+            mMockLooper.dispatchAll();
+            inOrder.verify(mMockNative).respondToDataPathRequest(anyShort(), eq(false),
+                    eq(ndpId), eq(""), eq(null), eq(null), any());
+        }
+
+        verifyNoMoreInteractions(mMockNative, mMockCm);
+    }
+
     private void testDataPathInitiatorUtility(boolean useDirect, boolean provideMac,
             boolean providePmk, boolean getConfirmation, boolean immediateHalFailure)
             throws Exception {
@@ -751,7 +842,6 @@
             PeerHandle peerHandle, byte[] peerDiscoveryMac, InOrder inOrder,
             boolean doPublish)
             throws Exception {
-        final int uid = 1000;
         final int pid = 2000;
         final String callingPackage = "com.android.somePackage";
         final String someMsg = "some arbitrary message from peer";
@@ -790,7 +880,8 @@
         mMockLooper.dispatchAll();
 
         // (3) create client & session & rx message
-        mDut.connect(clientId, uid, pid, callingPackage, mMockCallback, configRequest, false);
+        mDut.connect(clientId, Process.myUid(), pid, callingPackage, mMockCallback, configRequest,
+                false);
         mMockLooper.dispatchAll();
         inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
                 eq(configRequest), eq(false), eq(true));