Merge changes from topics "vpnmove-getconnectionowneruid", "vpnmove-systemdefaultcallback", "vpnmove-vpntransportinfo"

* changes:
  Accept both pre-S and post-S errors in getConnectionOwnerUid.
  Add CTS coverage for VpnTransportInfo.
  Add test coverage for registerSystemDefaultNetworkCallback.
diff --git a/Tethering/bpf_progs/bpf_tethering.h b/Tethering/bpf_progs/bpf_tethering.h
index d83ae34..c8ada88 100644
--- a/Tethering/bpf_progs/bpf_tethering.h
+++ b/Tethering/bpf_progs/bpf_tethering.h
@@ -31,10 +31,18 @@
     ERR(LOCAL_SRC_DST)       \
     ERR(NO_STATS_ENTRY)      \
     ERR(NO_LIMIT_ENTRY)      \
+    ERR(BELOW_IPV4_MTU)      \
     ERR(BELOW_IPV6_MTU)      \
     ERR(LIMIT_REACHED)       \
     ERR(CHANGE_HEAD_FAILED)  \
     ERR(TOO_SHORT)           \
+    ERR(HAS_IP_OPTIONS)      \
+    ERR(IS_IP_FRAG)          \
+    ERR(CHECKSUM)            \
+    ERR(NON_TCP_UDP)         \
+    ERR(SHORT_TCP_HEADER)    \
+    ERR(SHORT_UDP_HEADER)    \
+    ERR(TRUNCATED_IPV4)      \
     ERR(_MAX)
 
 #define ERR(x) BPF_TETHER_ERR_ ##x,
diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c
index 0b2c08d..bf60e67 100644
--- a/Tethering/bpf_progs/offload.c
+++ b/Tethering/bpf_progs/offload.c
@@ -361,10 +361,10 @@
     if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_OK;
 
     // IP version must be 4
-    if (ip->version != 4) return TC_ACT_OK;
+    if (ip->version != 4) PUNT(INVALID_IP_VERSION);
 
     // We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
-    if (ip->ihl != 5) return TC_ACT_OK;
+    if (ip->ihl != 5) PUNT(HAS_IP_OPTIONS);
 
     // Calculate the IPv4 one's complement checksum of the IPv4 header.
     __wsum sum4 = 0;
@@ -375,36 +375,36 @@
     sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse u32 into range 1 .. 0x1FFFE
     sum4 = (sum4 & 0xFFFF) + (sum4 >> 16);  // collapse any potential carry into u16
     // for a correct checksum we should get *a* zero, but sum4 must be positive, ie 0xFFFF
-    if (sum4 != 0xFFFF) return TC_ACT_OK;
+    if (sum4 != 0xFFFF) PUNT(CHECKSUM);
 
     // Minimum IPv4 total length is the size of the header
-    if (ntohs(ip->tot_len) < sizeof(*ip)) return TC_ACT_OK;
+    if (ntohs(ip->tot_len) < sizeof(*ip)) PUNT(TRUNCATED_IPV4);
 
     // We are incapable of dealing with IPv4 fragments
-    if (ip->frag_off & ~htons(IP_DF)) return TC_ACT_OK;
+    if (ip->frag_off & ~htons(IP_DF)) PUNT(IS_IP_FRAG);
 
     // Cannot decrement during forward if already zero or would be zero,
     // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
-    if (ip->ttl <= 1) return TC_ACT_OK;
+    if (ip->ttl <= 1) PUNT(LOW_TTL);
 
     const bool is_tcp = (ip->protocol == IPPROTO_TCP);
 
     // We do not support anything besides TCP and UDP
-    if (!is_tcp && (ip->protocol != IPPROTO_UDP)) return TC_ACT_OK;
+    if (!is_tcp && (ip->protocol != IPPROTO_UDP)) PUNT(NON_TCP_UDP);
 
     struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL;
     struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1);
 
     if (is_tcp) {
         // Make sure we can get at the tcp header
-        if (data + l2_header_size + sizeof(*ip) + sizeof(*tcph) > data_end) return TC_ACT_OK;
+        if (data + l2_header_size + sizeof(*ip) + sizeof(*tcph) > data_end) PUNT(SHORT_TCP_HEADER);
 
         // If hardware offload is running and programming flows based on conntrack entries, try not
         // to interfere with it, so do not offload TCP packets with any one of the SYN/FIN/RST flags
-        if (tcph->syn || tcph->fin || tcph->rst) return TC_ACT_OK;
+        if (tcph->syn || tcph->fin || tcph->rst) PUNT(TCP_CONTROL_PACKET);
     } else { // UDP
         // Make sure we can get at the udp header
-        if (data + l2_header_size + sizeof(*ip) + sizeof(*udph) > data_end) return TC_ACT_OK;
+        if (data + l2_header_size + sizeof(*ip) + sizeof(*udph) > data_end) PUNT(SHORT_UDP_HEADER);
     }
 
     Tether4Key k = {
@@ -428,15 +428,15 @@
     TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
 
     // If we don't have anywhere to put stats, then abort...
-    if (!stat_v) return TC_ACT_OK;
+    if (!stat_v) PUNT(NO_STATS_ENTRY);
 
     uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
 
     // If we don't have a limit, then abort...
-    if (!limit_v) return TC_ACT_OK;
+    if (!limit_v) PUNT(NO_LIMIT_ENTRY);
 
     // Required IPv4 minimum mtu is 68, below that not clear what we should do, abort...
-    if (v->pmtu < 68) return TC_ACT_OK;
+    if (v->pmtu < 68) PUNT(BELOW_IPV4_MTU);
 
     // Approximate handling of TCP/IPv4 overhead for incoming LRO/GRO packets: default
     // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
@@ -461,7 +461,7 @@
     // a packet we let the core stack deal with things.
     // (The core stack needs to handle limits correctly anyway,
     // since we don't offload all traffic in both directions)
-    if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK;
+    if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) PUNT(LIMIT_REACHED);
 
 
 if (!is_tcp) return TC_ACT_OK; // HACK
@@ -472,7 +472,7 @@
         // because this is easier and the kernel will strip extraneous ethernet header.
         if (bpf_skb_change_head(skb, sizeof(struct ethhdr), /*flags*/ 0)) {
             __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
-            return TC_ACT_OK;
+            PUNT(CHANGE_HEAD_FAILED);
         }
 
         // bpf_skb_change_head() invalidates all pointers - reload them
@@ -486,7 +486,7 @@
         // I do not believe this can ever happen, but keep the verifier happy...
         if (data + sizeof(struct ethhdr) + sizeof(*ip) + (is_tcp ? sizeof(*tcph) : sizeof(*udph)) > data_end) {
             __sync_fetch_and_add(downstream ? &stat_v->rxErrors : &stat_v->txErrors, 1);
-            return TC_ACT_SHOT;
+            DROP(TOO_SHORT);
         }
     };
 
diff --git a/Tethering/jni/com_android_networkstack_tethering_BpfCoordinator.cpp b/Tethering/jni/com_android_networkstack_tethering_BpfCoordinator.cpp
new file mode 100644
index 0000000..27357f8
--- /dev/null
+++ b/Tethering/jni/com_android_networkstack_tethering_BpfCoordinator.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+
+#include "bpf_tethering.h"
+
+namespace android {
+
+static jobjectArray getBpfCounterNames(JNIEnv *env) {
+    size_t size = BPF_TETHER_ERR__MAX;
+    jobjectArray ret = env->NewObjectArray(size, env->FindClass("java/lang/String"), nullptr);
+    for (int i = 0; i < size; i++) {
+        env->SetObjectArrayElement(ret, i, env->NewStringUTF(bpf_tether_errors[i]));
+    }
+    return ret;
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "getBpfCounterNames", "()[Ljava/lang/String;", (void*) getBpfCounterNames },
+};
+
+int register_com_android_networkstack_tethering_BpfCoordinator(JNIEnv* env) {
+    return jniRegisterNativeMethods(env,
+            "com/android/networkstack/tethering/BpfCoordinator",
+            gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/Tethering/jni/onload.cpp b/Tethering/jni/onload.cpp
index 3766de9..e31da60 100644
--- a/Tethering/jni/onload.cpp
+++ b/Tethering/jni/onload.cpp
@@ -24,6 +24,7 @@
 
 int register_android_net_util_TetheringUtils(JNIEnv* env);
 int register_com_android_networkstack_tethering_BpfMap(JNIEnv* env);
+int register_com_android_networkstack_tethering_BpfCoordinator(JNIEnv* env);
 
 extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
     JNIEnv *env;
@@ -36,6 +37,8 @@
 
     if (register_com_android_networkstack_tethering_BpfMap(env) < 0) return JNI_ERR;
 
+    if (register_com_android_networkstack_tethering_BpfCoordinator(env) < 0) return JNI_ERR;
+
     return JNI_VERSION_1_6;
 }
 
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index b17bfcf..985328f 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -59,6 +59,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.Struct;
 import com.android.networkstack.tethering.apishim.common.BpfCoordinatorShim;
 
 import java.net.Inet4Address;
@@ -84,6 +85,13 @@
  * @hide
  */
 public class BpfCoordinator {
+    // Ensure the JNI code is loaded. In production this will already have been loaded by
+    // TetherService, but for tests it needs to be either loaded here or loaded by every test.
+    // TODO: is there a better way?
+    static {
+        System.loadLibrary("tetherutilsjni");
+    }
+
     static final boolean DOWNSTREAM = true;
     static final boolean UPSTREAM = false;
 
@@ -97,6 +105,10 @@
     private static final String TETHER_UPSTREAM6_FS_PATH = makeMapPath(UPSTREAM, 6);
     private static final String TETHER_STATS_MAP_PATH = makeMapPath("stats");
     private static final String TETHER_LIMIT_MAP_PATH = makeMapPath("limit");
+    private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
+
+    /** The names of all the BPF counters defined in bpf_tethering.h. */
+    public static final String[] sBpfCounterNames = getBpfCounterNames();
 
     private static String makeMapPath(String which) {
         return "/sys/fs/bpf/tethering/map_offload_tether_" + which + "_map";
@@ -717,6 +729,12 @@
             dumpIpv4ForwardingRules(pw);
             pw.decreaseIndent();
 
+            pw.println();
+            pw.println("Forwarding counters:");
+            pw.increaseIndent();
+            dumpCounters(pw);
+            pw.decreaseIndent();
+
             dumpDone.open();
         });
         if (!dumpDone.block(DUMP_TIMEOUT_MS)) {
@@ -766,17 +784,16 @@
     }
 
     private void dumpIpv6UpstreamRules(IndentingPrintWriter pw) {
-        final BpfMap<TetherUpstream6Key, Tether6Value> ipv6UpstreamMap = mDeps.getBpfUpstream6Map();
-        if (ipv6UpstreamMap == null) {
-            pw.println("No IPv6 upstream");
-            return;
-        }
-        try {
-            if (ipv6UpstreamMap.isEmpty()) {
+        try (BpfMap<TetherUpstream6Key, Tether6Value> map = mDeps.getBpfUpstream6Map()) {
+            if (map == null) {
+                pw.println("No IPv6 upstream");
+                return;
+            }
+            if (map.isEmpty()) {
                 pw.println("No IPv6 upstream rules");
                 return;
             }
-            ipv6UpstreamMap.forEach((k, v) -> pw.println(ipv6UpstreamRuletoString(k, v)));
+            map.forEach((k, v) -> pw.println(ipv6UpstreamRuletoString(k, v)));
         } catch (ErrnoException e) {
             pw.println("Error dumping IPv4 map: " + e);
         }
@@ -797,25 +814,54 @@
     }
 
     private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) {
-        final BpfMap<Tether4Key, Tether4Value> ipv4UpstreamMap = mDeps.getBpfUpstream4Map();
-        if (ipv4UpstreamMap == null) {
-            pw.println("No IPv4 support");
-            return;
-        }
-        try {
-            if (ipv4UpstreamMap.isEmpty()) {
+        try (BpfMap<Tether4Key, Tether4Value> map = mDeps.getBpfUpstream4Map()) {
+            if (map == null) {
+                pw.println("No IPv4 support");
+                return;
+            }
+            if (map.isEmpty()) {
                 pw.println("No IPv4 rules");
                 return;
             }
             pw.println("[IPv4]: iif(iface) oif(iface) src nat dst");
             pw.increaseIndent();
-            ipv4UpstreamMap.forEach((k, v) -> pw.println(ipv4RuleToString(k, v)));
+            map.forEach((k, v) -> pw.println(ipv4RuleToString(k, v)));
         } catch (ErrnoException e) {
             pw.println("Error dumping IPv4 map: " + e);
         }
         pw.decreaseIndent();
     }
 
+    /**
+     * Simple struct that only contains a u32. Must be public because Struct needs access to it.
+     * TODO: make this a public inner class of Struct so anyone can use it as, e.g., Struct.U32?
+     */
+    public static class U32Struct extends Struct {
+        @Struct.Field(order = 0, type = Struct.Type.U32)
+        public long val;
+    }
+
+    private void dumpCounters(@NonNull IndentingPrintWriter pw) {
+        try (BpfMap<U32Struct, U32Struct> map = new BpfMap<>(TETHER_ERROR_MAP_PATH,
+                BpfMap.BPF_F_RDONLY, U32Struct.class, U32Struct.class)) {
+
+            map.forEach((k, v) -> {
+                String counterName;
+                try {
+                    counterName = sBpfCounterNames[(int) 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);
+                }
+                if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
+            });
+        } catch (ErrnoException e) {
+            pw.println("Error dumping counter map: " + e);
+        }
+    }
+
     /** IPv6 forwarding rule class. */
     public static class Ipv6ForwardingRule {
         public final int upstreamIfindex;
@@ -1298,4 +1344,6 @@
     final SparseArray<String> getInterfaceNamesForTesting() {
         return mInterfaceNames;
     }
+
+    private static native String[] getBpfCounterNames();
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfMap.java b/Tethering/src/com/android/networkstack/tethering/BpfMap.java
index 89caa8a..bc01dbd 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfMap.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfMap.java
@@ -218,7 +218,7 @@
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() throws ErrnoException {
         closeMap(mMapFd);
     }
 
diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp
index 5e4fe52..6c479a0 100644
--- a/Tethering/tests/unit/Android.bp
+++ b/Tethering/tests/unit/Android.bp
@@ -69,6 +69,7 @@
         // For mockito extended
         "libdexmakerjvmtiagent",
         "libstaticjvmtiagent",
+        "libtetherutilsjni",
     ],
 }