Merge "[VCN06.1] Add CTS for request background network"
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index 2bdddc1..4dc1c51 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -324,20 +324,20 @@
         return true;
     }
 
+    private String mapStatus(BpfMap m, String name) {
+        return name + "{" + (m != null ? "OK" : "ERROR") + "}";
+    }
+
     @Override
     public String toString() {
-        return "mBpfDownstream4Map{"
-                + (mBpfDownstream4Map != null ? "initialized" : "not initialized") + "}, "
-                + "mBpfUpstream4Map{"
-                + (mBpfUpstream4Map != null ? "initialized" : "not initialized") + "}, "
-                + "mBpfUpstream6Map{"
-                + (mBpfUpstream6Map != null ? "initialized" : "not initialized") + "}, "
-                + "mBpfDownstream6Map{"
-                + (mBpfDownstream6Map != null ? "initialized" : "not initialized") + "}, "
-                + "mBpfStatsMap{"
-                + (mBpfStatsMap != null ? "initialized" : "not initialized") + "}, "
-                + "mBpfLimitMap{"
-                + (mBpfLimitMap != null ? "initialized" : "not initialized") + "} ";
+        return String.join(", ", new String[] {
+                mapStatus(mBpfDownstream6Map, "mBpfDownstream6Map"),
+                mapStatus(mBpfUpstream6Map, "mBpfUpstream6Map"),
+                mapStatus(mBpfDownstream4Map, "mBpfDownstream4Map"),
+                mapStatus(mBpfUpstream4Map, "mBpfUpstream4Map"),
+                mapStatus(mBpfStatsMap, "mBpfStatsMap"),
+                mapStatus(mBpfLimitMap, "mBpfLimitMap")
+        });
     }
 
     /**
diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c
index 3a3291d..2997031 100644
--- a/Tethering/bpf_progs/offload.c
+++ b/Tethering/bpf_progs/offload.c
@@ -40,13 +40,13 @@
 
 // ----- IPv6 Support -----
 
-DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, TetherDownstream6Value, 64,
+DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 64,
                    AID_NETWORK_STACK)
 
 DEFINE_BPF_MAP_GRW(tether_downstream64_map, HASH, TetherDownstream64Key, TetherDownstream64Value,
                    64, AID_NETWORK_STACK)
 
-DEFINE_BPF_MAP_GRW(tether_upstream6_map, HASH, TetherUpstream6Key, TetherUpstream6Value, 64,
+DEFINE_BPF_MAP_GRW(tether_upstream6_map, HASH, TetherUpstream6Key, Tether6Value, 64,
                    AID_NETWORK_STACK)
 
 static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet,
@@ -113,14 +113,13 @@
             .iif = skb->ifindex,
     };
 
-    TetherDownstream6Value* vd = downstream ? bpf_tether_downstream6_map_lookup_elem(&kd) : NULL;
-    TetherUpstream6Value* vu = downstream ? NULL : bpf_tether_upstream6_map_lookup_elem(&ku);
+    Tether6Value* v = downstream ? bpf_tether_downstream6_map_lookup_elem(&kd)
+                                 : bpf_tether_upstream6_map_lookup_elem(&ku);
 
     // If we don't find any offload information then simply let the core stack handle it...
-    if (downstream && !vd) return TC_ACT_OK;
-    if (!downstream && !vu) return TC_ACT_OK;
+    if (!v) return TC_ACT_OK;
 
-    uint32_t stat_and_limit_k = downstream ? skb->ifindex : vu->oif;
+    uint32_t stat_and_limit_k = downstream ? skb->ifindex : v->oif;
 
     TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
 
@@ -133,8 +132,7 @@
     if (!limit_v) return TC_ACT_OK;
 
     // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
-    const int pmtu = downstream ? vd->pmtu : vu->pmtu;
-    if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
+    if (v->pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
 
     // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
     // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
@@ -145,9 +143,9 @@
     // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
     uint64_t packets = 1;
     uint64_t bytes = skb->len;
-    if (bytes > pmtu) {
+    if (bytes > v->pmtu) {
         const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
-        const int mss = pmtu - tcp_overhead;
+        const int mss = v->pmtu - tcp_overhead;
         const uint64_t payload = bytes - tcp_overhead;
         packets = (payload + mss - 1) / mss;
         bytes = tcp_overhead * packets + payload;
@@ -203,7 +201,7 @@
 
     // Overwrite any mac header with the new one
     // For a rawip tx interface it will simply be a bunch of zeroes and later stripped.
-    *eth = downstream ? vd->macHeader : vu->macHeader;
+    *eth = v->macHeader;
 
     // Redirect to forwarded interface.
     //
@@ -211,7 +209,7 @@
     // The redirect actually happens after the ebpf program has already terminated,
     // and can fail for example for mtu reasons at that point in time, but there's nothing
     // we can do about it here.
-    return bpf_redirect(downstream ? vd->oif : vu->oif, 0 /* this is effectively BPF_F_EGRESS */);
+    return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
 }
 
 DEFINE_BPF_PROG("schedcls/tether_downstream6_ether", AID_ROOT, AID_NETWORK_STACK,
diff --git a/Tethering/bpf_progs/test.c b/Tethering/bpf_progs/test.c
index aedc9a0..c4a8271 100644
--- a/Tethering/bpf_progs/test.c
+++ b/Tethering/bpf_progs/test.c
@@ -23,7 +23,7 @@
 #include "netdbpf/bpf_shared.h"
 
 // Used only by TetheringPrivilegedTests, not by production code.
-DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, TetherDownstream6Value, 16,
+DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 16,
                    AID_NETWORK_STACK)
 
 DEFINE_BPF_PROG_KVER("xdp/drop_ipv4_udp_ether", AID_ROOT, AID_NETWORK_STACK,
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 35de400..b17bfcf 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -64,6 +64,7 @@
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -677,6 +678,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));
+    }
+
     /**
      * Dump information.
      * Block the function until all the data are dumped on the handler thread or timed-out. The
@@ -705,11 +712,9 @@
 
             pw.println("Forwarding rules:");
             pw.increaseIndent();
-            if (mIpv6ForwardingRules.size() == 0) {
-                pw.println("<empty>");
-            } else {
-                dumpIpv6ForwardingRules(pw);
-            }
+            dumpIpv6UpstreamRules(pw);
+            dumpIpv6ForwardingRules(pw);
+            dumpIpv4ForwardingRules(pw);
             pw.decreaseIndent();
 
             dumpDone.open();
@@ -729,6 +734,11 @@
     }
 
     private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) {
+        if (mIpv6ForwardingRules.size() == 0) {
+            pw.println("No IPv6 rules");
+            return;
+        }
+
         for (Map.Entry<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>> entry :
                 mIpv6ForwardingRules.entrySet()) {
             IpServer ipServer = entry.getKey();
@@ -749,6 +759,63 @@
         }
     }
 
+    private String ipv6UpstreamRuletoString(TetherUpstream6Key key, Tether6Value value) {
+        return String.format("%d(%s) -> %d(%s) %04x %s %s",
+                key.iif, getIfName(key.iif), value.oif, getIfName(value.oif),
+                value.ethProto, value.ethSrcMac, value.ethDstMac);
+    }
+
+    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()) {
+                pw.println("No IPv6 upstream rules");
+                return;
+            }
+            ipv6UpstreamMap.forEach((k, v) -> pw.println(ipv6UpstreamRuletoString(k, v)));
+        } catch (ErrnoException e) {
+            pw.println("Error dumping IPv4 map: " + e);
+        }
+    }
+
+    private String ipv4RuleToString(Tether4Key key, Tether4Value value) {
+        final String private4, public4, dst4;
+        try {
+            private4 = InetAddress.getByAddress(key.src4).getHostAddress();
+            dst4 = InetAddress.getByAddress(key.dst4).getHostAddress();
+            public4 = InetAddress.getByAddress(value.src46).getHostAddress();
+        } catch (UnknownHostException impossible) {
+            throw new AssertionError("4-byte array not valid IPv4 address!");
+        }
+        return String.format("%d(%s) %d(%s) %s:%d -> %s:%d -> %s:%d",
+                key.iif, getIfName(key.iif), value.oif, getIfName(value.oif),
+                private4, key.srcPort, public4, value.srcPort, dst4, key.dstPort);
+    }
+
+    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()) {
+                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)));
+        } catch (ErrnoException e) {
+            pw.println("Error dumping IPv4 map: " + e);
+        }
+        pw.decreaseIndent();
+    }
+
     /** IPv6 forwarding rule class. */
     public static class Ipv6ForwardingRule {
         public final int upstreamIfindex;
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 2354c2d..385c691 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2225,6 +2225,13 @@
                 && !isProvisioningNeededButUnavailable();
     }
 
+    private void dumpBpf(IndentingPrintWriter pw) {
+        pw.println("BPF offload:");
+        pw.increaseIndent();
+        mBpfCoordinator.dump(pw);
+        pw.decreaseIndent();
+    }
+
     void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
         // Binder.java closes the resource for us.
         @SuppressWarnings("resource")
@@ -2235,6 +2242,11 @@
             return;
         }
 
+        if (argsContain(args, "bpf")) {
+            dumpBpf(pw);
+            return;
+        }
+
         pw.println("Tethering:");
         pw.increaseIndent();
 
@@ -2286,10 +2298,7 @@
         mOffloadController.dump(pw);
         pw.decreaseIndent();
 
-        pw.println("BPF offload:");
-        pw.increaseIndent();
-        mBpfCoordinator.dump(pw);
-        pw.decreaseIndent();
+        dumpBpf(pw);
 
         pw.println("Private address coordinator:");
         pw.increaseIndent();
diff --git a/framework/Android.bp b/framework/Android.bp
deleted file mode 100644
index 8db8d76..0000000
--- a/framework/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Copyright (C) 2020 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.
-//
-
-// TODO: use a java_library in the bootclasspath instead
-filegroup {
-    name: "framework-connectivity-sources",
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.aidl",
-    ],
-    path: "src",
-    visibility: [
-        "//frameworks/base",
-        "//packages/modules/Connectivity:__subpackages__",
-    ],
-}
\ No newline at end of file
diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
deleted file mode 100644
index 64b5567..0000000
--- a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2020, 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 perNmissions and
- * limitations under the License.
- */
-package com.android.connectivity.aidl;
-
-import android.net.NattKeepalivePacketData;
-import android.net.QosFilterParcelable;
-import android.net.TcpKeepalivePacketData;
-
-import com.android.connectivity.aidl.INetworkAgentRegistry;
-
-/**
- * Interface to notify NetworkAgent of connectivity events.
- * @hide
- */
-oneway interface INetworkAgent {
-    void onRegistered(in INetworkAgentRegistry registry);
-    void onDisconnected();
-    void onBandwidthUpdateRequested();
-    void onValidationStatusChanged(int validationStatus,
-            in @nullable String captivePortalUrl);
-    void onSaveAcceptUnvalidated(boolean acceptUnvalidated);
-    void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
-        in NattKeepalivePacketData packetData);
-    void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
-        in TcpKeepalivePacketData packetData);
-    void onStopSocketKeepalive(int slot);
-    void onSignalStrengthThresholdsUpdated(in int[] thresholds);
-    void onPreventAutomaticReconnect();
-    void onAddNattKeepalivePacketFilter(int slot,
-        in NattKeepalivePacketData packetData);
-    void onAddTcpKeepalivePacketFilter(int slot,
-        in TcpKeepalivePacketData packetData);
-    void onRemoveKeepalivePacketFilter(int slot);
-    void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
-    void onQosCallbackUnregistered(int qosCallbackId);
-}
diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
deleted file mode 100644
index f0193db..0000000
--- a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2020, 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 perNmissions and
- * limitations under the License.
- */
-package com.android.connectivity.aidl;
-
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.QosSession;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-
-/**
- * Interface for NetworkAgents to send network network properties.
- * @hide
- */
-oneway interface INetworkAgentRegistry {
-    void sendNetworkCapabilities(in NetworkCapabilities nc);
-    void sendLinkProperties(in LinkProperties lp);
-    // TODO: consider replacing this by "markConnected()" and removing
-    void sendNetworkInfo(in NetworkInfo info);
-    void sendScore(int score);
-    void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
-    void sendSocketKeepaliveEvent(int slot, int reason);
-    void sendUnderlyingNetworks(in @nullable List<Network> networks);
-    void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
-    void sendQosSessionLost(int qosCallbackId, in QosSession session);
-    void sendQosCallbackError(int qosCallbackId, int exceptionType);
-}