Merge "Verify pending intent flags"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index f89ee24..bc2be14 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -32,6 +32,7 @@
         "android.hardware.tetheroffload.config-V1.0-java",
         "android.hardware.tetheroffload.control-V1.0-java",
         "net-utils-framework-common",
+        "net-utils-device-common",
     ],
     libs: [
         "framework-tethering.impl",
diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml
index 2b2fe45..e6444f3 100644
--- a/Tethering/AndroidManifest.xml
+++ b/Tethering/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <!-- Permissions must be defined here, and not in the base manifest, as the tethering
          running in the system server process does not need any permission, and having
          privileged permissions added would cause crashes on startup unless they are also
-         added to the privileged permissions whitelist for that package. -->
+         added to the privileged permissions allowlist for that package. -->
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt
index 2c4059d..591861f 100644
--- a/Tethering/jarjar-rules.txt
+++ b/Tethering/jarjar-rules.txt
@@ -1,17 +1,8 @@
 # These must be kept in sync with the framework-tethering-shared-srcs filegroup.
-# If there are files in that filegroup that do not appear here, the classes in the
+# Classes from the framework-tethering-shared-srcs filegroup.
+# If there are files in that filegroup that are not covered below, the classes in the
 # module will be overwritten by the ones in the framework.
-# Don't jar-jar the entire package because tethering still use some internal classes
-# (like TrafficStatsConstants in com.android.internal.util)
-# TODO: simply these when tethering is built as system_current.
-rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1
-rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1
-rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1
-rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1
-rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1
-rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1
-rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
-
+rule com.android.internal.util.** com.android.networkstack.tethering.util.@1
 rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
 
 rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags
index 051fbd1..86b9033 100644
--- a/Tethering/proguard.flags
+++ b/Tethering/proguard.flags
@@ -1,5 +1,5 @@
 # Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMasterSM {
+-keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
     static final int CMD_*;
     static final int EVENT_*;
 }
diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml
index 4807e52..89a9046 100644
--- a/Tethering/res/values/config.xml
+++ b/Tethering/res/values/config.xml
@@ -71,6 +71,9 @@
     <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
     <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
 
+    <!-- Use legacy wifi p2p dedicated address instead of randomize address. -->
+    <bool translatable="false" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip">false</bool>
+
     <!-- Dhcp range (min, max) to use for tethering purposes -->
     <string-array translatable="false" name="config_tether_dhcp_range">
     </string-array>
diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml
index 6a33d55..0ee7a99 100644
--- a/Tethering/res/values/overlayable.xml
+++ b/Tethering/res/values/overlayable.xml
@@ -30,6 +30,7 @@
             -->
             <item type="bool" name="config_tether_enable_bpf_offload"/>
             <item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+            <item type="bool" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip"/>
             <item type="integer" name="config_tether_offload_poll_interval"/>
             <item type="array" name="config_tether_upstream_types"/>
             <item type="bool" name="config_tether_upstream_automatic"/>
diff --git a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
index 4710a30..aaaec17 100644
--- a/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ b/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -16,7 +16,7 @@
 
 package android.net.dhcp;
 
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
 
 import android.net.LinkAddress;
 import android.util.ArraySet;
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index a61fcfb..673cbf0 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -19,13 +19,14 @@
 import static android.net.RouteInfo.RTN_UNICAST;
 import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
 import static android.net.util.NetworkConstants.asByte;
 import static android.net.util.PrefixUtils.asIpPrefix;
 import static android.net.util.TetheringMessageBase.BASE_IPSERVER;
 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
 
+import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+
 import android.net.INetd;
 import android.net.INetworkStackStatusCallback;
 import android.net.IpPrefix;
@@ -196,15 +197,19 @@
     public static final int CMD_TETHER_UNREQUESTED          = BASE_IPSERVER + 2;
     // notification that this interface is down
     public static final int CMD_INTERFACE_DOWN              = BASE_IPSERVER + 3;
-    // notification from the master SM that it had trouble enabling IP Forwarding
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble enabling IP
+    // Forwarding
     public static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IPSERVER + 4;
-    // notification from the master SM that it had trouble disabling IP Forwarding
+    // notification from the {@link Tethering.TetherMainSM} SM that it had trouble disabling IP
+    // Forwarding
     public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5;
-    // notification from the master SM that it had trouble starting tethering
+    // notification from the {@link Tethering.TetherMainSM} SM that it had trouble starting
+    // tethering
     public static final int CMD_START_TETHERING_ERROR       = BASE_IPSERVER + 6;
-    // notification from the master SM that it had trouble stopping tethering
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble stopping tethering
     public static final int CMD_STOP_TETHERING_ERROR        = BASE_IPSERVER + 7;
-    // notification from the master SM that it had trouble setting the DNS forwarders
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble setting the DNS
+    // forwarders
     public static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IPSERVER + 8;
     // the upstream connection has changed
     public static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IPSERVER + 9;
@@ -422,9 +427,13 @@
             getHandler().post(() -> {
                 // We are on the handler thread: mDhcpServerStartIndex can be read safely.
                 if (mStartIndex != mDhcpServerStartIndex) {
-                    // This start request is obsolete. When the |server| binder token goes out of
-                    // scope, the garbage collector will finalize it, which causes the network stack
-                    // process garbage collector to collect the server itself.
+                     // This start request is obsolete. Explicitly stop the DHCP server to shut
+                     // down its thread. When the |server| binder token goes out of scope, the
+                     // garbage collector will finalize it, which causes the network stack process
+                     // garbage collector to collect the server itself.
+                    try {
+                        server.stop(null);
+                    } catch (RemoteException e) { }
                     return;
                 }
 
@@ -1315,7 +1324,7 @@
 
     /**
      * This state is terminal for the per interface state machine.  At this
-     * point, the master state machine should have removed this interface
+     * point, the tethering main state machine should have removed this interface
      * specific state machine from its list of possible recipients of
      * tethering requests.  The state machine itself will hang around until
      * the garbage collector finds it.
diff --git a/Tethering/src/android/net/util/TetheringMessageBase.java b/Tethering/src/android/net/util/TetheringMessageBase.java
index 1b763ce..29c0a81 100644
--- a/Tethering/src/android/net/util/TetheringMessageBase.java
+++ b/Tethering/src/android/net/util/TetheringMessageBase.java
@@ -19,7 +19,7 @@
  * This class defines Message.what base addresses for various state machine.
  */
 public class TetheringMessageBase {
-    public static final int BASE_MASTER   = 0;
+    public static final int BASE_MAIN_SM   = 0;
     public static final int BASE_IPSERVER = 100;
 
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 9dace70..bb7322f 100644
--- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -296,16 +296,16 @@
      * Reference TetheringManager.TETHERING_{@code *} for each tether type.
      *
      * @param config an object that encapsulates the various tethering configuration elements.
-     * Note: this method is only called from TetherMaster on the handler thread.
+     * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread.
      * If there are new callers from different threads, the logic should move to
-     * masterHandler to avoid race conditions.
+     * @{link Tethering.TetherMainSM} handler to avoid race conditions.
      */
     public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
         if (DBG) mLog.i("reevaluateSimCardProvisioning");
 
         if (!mHandler.getLooper().isCurrentThread()) {
             // Except for test, this log should not appear in normal flow.
-            mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
+            mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread");
         }
         mEntitlementCacheValue.clear();
         mCurrentEntitlementResults.clear();
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index aa58a4b..fd9e360 100644
--- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,8 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static java.util.Arrays.asList;
 
 import android.content.Context;
@@ -58,6 +60,7 @@
     private static final int BYTE_MASK = 0xff;
     // reserved for bluetooth tethering.
     private static final int BLUETOOTH_RESERVED = 44;
+    private static final int WIFI_P2P_RESERVED = 49;
     private static final byte DEFAULT_ID = (byte) 42;
 
     // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -71,15 +74,18 @@
     // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
     // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
     private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
+    private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
     private final IpPrefix mTetheringPrefix;
     private final ConnectivityManager mConnectivityMgr;
+    private final TetheringConfiguration mConfig;
 
-    public PrivateAddressCoordinator(Context context) {
+    public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
         mDownstreams = new ArraySet<>();
         mUpstreamPrefixMap = new ArrayMap<>();
         mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
         mConnectivityMgr = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
+        mConfig = config;
     }
 
     /**
@@ -141,12 +147,21 @@
         mUpstreamPrefixMap.removeAll(toBeRemoved);
     }
 
+    private boolean isReservedSubnet(final int subnet) {
+        return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
+    }
+
     /**
      * Pick a random available address and mark its prefix as in use for the provided IpServer,
      * returns null if there is no available address.
      */
     @Nullable
     public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+        if (mConfig.shouldEnableWifiP2pDedicatedIp()
+                && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
+            return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
+        }
+
         // Address would be 192.168.[subAddress]/24.
         final byte[] bytes = mTetheringPrefix.getRawAddress();
         final int subAddress = getRandomSubAddr();
@@ -154,7 +169,7 @@
         bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
         for (int i = 0; i < MAX_UBYTE; i++) {
             final int newSubNet = (subNet + i) & BYTE_MASK;
-            if (newSubNet == BLUETOOTH_RESERVED) continue;
+            if (isReservedSubnet(newSubNet)) continue;
 
             bytes[2] = (byte) newSubNet;
             final InetAddress addr;
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 3627085..255cf75 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -50,7 +50,7 @@
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-import static android.net.util.TetheringMessageBase.BASE_MASTER;
+import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -159,7 +159,7 @@
     private static final boolean VDBG = false;
 
     private static final Class[] sMessageClasses = {
-            Tethering.class, TetherMasterSM.class, IpServer.class
+            Tethering.class, TetherMainSM.class, IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(sMessageClasses);
@@ -216,7 +216,7 @@
     private final ArrayMap<String, TetherState> mTetherStates;
     private final BroadcastReceiver mStateReceiver;
     private final Looper mLooper;
-    private final StateMachine mTetherMasterSM;
+    private final StateMachine mTetherMainSM;
     private final OffloadController mOffloadController;
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     // TODO: Figure out how to merge this and other downstream-tracking objects
@@ -273,10 +273,10 @@
         mTetherStates = new ArrayMap<>();
         mConnectedClientsTracker = new ConnectedClientsTracker();
 
-        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
-        mTetherMasterSM.start();
+        mTetherMainSM = new TetherMainSM("TetherMain", mLooper, deps);
+        mTetherMainSM.start();
 
-        mHandler = mTetherMasterSM.getHandler();
+        mHandler = mTetherMainSM.getHandler();
         mOffloadController = mDeps.getOffloadController(mHandler, mLog,
                 new OffloadController.Dependencies() {
 
@@ -285,8 +285,8 @@
                         return mConfig;
                     }
                 });
-        mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
-                TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+        mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog,
+                TetherMainSM.EVENT_UPSTREAM_CALLBACK);
         mForwardedDownstreams = new LinkedHashSet<>();
 
         IntentFilter filter = new IntentFilter();
@@ -294,8 +294,8 @@
         // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
         // permission is changed according to entitlement check result.
         mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
-                () -> mTetherMasterSM.sendMessage(
-                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
+                () -> mTetherMainSM.sendMessage(
+                TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
         mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
             mLog.log("OBSERVED UiEnitlementFailed");
             stopTethering(downstream);
@@ -320,10 +320,13 @@
         mExecutor = new TetheringThreadExecutor(mHandler);
         mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
         mNetdCallback = new NetdCallback();
-        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext);
 
         // Load tethering configuration.
         updateConfiguration();
+        // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
+        // construction time because the only part of the configuration it uses is
+        // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
+        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
 
         // Must be initialized after tethering configuration is loaded because BpfCoordinator
         // constructor needs to use the configuration.
@@ -945,7 +948,7 @@
             }
 
             if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+            mTetherMainSM.sendMessage(TetherMainSM.CMD_UPSTREAM_CHANGED);
         }
 
         private void handleUsbAction(Intent intent) {
@@ -1170,7 +1173,7 @@
     private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
         if (TextUtils.isEmpty(ifname)) return;
 
-        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0);
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -1381,23 +1384,23 @@
         return false;
     }
 
-    class TetherMasterSM extends StateMachine {
+    class TetherMainSM extends StateMachine {
         // an interface SM has requested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MASTER + 1;
+        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MAIN_SM + 1;
         // an interface SM has unrequested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MASTER + 2;
+        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MAIN_SM + 2;
         // upstream connection change - do the right thing
-        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
+        static final int CMD_UPSTREAM_CHANGED                   = BASE_MAIN_SM + 3;
         // we don't have a valid upstream conn, check again after a delay
-        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
-        // Events from NetworkCallbacks that we process on the master state
+        static final int CMD_RETRY_UPSTREAM                     = BASE_MAIN_SM + 4;
+        // Events from NetworkCallbacks that we process on the main state
         // machine thread on behalf of the UpstreamNetworkMonitor.
-        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MASTER + 5;
+        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MAIN_SM + 5;
         // we treated the error and want now to clear it
-        static final int CMD_CLEAR_ERROR                        = BASE_MASTER + 6;
-        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MASTER + 7;
+        static final int CMD_CLEAR_ERROR                        = BASE_MAIN_SM + 6;
+        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MAIN_SM + 7;
         // Events from EntitlementManager to choose upstream again.
-        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MASTER + 8;
+        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MAIN_SM + 8;
         private final State mInitialState;
         private final State mTetherModeAliveState;
 
@@ -1425,7 +1428,7 @@
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
-        TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
+        TetherMainSM(String name, Looper looper, TetheringDependencies deps) {
             super(name, looper);
 
             mInitialState = new InitialState();
@@ -1479,7 +1482,7 @@
             }
         }
 
-        protected boolean turnOnMasterTetherSettings() {
+        protected boolean turnOnMainTetherSettings() {
             final TetheringConfiguration cfg = mConfig;
             try {
                 mNetd.ipfwdEnableForwarding(TAG);
@@ -1506,11 +1509,11 @@
                     return false;
                 }
             }
-            mLog.log("SET master tether settings: ON");
+            mLog.log("SET main tether settings: ON");
             return true;
         }
 
-        protected boolean turnOffMasterTetherSettings() {
+        protected boolean turnOffMainTetherSettings() {
             try {
                 mNetd.tetherStop();
             } catch (RemoteException | ServiceSpecificException e) {
@@ -1526,7 +1529,7 @@
                 return false;
             }
             transitionTo(mInitialState);
-            mLog.log("SET master tether settings: OFF");
+            mLog.log("SET main tether settings: OFF");
             return true;
         }
 
@@ -1730,7 +1733,7 @@
                     // TODO: Re-evaluate possible upstreams. Currently upstream
                     // reevaluation is triggered via received CONNECTIVITY_ACTION
                     // broadcasts that result in being passed a
-                    // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+                    // TetherMainSM.CMD_UPSTREAM_CHANGED.
                     handleNewUpstreamNetworkState(null);
                     break;
                 default:
@@ -1745,9 +1748,9 @@
 
             @Override
             public void enter() {
-                // If turning on master tether settings fails, we have already
+                // If turning on main tether settings fails, we have already
                 // transitioned to an error state; exit early.
-                if (!turnOnMasterTetherSettings()) {
+                if (!turnOnMainTetherSettings()) {
                     return;
                 }
 
@@ -1819,7 +1822,7 @@
                         if (mNotifyList.isEmpty()) {
                             // This transitions us out of TetherModeAliveState,
                             // either to InitialState or an error state.
-                            turnOffMasterTetherSettings();
+                            turnOffMainTetherSettings();
                             break;
                         }
 
@@ -2329,7 +2332,7 @@
         };
     }
 
-    // TODO: Move into TetherMasterSM.
+    // TODO: Move into TetherMainSM.
     private void notifyInterfaceStateChange(IpServer who, int state, int error) {
         final String iface = who.interfaceName();
         synchronized (mPublicSync) {
@@ -2344,27 +2347,27 @@
 
         mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
 
-        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
-        // Thus we give a chance for TetherMasterSM to recover to InitialState
+        // If TetherMainSM is in ErrorState, TetherMainSM stays there.
+        // Thus we give a chance for TetherMainSM to recover to InitialState
         // by sending CMD_CLEAR_ERROR
         if (error == TETHER_ERROR_INTERNAL_ERROR) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+            mTetherMainSM.sendMessage(TetherMainSM.CMD_CLEAR_ERROR, who);
         }
         int which;
         switch (state) {
             case IpServer.STATE_UNAVAILABLE:
             case IpServer.STATE_AVAILABLE:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
+                which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
             case IpServer.STATE_TETHERED:
             case IpServer.STATE_LOCAL_ONLY:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
+                which = TetherMainSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
                 Log.wtf(TAG, "Unknown interface state: " + state);
                 return;
         }
-        mTetherMasterSM.sendMessage(which, state, 0, who);
+        mTetherMainSM.sendMessage(which, state, 0, who);
         sendTetherStateChangedBroadcast();
     }
 
@@ -2384,8 +2387,8 @@
         mLog.log(String.format(
                 "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
                 iface, IpServer.getStateString(state), newLp));
-        final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
-        mTetherMasterSM.sendMessage(which, state, 0, newLp);
+        final int which = TetherMainSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
+        mTetherMainSM.sendMessage(which, state, 0, newLp);
     }
 
     private void maybeTrackNewInterfaceLocked(final String iface) {
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index e1771a5..5783805 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -84,6 +84,9 @@
     public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
             "tether_enable_legacy_dhcp_server";
 
+    public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
+            "use_legacy_wifi_p2p_dedicated_ip";
+
     /**
      * Default value that used to periodic polls tether offload stats from tethering offload HAL
      * to make the data warnings work.
@@ -113,6 +116,7 @@
     private final int mOffloadPollInterval;
     // TODO: Add to TetheringConfigurationParcel if required.
     private final boolean mEnableBpfOffload;
+    private final boolean mEnableWifiP2pDedicatedIp;
 
     public TetheringConfiguration(Context ctx, SharedLog log, int id) {
         final SharedLog configLog = log.forSubComponent("config");
@@ -156,6 +160,10 @@
                 R.integer.config_tether_offload_poll_interval,
                 DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
 
+        mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
+                R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
+                false /* defaultValue */);
+
         configLog.log(toString());
     }
 
@@ -199,6 +207,11 @@
         return !TextUtils.isEmpty(provisioningAppNoUi);
     }
 
+    /** Check whether dedicated wifi p2p address is enabled. */
+    public boolean shouldEnableWifiP2pDedicatedIp() {
+        return mEnableWifiP2pDedicatedIp;
+    }
+
     /** Does the dumping.*/
     public void dump(PrintWriter pw) {
         pw.print("activeDataSubId: ");
@@ -233,6 +246,9 @@
 
         pw.print("enableLegacyDhcpServer: ");
         pw.println(enableLegacyDhcpServer);
+
+        pw.print("enableWifiP2pDedicatedIp: ");
+        pw.println(mEnableWifiP2pDedicatedIp);
     }
 
     /** Returns the string representation of this object.*/
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 320427c..b17065c 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -63,7 +63,7 @@
  * Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
  *
  * The methods and data members of this class are only to be accessed and
- * modified from the tethering master state machine thread. Any other
+ * modified from the tethering main state machine thread. Any other
  * access semantics would necessitate the addition of locking.
  *
  * TODO: Move upstream selection logic here.
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 05cf58a..3b72b5b 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -36,7 +36,8 @@
 import static android.net.netlink.StructNdMsg.NUD_FAILED;
 import static android.net.netlink.StructNdMsg.NUD_REACHABLE;
 import static android.net.netlink.StructNdMsg.NUD_STALE;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+
+import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -49,6 +50,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
@@ -72,6 +74,7 @@
 import android.net.RouteInfo;
 import android.net.TetherOffloadRuleParcel;
 import android.net.TetherStatsParcel;
+import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpEventCallbacks;
 import android.net.dhcp.IDhcpServer;
@@ -162,17 +165,6 @@
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
             boolean usingBpfOffload) throws Exception {
-        doAnswer(inv -> {
-            final IDhcpServerCallbacks cb = inv.getArgument(2);
-            new Thread(() -> {
-                try {
-                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
-                } catch (RemoteException e) {
-                    fail(e.getMessage());
-                }
-            }).run();
-            return null;
-        }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
         when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
         when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
@@ -224,6 +216,20 @@
         when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
     }
 
+    private void setUpDhcpServer() throws Exception {
+        doAnswer(inv -> {
+            final IDhcpServerCallbacks cb = inv.getArgument(2);
+            new Thread(() -> {
+                try {
+                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+                } catch (RemoteException e) {
+                    fail(e.getMessage());
+                }
+            }).run();
+            return null;
+        }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
+    }
+
     @Before public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
@@ -257,6 +263,8 @@
                         return mTetherConfig;
                     }
                 }));
+
+        setUpDhcpServer();
     }
 
     @Test
@@ -964,6 +972,31 @@
         reset(mRaDaemon);
     }
 
+    @Test
+    public void testStopObsoleteDhcpServer() throws Exception {
+        final ArgumentCaptor<DhcpServerCallbacks> cbCaptor =
+                ArgumentCaptor.forClass(DhcpServerCallbacks.class);
+        doNothing().when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(),
+                cbCaptor.capture());
+        initStateMachine(TETHERING_WIFI);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        verify(mDhcpServer, never()).startWithCallbacks(any(), any());
+
+        // No stop dhcp server because dhcp server is not created yet.
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        verify(mDhcpServer, never()).stop(any());
+
+        // Stop obsolete dhcp server.
+        try {
+            final DhcpServerCallbacks cb = cbCaptor.getValue();
+            cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+            mLooper.dispatchAll();
+        } catch (RemoteException e) {
+            fail(e.getMessage());
+        }
+        verify(mDhcpServer).stop(any());
+    }
+
     private void assertDhcpServingParams(final DhcpServingParamsParcel params,
             final IpPrefix prefix) {
         // Last address byte is random
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 2c0df6f..8e93c2e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,11 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.Mockito.never;
@@ -54,22 +59,34 @@
     @Mock private IpServer mHotspotIpServer;
     @Mock private IpServer mUsbIpServer;
     @Mock private IpServer mEthernetIpServer;
+    @Mock private IpServer mWifiP2pIpServer;
     @Mock private Context mContext;
     @Mock private ConnectivityManager mConnectivityMgr;
+    @Mock private TetheringConfiguration mConfig;
 
     private PrivateAddressCoordinator mPrivateAddressCoordinator;
     private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+    private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
     private final Network mWifiNetwork = new Network(1);
     private final Network mMobileNetwork = new Network(2);
     private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
 
+    private void setUpIpServers() throws Exception {
+        when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
+        when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
+        when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+        when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
         when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
-        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext));
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+        setUpIpServers();
+        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
     }
 
     @Test
@@ -256,4 +273,38 @@
         final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
         assertEquals(predefinedPrefix, ethPrefix);
     }
+
+    private int getSubAddress(final byte... ipv4Address) {
+        assertEquals(4, ipv4Address.length);
+
+        int subnet = Byte.toUnsignedInt(ipv4Address[2]);
+        return (subnet << 8) + ipv4Address[3];
+    }
+
+    private void assertReseveredWifiP2pPrefix() throws Exception {
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mHotspotIpServer);
+        final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
+        final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+        assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
+        mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+    }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+                getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+        // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
+        // is resevered.
+        assertReseveredWifiP2pPrefix();
+
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(true);
+        assertReseveredWifiP2pPrefix();
+
+        // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mWifiP2pIpServer);
+        assertEquals(mLegacyWifiP2pAddress, address);
+        mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index a9ac4e2..dc0940c 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -128,6 +128,8 @@
                 .thenReturn(new String[0]);
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(false);
         initializeBpfOffloadConfiguration(true, null /* unset */);
 
         mHasTelephonyManager = true;
@@ -413,4 +415,17 @@
                 R.string.config_mobile_hotspot_provision_response)).thenReturn(
                 PROVISIONING_APP_RESPONSE);
     }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        final TetheringConfiguration defaultCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp());
+
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(true);
+        final TetheringConfiguration testCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp());
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index d37aad2..fb3940b 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -40,7 +40,6 @@
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -49,6 +48,7 @@
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
 import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
 import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES;
 
@@ -337,11 +337,11 @@
     }
 
     public class MockTetheringDependencies extends TetheringDependencies {
-        StateMachine mUpstreamNetworkMonitorMasterSM;
+        StateMachine mUpstreamNetworkMonitorSM;
         ArrayList<IpServer> mIpv6CoordinatorNotifyList;
 
         public void reset() {
-            mUpstreamNetworkMonitorMasterSM = null;
+            mUpstreamNetworkMonitorSM = null;
             mIpv6CoordinatorNotifyList = null;
         }
 
@@ -368,7 +368,7 @@
         @Override
         public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
                 StateMachine target, SharedLog log, int what) {
-            mUpstreamNetworkMonitorMasterSM = target;
+            mUpstreamNetworkMonitorSM = target;
             return mUpstreamNetworkMonitor;
         }
 
@@ -911,8 +911,8 @@
         initTetheringUpstream(upstreamState);
 
         // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamState);
@@ -1126,7 +1126,7 @@
         verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
         // This never gets called because of the exception thrown above.
         verify(mNetd, times(0)).tetherStartWithConfiguration(any());
-        // When the master state machine transitions to an error state it tells
+        // When the main state machine transitions to an error state it tells
         // downstream interfaces, which causes us to tell Wi-Fi about the error
         // so it can take down AP mode.
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
@@ -1753,8 +1753,8 @@
 
     @Test
     public void testUpstreamNetworkChanged() {
-        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
-                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+        final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+                mTetheringDependencies.mUpstreamNetworkMonitorSM;
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
         stateMachine.chooseUpstreamType(true);
@@ -1765,8 +1765,8 @@
 
     @Test
     public void testUpstreamCapabilitiesChanged() {
-        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
-                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+        final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+                mTetheringDependencies.mUpstreamNetworkMonitorSM;
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
         stateMachine.chooseUpstreamType(true);
@@ -1891,8 +1891,8 @@
                 any(), any());
         reset(mNetd, mUsbManager);
         upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork);
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamNetwork);
@@ -1929,8 +1929,8 @@
 
         final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState(
                 upstreamAddress, 16, wifiNetwork);
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamNetwork);