Merge "updateSupportedDownstreams when tethering allowed is changed"
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index ac0bbd4..05a2884 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -64,7 +64,7 @@
 import com.android.net.module.util.NetworkStackConstants;
 import com.android.net.module.util.SharedLog;
 import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.S32;
 import com.android.net.module.util.bpf.Tether4Key;
 import com.android.net.module.util.bpf.Tether4Value;
 import com.android.net.module.util.bpf.TetherStatsKey;
@@ -575,7 +575,7 @@
             if (!mBpfCoordinatorShim.startUpstreamIpv6Forwarding(downstream, upstream, rule.srcMac,
                     NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, NetworkStackConstants.ETHER_MTU)) {
                 mLog.e("Failed to enable upstream IPv6 forwarding from "
-                        + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
+                        + getIfName(downstream) + " to " + getIfName(upstream));
             }
         }
 
@@ -616,7 +616,7 @@
             if (!mBpfCoordinatorShim.stopUpstreamIpv6Forwarding(downstream, upstream,
                     rule.srcMac)) {
                 mLog.e("Failed to disable upstream IPv6 forwarding from "
-                        + mInterfaceNames.get(downstream) + " to " + mInterfaceNames.get(upstream));
+                        + getIfName(downstream) + " to " + getIfName(upstream));
             }
         }
 
@@ -960,8 +960,12 @@
     }
 
     // TODO: make mInterfaceNames accessible to the shim and move this code to there.
-    private String getIfName(long ifindex) {
-        return mInterfaceNames.get((int) ifindex, Long.toString(ifindex));
+    // This function should only be used for logging/dump purposes.
+    private String getIfName(int ifindex) {
+        // TODO: return something more useful on lookup failure
+        // likely use the 'iface_index_name_map' bpf map and/or if_nametoindex
+        // perhaps should even check that all 3 match if available.
+        return mInterfaceNames.get(ifindex, Integer.toString(ifindex));
     }
 
     /**
@@ -1038,8 +1042,8 @@
         for (int i = 0; i < mStats.size(); i++) {
             final int upstreamIfindex = mStats.keyAt(i);
             final ForwardedStats stats = mStats.get(upstreamIfindex);
-            pw.println(String.format("%d(%s) - %s", upstreamIfindex, mInterfaceNames.get(
-                    upstreamIfindex), stats.toString()));
+            pw.println(String.format("%d(%s) - %s", upstreamIfindex, getIfName(upstreamIfindex),
+                    stats.toString()));
         }
     }
     private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
@@ -1082,8 +1086,9 @@
             for (Ipv6ForwardingRule rule : rules.values()) {
                 final int upstreamIfindex = rule.upstreamIfindex;
                 pw.println(String.format("%d(%s) %d(%s) %s [%s] [%s]", upstreamIfindex,
-                        mInterfaceNames.get(upstreamIfindex), rule.downstreamIfindex,
-                        downstreamIface, rule.address.getHostAddress(), rule.srcMac, rule.dstMac));
+                        getIfName(upstreamIfindex), rule.downstreamIfindex,
+                        getIfName(rule.downstreamIfindex), rule.address.getHostAddress(),
+                        rule.srcMac, rule.dstMac));
             }
             pw.decreaseIndent();
         }
@@ -1278,18 +1283,18 @@
             pw.println("No counter support");
             return;
         }
-        try (BpfMap<U32, U32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
-                U32.class, U32.class)) {
+        try (BpfMap<S32, S32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
+                S32.class, S32.class)) {
 
             map.forEach((k, v) -> {
                 String counterName;
                 try {
-                    counterName = sBpfCounterNames[(int) k.val];
+                    counterName = sBpfCounterNames[k.val];
                 } catch (IndexOutOfBoundsException e) {
                     // Should never happen because this code gets the counter name from the same
                     // include file as the BPF program that increments the counter.
                     Log.wtf(TAG, "Unknown tethering counter type " + k.val);
-                    counterName = Long.toString(k.val);
+                    counterName = Integer.toString(k.val);
                 }
                 if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
             });
@@ -1817,8 +1822,7 @@
         // TODO: Perhaps stop the coordinator.
         boolean success = updateDataLimit(upstreamIfindex);
         if (!success) {
-            final String iface = mInterfaceNames.get(upstreamIfindex);
-            mLog.e("Setting data limit for " + iface + " failed.");
+            mLog.e("Setting data limit for " + getIfName(upstreamIfindex) + " failed.");
         }
     }
 
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java b/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
index 4283c1b..997080c 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDevKey.java
@@ -22,10 +22,10 @@
 
 /** The key of BpfMap which is used for mapping interface index. */
 public class TetherDevKey extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long ifIndex;  // interface index
+    @Field(order = 0, type = Type.S32)
+    public final int ifIndex;  // interface index
 
-    public TetherDevKey(final long ifIndex) {
+    public TetherDevKey(final int ifIndex) {
         this.ifIndex = ifIndex;
     }
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java b/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
index 1cd99b5..b6e0c73 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDevValue.java
@@ -22,10 +22,10 @@
 
 /** The key of BpfMap which is used for mapping interface index. */
 public class TetherDevValue extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long ifIndex;  // interface index
+    @Field(order = 0, type = Type.S32)
+    public final int ifIndex;  // interface index
 
-    public TetherDevValue(final long ifIndex) {
+    public TetherDevValue(final int ifIndex) {
         this.ifIndex = ifIndex;
     }
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
index a08ad4a..e34b3f1 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherDownstream6Key.java
@@ -32,8 +32,8 @@
 
 /** The key of BpfMap which is used for bpf offload. */
 public class TetherDownstream6Key extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long iif; // The input interface index.
+    @Field(order = 0, type = Type.S32)
+    public final int iif; // The input interface index.
 
     @Field(order = 1, type = Type.EUI48, padding = 2)
     public final MacAddress dstMac; // Destination ethernet mac address (zeroed iff rawip ingress).
@@ -41,7 +41,7 @@
     @Field(order = 2, type = Type.ByteArray, arraysize = 16)
     public final byte[] neigh6; // The destination IPv6 address.
 
-    public TetherDownstream6Key(final long iif, @NonNull final MacAddress dstMac,
+    public TetherDownstream6Key(final int iif, @NonNull final MacAddress dstMac,
             final byte[] neigh6) {
         Objects.requireNonNull(dstMac);
 
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java b/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
index bc9bb47..a7e8ccf 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetherLimitKey.java
@@ -22,10 +22,10 @@
 
 /** The key of BpfMap which is used for tethering per-interface limit. */
 public class TetherLimitKey extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long ifindex;  // upstream interface index
+    @Field(order = 0, type = Type.S32)
+    public final int ifindex;  // upstream interface index
 
-    public TetherLimitKey(final long ifindex) {
+    public TetherLimitKey(final int ifindex) {
         this.ifindex = ifindex;
     }
 
@@ -43,7 +43,7 @@
 
     @Override
     public int hashCode() {
-        return Long.hashCode(ifindex);
+        return Integer.hashCode(ifindex);
     }
 
     @Override
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 536ab2d..0e8b044 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -98,7 +98,7 @@
         assertTrue(mTestMap.isEmpty());
     }
 
-    private TetherDownstream6Key createTetherDownstream6Key(long iif, String mac,
+    private TetherDownstream6Key createTetherDownstream6Key(int iif, String mac,
             String address) throws Exception {
         final MacAddress dstMac = MacAddress.fromString(mac);
         final InetAddress ipv6Address = InetAddress.getByName(address);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 63bb731..b100f58 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -222,7 +222,7 @@
 
     private static class TestUpstream4Key {
         public static class Builder {
-            private long mIif = DOWNSTREAM_IFINDEX;
+            private int mIif = DOWNSTREAM_IFINDEX;
             private MacAddress mDstMac = DOWNSTREAM_MAC;
             private short mL4proto = (short) IPPROTO_TCP;
             private byte[] mSrc4 = PRIVATE_ADDR.getAddress();
@@ -246,7 +246,7 @@
 
     private static class TestDownstream4Key {
         public static class Builder {
-            private long mIif = UPSTREAM_IFINDEX;
+            private int mIif = UPSTREAM_IFINDEX;
             private MacAddress mDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
             private short mL4proto = (short) IPPROTO_TCP;
             private byte[] mSrc4 = REMOTE_ADDR.getAddress();
@@ -270,7 +270,7 @@
 
     private static class TestUpstream4Value {
         public static class Builder {
-            private long mOif = UPSTREAM_IFINDEX;
+            private int mOif = UPSTREAM_IFINDEX;
             private MacAddress mEthDstMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
             private MacAddress mEthSrcMac = MacAddress.ALL_ZEROS_ADDRESS /* dstMac (rawip) */;
             private int mEthProto = ETH_P_IP;
@@ -290,7 +290,7 @@
 
     private static class TestDownstream4Value {
         public static class Builder {
-            private long mOif = DOWNSTREAM_IFINDEX;
+            private int mOif = DOWNSTREAM_IFINDEX;
             private MacAddress mEthDstMac = MAC_A /* client mac */;
             private MacAddress mEthSrcMac = DOWNSTREAM_MAC;
             private int mEthProto = ETH_P_IP;
@@ -941,11 +941,11 @@
 
     @Test
     public void testRuleMakeTetherDownstream6Key() throws Exception {
-        final Integer mobileIfIndex = 100;
+        final int mobileIfIndex = 100;
         final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
 
         final TetherDownstream6Key key = rule.makeTetherDownstream6Key();
-        assertEquals(key.iif, (long) mobileIfIndex);
+        assertEquals(key.iif, mobileIfIndex);
         assertEquals(key.dstMac, MacAddress.ALL_ZEROS_ADDRESS);  // rawip upstream
         assertTrue(Arrays.equals(key.neigh6, NEIGH_A.getAddress()));
         // iif (4) + dstMac(6) + padding(2) + neigh6 (16) = 28.
@@ -954,7 +954,7 @@
 
     @Test
     public void testRuleMakeTether6Value() throws Exception {
-        final Integer mobileIfIndex = 100;
+        final int mobileIfIndex = 100;
         final Ipv6ForwardingRule rule = buildTestForwardingRule(mobileIfIndex, NEIGH_A, MAC_A);
 
         final Tether6Value value = rule.makeTether6Value();
@@ -974,7 +974,7 @@
         final BpfCoordinator coordinator = makeBpfCoordinator();
 
         final String mobileIface = "rmnet_data0";
-        final Integer mobileIfIndex = 100;
+        final int mobileIfIndex = 100;
         coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
 
         // [1] Default limit.
@@ -1018,7 +1018,7 @@
         final BpfCoordinator coordinator = makeBpfCoordinator();
 
         final String mobileIface = "rmnet_data0";
-        final Integer mobileIfIndex = 100;
+        final int mobileIfIndex = 100;
         coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
 
         // Applying a data limit to the current upstream does not take any immediate action.
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Key.java b/common/src/com/android/net/module/util/bpf/Tether4Key.java
index 638576f..8273e6a 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Key.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Key.java
@@ -30,8 +30,8 @@
 
 /** Key type for downstream & upstream IPv4 forwarding maps. */
 public class Tether4Key extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long iif;
+    @Field(order = 0, type = Type.S32)
+    public final int iif;
 
     @Field(order = 1, type = Type.EUI48)
     public final MacAddress dstMac;
@@ -51,7 +51,7 @@
     @Field(order = 6, type = Type.UBE16)
     public final int dstPort;
 
-    public Tether4Key(final long iif, @NonNull final MacAddress dstMac, final short l4proto,
+    public Tether4Key(final int iif, @NonNull final MacAddress dstMac, final short l4proto,
             final byte[] src4, final byte[] dst4, final int srcPort,
             final int dstPort) {
         Objects.requireNonNull(dstMac);
diff --git a/common/src/com/android/net/module/util/bpf/Tether4Value.java b/common/src/com/android/net/module/util/bpf/Tether4Value.java
index de98766..74fdda2 100644
--- a/common/src/com/android/net/module/util/bpf/Tether4Value.java
+++ b/common/src/com/android/net/module/util/bpf/Tether4Value.java
@@ -30,8 +30,8 @@
 
 /** Value type for downstream & upstream IPv4 forwarding maps. */
 public class Tether4Value extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long oif;
+    @Field(order = 0, type = Type.S32)
+    public final int oif;
 
     // The ethhdr struct which is defined in uapi/linux/if_ether.h
     @Field(order = 1, type = Type.EUI48)
@@ -60,7 +60,7 @@
     @Field(order = 9, type = Type.U63)
     public final long lastUsed;
 
-    public Tether4Value(final long oif, @NonNull final MacAddress ethDstMac,
+    public Tether4Value(final int oif, @NonNull final MacAddress ethDstMac,
             @NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu,
             final byte[] src46, final byte[] dst46, final int srcPort,
             final int dstPort, final long lastUsed) {
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index a1d0310..bd74d54 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -59,7 +59,8 @@
     }
 }
 
-static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, const char* iface) {
+static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, bool setIffMulticast,
+                            const char* iface) {
     base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
     ifreq ifr{};
 
@@ -76,8 +77,8 @@
         setTunTapCarrierEnabledImpl(env, iface, tun.get(), hasCarrier);
     }
 
-    // Mark TAP interfaces as supporting multicast
-    if (!isTun) {
+    // Mark some TAP interfaces as supporting multicast
+    if (setIffMulticast && !isTun) {
         base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
         ifr.ifr_flags = IFF_MULTICAST;
 
@@ -122,14 +123,14 @@
 }
 
 static jint createTunTap(JNIEnv* env, jclass /* clazz */, jboolean isTun,
-                             jboolean hasCarrier, jstring jIface) {
+                             jboolean hasCarrier, jboolean setIffMulticast, jstring jIface) {
     ScopedUtfChars iface(env, jIface);
     if (!iface.c_str()) {
         jniThrowNullPointerException(env, "iface");
         return -1;
     }
 
-    return createTunTapImpl(env, isTun, hasCarrier, iface.c_str());
+    return createTunTapImpl(env, isTun, hasCarrier, setIffMulticast, iface.c_str());
 }
 
 static void bringUpInterface(JNIEnv* env, jclass /* clazz */, jstring jIface) {
@@ -145,7 +146,7 @@
 
 static const JNINativeMethod gMethods[] = {
     {"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
-    {"nativeCreateTunTap", "(ZZLjava/lang/String;)I", (void*)createTunTap},
+    {"nativeCreateTunTap", "(ZZZLjava/lang/String;)I", (void*)createTunTap},
     {"nativeBringUpInterface", "(Ljava/lang/String;)V", (void*)bringUpInterface},
 };
 
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 594223c..231a47f 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -26,6 +26,8 @@
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
+import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
 import static android.system.OsConstants.EINVAL;
 import static android.system.OsConstants.ENODEV;
 import static android.system.OsConstants.ENOENT;
@@ -45,6 +47,7 @@
 import com.android.net.module.util.BpfMap;
 import com.android.net.module.util.DeviceConfigUtils;
 import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.U8;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -85,6 +88,8 @@
             "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
     private static final String UID_OWNER_MAP_PATH =
             "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
+    private static final String UID_PERMISSION_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
     private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
     private static final U32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new U32(1);
     private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
@@ -94,6 +99,7 @@
     private static BpfMap<U32, U32> sConfigurationMap = null;
     // BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
     private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
+    private static BpfMap<U32, U8> sUidPermissionMap = null;
 
     // LINT.IfChange(match_type)
     @VisibleForTesting public static final long NO_MATCH = 0;
@@ -135,6 +141,14 @@
         sUidOwnerMap = uidOwnerMap;
     }
 
+    /**
+     * Set uidPermissionMap for test.
+     */
+    @VisibleForTesting
+    public static void setUidPermissionMapForTest(BpfMap<U32, U8> uidPermissionMap) {
+        sUidPermissionMap = uidPermissionMap;
+    }
+
     private static BpfMap<U32, U32> getConfigurationMap() {
         try {
             return new BpfMap<>(
@@ -153,6 +167,15 @@
         }
     }
 
+    private static BpfMap<U32, U8> getUidPermissionMap() {
+        try {
+            return new BpfMap<>(
+                    UID_PERMISSION_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U8.class);
+        } catch (ErrnoException e) {
+            throw new IllegalStateException("Cannot open uid permission map", e);
+        }
+    }
+
     private static void initBpfMaps() {
         if (sConfigurationMap == null) {
             sConfigurationMap = getConfigurationMap();
@@ -178,6 +201,10 @@
         } catch (ErrnoException e) {
             throw new IllegalStateException("Failed to initialize uid owner map", e);
         }
+
+        if (sUidPermissionMap == null) {
+            sUidPermissionMap = getUidPermissionMap();
+        }
     }
 
     /**
@@ -719,7 +746,31 @@
             mNetd.trafficSetNetPermForUids(permissions, uids);
             return;
         }
-        native_setPermissionForUids(permissions, uids);
+
+        if (sEnableJavaBpfMap) {
+            // Remove the entry if package is uninstalled or uid has only INTERNET permission.
+            if (permissions == PERMISSION_UNINSTALLED || permissions == PERMISSION_INTERNET) {
+                for (final int uid : uids) {
+                    try {
+                        sUidPermissionMap.deleteEntry(new U32(uid));
+                    } catch (ErrnoException e) {
+                        Log.e(TAG, "Failed to remove uid " + uid + " from permission map: " + e);
+                    }
+                }
+                return;
+            }
+
+            for (final int uid : uids) {
+                try {
+                    sUidPermissionMap.updateEntry(new U32(uid), new U8((short) permissions));
+                } catch (ErrnoException e) {
+                    Log.e(TAG, "Failed to set permission "
+                            + permissions + " to uid " + uid + ": " + e);
+                }
+            }
+        } else {
+            native_setPermissionForUids(permissions, uids);
+        }
     }
 
     /**
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index 15d9f13..5549fbe 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -77,7 +77,7 @@
 
     // Native method stubs
     private static native int nativeCreateTunTap(boolean isTun, boolean hasCarrier,
-            @NonNull String iface);
+            boolean setIffMulticast, @NonNull String iface);
 
     private static native void nativeSetTunTapCarrierEnabled(@NonNull String iface, int tunFd,
             boolean enabled);
@@ -136,8 +136,14 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
+            // Note: if the interface is brought up by ethernet, setting IFF_MULTICAST
+            // races NetUtils#setInterfaceUp(). This flag is not necessary for ethernet
+            // tests, so let's not set it when bringUp is false. See also b/242343156.
+            // In the future, we could use RTM_SETLINK with ifi_change set to set the
+            // flags atomically.
+            final boolean setIffMulticast = bringUp;
             ParcelFileDescriptor tunIntf = ParcelFileDescriptor.adoptFd(
-                    nativeCreateTunTap(isTun, hasCarrier, interfaceName));
+                    nativeCreateTunTap(isTun, hasCarrier, setIffMulticast, interfaceName));
 
             // Disable DAD and remove router_solicitation_delay before assigning link addresses.
             if (disableIpv6ProvisioningDelay) {
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 1f76773..043a0ad 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -163,8 +163,7 @@
 
             // Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
             // address.
-            iface = tnm.createTapInterface(true /* disableIpv6ProvisioningDelay */,
-                    arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
+            iface = tnm.createTapInterface(arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
             assertNotNull(iface)
         }
 
@@ -224,7 +223,7 @@
         val onLinkPrefix = raResponder.prefix
         val startTime = SystemClock.elapsedRealtime()
         while (SystemClock.elapsedRealtime() - startTime < PACKET_TIMEOUT_MS) {
-            SystemClock.sleep(1 /* ms */)
+            SystemClock.sleep(50 /* ms */)
             val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
             try {
                 network.bindSocket(sock)
@@ -273,7 +272,6 @@
         val lp = LinkProperties().apply {
             addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
             addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
-            addRoute(RouteInfo(IpPrefix("::/0"), TEST_ROUTER_IPV6_ADDR))
             setInterfaceName(specifier)
         }
         val config = NetworkAgentConfig.Builder().build()
diff --git a/tests/integration/AndroidManifest.xml b/tests/integration/AndroidManifest.xml
index 2e13689..50f02d3 100644
--- a/tests/integration/AndroidManifest.xml
+++ b/tests/integration/AndroidManifest.xml
@@ -60,7 +60,7 @@
                 <action android:name=".INetworkStackInstrumentation"/>
             </intent-filter>
         </service>
-        <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+        <service android:name="com.android.networkstack.ipmemorystore.RegularMaintenanceJobService"
              android:process="com.android.server.net.integrationtests.testnetworkstack"
              android:permission="android.permission.BIND_JOB_SERVICE"/>
 
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 2d09bf2..7696c40 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -27,6 +27,9 @@
 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
 import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NONE;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
 
 import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
 import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH;
@@ -56,6 +59,7 @@
 import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.BpfMap;
 import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.U8;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -107,6 +111,7 @@
     private final BpfMap<U32, U32> mConfigurationMap = new TestBpfMap<>(U32.class, U32.class);
     private final BpfMap<U32, UidOwnerValue> mUidOwnerMap =
             new TestBpfMap<>(U32.class, UidOwnerValue.class);
+    private final BpfMap<U32, U8> mUidPermissionMap = new TestBpfMap<>(U32.class, U8.class);
 
     @Before
     public void setUp() throws Exception {
@@ -115,6 +120,7 @@
         BpfNetMaps.setEnableJavaBpfMapForTest(true /* enable */);
         BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
         BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap);
+        BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap);
         mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
     }
 
@@ -728,4 +734,116 @@
                 () -> mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS));
     }
 
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsGrantInternetPermission() throws Exception {
+        mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
+
+        assertTrue(mUidPermissionMap.isEmpty());
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsGrantUpdateStatsPermission() throws Exception {
+        mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
+
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid1)).val);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsGrantMultiplePermissions() throws Exception {
+        final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+        mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsRevokeInternetPermission() throws Exception {
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
+        mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsRevokeUpdateDeviceStatsPermission() throws Exception {
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS);
+        mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new U32(uid1)).val);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsRevokeMultiplePermissions() throws Exception {
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+        mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+        mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0});
+
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsPermissionUninstalled() throws Exception {
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+        mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+        mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, new int[]{uid0});
+
+        assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testSetNetPermForUidsDuplicatedRequestSilentlyIgnored() throws Exception {
+        final int uid0 = TEST_UIDS[0];
+        final int uid1 = TEST_UIDS[1];
+        final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
+
+        mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+        mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(permission, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+        mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+        mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS);
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid0)).val);
+        assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new U32(uid1)).val);
+
+        mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
+        assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+        assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+
+        mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS);
+        assertNull(mUidPermissionMap.getValue(new U32(uid0)));
+        assertNull(mUidPermissionMap.getValue(new U32(uid1)));
+    }
 }
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 041e4ea..f159859 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -92,6 +92,7 @@
 import android.net.LinkProperties;
 import android.net.LocalSocket;
 import android.net.Network;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo.DetailedState;
 import android.net.RouteInfo;
@@ -264,6 +265,7 @@
         final Ikev2VpnProfile.Builder builder =
                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
         builder.setAuthPsk(TEST_VPN_PSK);
+        builder.setBypassable(true /* isBypassable */);
         mVpnProfile = builder.build().toVpnProfile();
     }
 
@@ -1787,9 +1789,11 @@
         ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
         ArgumentCaptor<NetworkCapabilities> ncCaptor =
                 ArgumentCaptor.forClass(NetworkCapabilities.class);
+        ArgumentCaptor<NetworkAgentConfig> nacCaptor =
+                ArgumentCaptor.forClass(NetworkAgentConfig.class);
         verify(mTestDeps).newNetworkAgent(
                 any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
-                any(), any(), any());
+                any(), nacCaptor.capture(), any());
 
         // Check LinkProperties
         final LinkProperties lp = lpCaptor.getValue();
@@ -1811,6 +1815,9 @@
         // Check NetworkCapabilities
         assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
 
+        // Check if allowBypass is set or not.
+        assertTrue(nacCaptor.getValue().isBypassableVpn());
+
         return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
     }
 
diff --git a/tools/gen_jarjar.py b/tools/gen_jarjar.py
index 4c2cf54..2ff53fa 100755
--- a/tools/gen_jarjar.py
+++ b/tools/gen_jarjar.py
@@ -115,7 +115,8 @@
             jar_classes = _list_jar_classes(jar)
             jar_classes.sort()
             for clazz in jar_classes:
-                if (_get_toplevel_class(clazz) not in excluded_classes and
+                if (not clazz.startswith(args.prefix + '.') and
+                        _get_toplevel_class(clazz) not in excluded_classes and
                         not any(r.fullmatch(clazz) for r in exclude_regexes)):
                     outfile.write(f'rule {clazz} {args.prefix}.@0\n')
                     # Also include jarjar rules for unit tests of the class, so the package matches
diff --git a/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java b/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java
new file mode 100644
index 0000000..6859020
--- /dev/null
+++ b/tools/testdata/java/jarjar/prefix/AlreadyInTargetPackageClass.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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 jarjar.prefix;
+
+/**
+ * Sample class to test jarjar rules, already in the "jarjar.prefix" package.
+ */
+public class AlreadyInTargetPackageClass {
+    /** Test inner class that should not be jarjared either */
+    public static class TestInnerClass {}
+}