Merge "Move libipchecksum to frameworks/libs/net."
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
index a518c76..f7b0d02 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
@@ -114,9 +114,10 @@
         // and will overwrite the flags set above.
         byteBuffer.position(baseOffset);
         nlAttr = StructNlAttr.findNextAttrOfType(IFA_FLAGS, byteBuffer);
-        if (nlAttr != null) {
-            addrMsg.mFlags = nlAttr.getValueAsInt(0 /* default value */);
-        }
+        if (nlAttr == null) return null;
+        final Integer value = nlAttr.getValueAsInteger();
+        if (value == null) return null;
+        addrMsg.mFlags = value;
 
         return addrMsg;
     }
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java
index 485e67c..a9b6495 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java
@@ -287,14 +287,22 @@
     }
 
     /**
-     * Get attribute value as Integer.
+     * Get attribute value as Integer, or null if malformed (e.g., length is not 4 bytes).
      */
-    public int getValueAsInt(int defaultValue) {
+    public Integer getValueAsInteger() {
         final ByteBuffer byteBuffer = getValueAsByteBuffer();
         if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
-            return defaultValue;
+            return null;
         }
-        return getValueAsByteBuffer().getInt();
+        return byteBuffer.getInt();
+    }
+
+    /**
+     * Get attribute value as Int, default value if malformed.
+     */
+    public int getValueAsInt(int defaultValue) {
+        final Integer value = getValueAsInteger();
+        return (value != null) ? value : defaultValue;
     }
 
     /**
@@ -341,6 +349,7 @@
     public String getValueAsString() {
         if (nla_value == null) return null;
         // Check the attribute value length after removing string termination flag '\0'.
+        // This assumes that all netlink strings are null-terminated.
         if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null;
 
         try {
diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java
new file mode 100644
index 0000000..5249454
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+package com.android.net.module.util.structs;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.Inet4Address;
+
+/**
+ * L3 IPv4 header as per https://tools.ietf.org/html/rfc791.
+ * This class doesn't contain options field.
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Version|  IHL  |Type of Service|          Total Length         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |         Identification        |Flags|      Fragment Offset    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Time to Live |    Protocol   |         Header Checksum       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Source Address                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Destination Address                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class Ipv4Header extends Struct {
+    // IP Version=IPv4, IHL is always 5(*4bytes) because options are not supported.
+    @VisibleForTesting
+    public static final byte IPHDR_VERSION_IHL = 0x45;
+
+    @Field(order = 0, type = Type.S8)
+    // version (4 bits), IHL (4 bits)
+    public final byte vi;
+    @Field(order = 1, type = Type.S8)
+    public final byte tos;
+    @Field(order = 2, type = Type.U16)
+    public final int totalLength;
+    @Field(order = 3, type = Type.S16)
+    public final short id;
+    @Field(order = 4, type = Type.S16)
+    // flags (3 bits), fragment offset (13 bits)
+    public final short flagsAndFragmentOffset;
+    @Field(order = 5, type = Type.U8)
+    public final short ttl;
+    @Field(order = 6, type = Type.S8)
+    public final byte protocol;
+    @Field(order = 7, type = Type.S16)
+    public final short checksum;
+    @Field(order = 8, type = Type.Ipv4Address)
+    public final Inet4Address srcIp;
+    @Field(order = 9, type = Type.Ipv4Address)
+    public final Inet4Address dstIp;
+
+    public Ipv4Header(final byte tos, final int totalLength, final short id,
+            final short flagsAndFragmentOffset, final short ttl, final byte protocol,
+            final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) {
+        this(IPHDR_VERSION_IHL, tos, totalLength, id, flagsAndFragmentOffset, ttl,
+                protocol, checksum, srcIp, dstIp);
+    }
+
+    private Ipv4Header(final byte vi, final byte tos, final int totalLength, final short id,
+            final short flagsAndFragmentOffset, final short ttl, final byte protocol,
+            final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) {
+        this.vi = vi;
+        this.tos = tos;
+        this.totalLength = totalLength;
+        this.id = id;
+        this.flagsAndFragmentOffset = flagsAndFragmentOffset;
+        this.ttl = ttl;
+        this.protocol = protocol;
+        this.checksum = checksum;
+        this.srcIp = srcIp;
+        this.dstIp = dstIp;
+    }
+}
diff --git a/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java b/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java
new file mode 100644
index 0000000..0c97401
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package com.android.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * L4 TCP header as per https://tools.ietf.org/html/rfc793.
+ * This class does not contain option and data fields.
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          Source Port          |       Destination Port        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        Sequence Number                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Acknowledgment Number                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Data |           |U|A|P|R|S|F|                               |
+ * | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
+ * |       |           |G|K|H|T|N|N|                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           Checksum            |         Urgent Pointer        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Options                    |    Padding    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                             data                              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+public class TcpHeader extends Struct {
+    @Field(order = 0, type = Type.U16)
+    public final int srcPort;
+    @Field(order = 1, type = Type.U16)
+    public final int dstPort;
+    @Field(order = 2, type = Type.U32)
+    public final long seq;
+    @Field(order = 3, type = Type.U32)
+    public final long ack;
+    @Field(order = 4, type = Type.S16)
+    // data Offset (4 bits), reserved (6 bits), control bits (6 bits)
+    // TODO: update with bitfields once class Struct supports it
+    public final short dataOffsetAndControlBits;
+    @Field(order = 5, type = Type.U16)
+    public final int window;
+    @Field(order = 6, type = Type.S16)
+    public final short checksum;
+    @Field(order = 7, type = Type.U16)
+    public final int urgentPointer;
+
+    public TcpHeader(final int srcPort, final int dstPort, final long seq, final long ack,
+            final short dataOffsetAndControlBits, final int window, final short checksum,
+            final int urgentPointer) {
+        this.srcPort = srcPort;
+        this.dstPort = dstPort;
+        this.seq = seq;
+        this.ack = ack;
+        this.dataOffsetAndControlBits = dataOffsetAndControlBits;
+        this.window = window;
+        this.checksum = checksum;
+        this.urgentPointer = urgentPointer;
+    }
+}
diff --git a/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java b/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java
new file mode 100644
index 0000000..8b0316b
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package com.android.net.module.util.structs;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * L4 UDP header as per https://tools.ietf.org/html/rfc768.
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          Source Port          |       Destination Port        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           Length              |          Checksum             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          data octets  ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ...
+ */
+public class UdpHeader extends Struct {
+    @Field(order = 0, type = Type.U16)
+    public final int srcPort;
+    @Field(order = 1, type = Type.U16)
+    public final int dstPort;
+    @Field(order = 2, type = Type.U16)
+    public final int length;
+    @Field(order = 3, type = Type.S16)
+    public final short checksum;
+
+    public UdpHeader(final int srcPort, final int dstPort, final int length,
+            final short checksum) {
+        this.srcPort = srcPort;
+        this.dstPort = dstPort;
+        this.length = length;
+        this.checksum = checksum;
+    }
+}
diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_map_utils/Android.bp
index 521b682..e14c259 100644
--- a/staticlibs/native/bpf_map_utils/Android.bp
+++ b/staticlibs/native/bpf_map_utils/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_headers {
     name: "bpf_map_utils",
     vendor_available: true,
@@ -25,6 +29,7 @@
     min_sdk_version: "30",
     apex_available: [
         "//apex_available:platform",
+        "com.android.tethering",
         "com.android.art.debug",
     ],
     visibility: [
@@ -35,6 +40,7 @@
         "//frameworks/native/services/gpuservice/gpumem",
         "//frameworks/native/services/gpuservice/tests/unittests",
         "//frameworks/native/services/gpuservice/tracing",
+        "//packages/modules/Connectivity/netd",
         "//packages/modules/Connectivity/tests/unit/jni",
         "//packages/modules/DnsResolver/tests",
         "//system/bpf/bpfloader",
diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp
index 379c8a9..037e10d 100644
--- a/staticlibs/native/bpf_syscall_wrappers/Android.bp
+++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp
@@ -35,6 +35,7 @@
     ],
     visibility: [
         "//frameworks/libs/net/common/native/bpfmapjni",
+        "//packages/modules/Connectivity/netd",
         "//packages/modules/Connectivity/service",
         "//packages/modules/Connectivity/Tethering",
         "//packages/providers/MediaProvider/jni",
diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp
index 3bb6270..732e37d 100644
--- a/staticlibs/netd/libnetdutils/Android.bp
+++ b/staticlibs/netd/libnetdutils/Android.bp
@@ -18,6 +18,7 @@
         "Syscalls.cpp",
         "UniqueFd.cpp",
         "UniqueFile.cpp",
+        "Utils.cpp",
     ],
     defaults: ["netd_defaults"],
     cflags: ["-Wall", "-Werror"],
@@ -36,6 +37,7 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.resolv",
+        "com.android.tethering",
     ],
     min_sdk_version: "29",
 }
diff --git a/staticlibs/netd/libnetdutils/Utils.cpp b/staticlibs/netd/libnetdutils/Utils.cpp
new file mode 100644
index 0000000..16ec882
--- /dev/null
+++ b/staticlibs/netd/libnetdutils/Utils.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 <map>
+
+#include <net/if.h>
+
+#include "dirent.h"
+#include "netdutils/Status.h"
+#include "netdutils/Utils.h"
+
+namespace android {
+namespace netdutils {
+
+StatusOr<std::vector<std::string>> getIfaceNames() {
+    std::vector<std::string> ifaceNames;
+    DIR* d;
+    struct dirent* de;
+
+    if (!(d = opendir("/sys/class/net"))) {
+        return statusFromErrno(errno, "Cannot open iface directory");
+    }
+    while ((de = readdir(d))) {
+        if ((de->d_type != DT_DIR) && (de->d_type != DT_LNK)) continue;
+        if (de->d_name[0] == '.') continue;
+        ifaceNames.push_back(std::string(de->d_name));
+    }
+    closedir(d);
+    return ifaceNames;
+}
+
+StatusOr<std::map<std::string, uint32_t>> getIfaceList() {
+    std::map<std::string, uint32_t> ifacePairs;
+
+    ASSIGN_OR_RETURN(auto ifaceNames, getIfaceNames());
+
+    for (const auto& name : ifaceNames) {
+        uint32_t ifaceIndex = if_nametoindex(name.c_str());
+        if (ifaceIndex) {
+            ifacePairs.insert(std::pair<std::string, uint32_t>(name, ifaceIndex));
+        }
+    }
+    return ifacePairs;
+}
+
+}  // namespace netdutils
+}  // namespace android
diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Utils.h b/staticlibs/netd/libnetdutils/include/netdutils/Utils.h
new file mode 100644
index 0000000..83c583b
--- /dev/null
+++ b/staticlibs/netd/libnetdutils/include/netdutils/Utils.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef NETUTILS_UTILS_H
+#define NETUTILS_UTILS_H
+
+#include "netdutils/StatusOr.h"
+
+namespace android {
+namespace netdutils {
+
+StatusOr<std::vector<std::string>> getIfaceNames();
+
+StatusOr<std::map<std::string, uint32_t>> getIfaceList();
+
+}  // namespace netdutils
+}  // namespace android
+
+#endif /* NETUTILS_UTILS_H */
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt
index 0067931..649b30e 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt
@@ -32,6 +32,7 @@
 class CleanupTest {
     class TestException1 : Exception()
     class TestException2 : Exception()
+    class TestException3 : Exception()
 
     @Test
     fun testNotThrow() {
@@ -172,4 +173,32 @@
         assertTrue(x == 4)
         assertTrue(thrown.suppressedExceptions.isEmpty())
     }
+
+    @Test
+    fun testMultipleCleanups() {
+        var x = 1
+        val thrown = assertFailsWith<TestException1> {
+            tryTest {
+                x = 2
+                throw TestException1()
+            } cleanupStep {
+                assertTrue(x == 2)
+                x = 3
+                throw TestException2()
+                x = 4
+            } cleanupStep {
+                assertTrue(x == 3)
+                x = 5
+                throw TestException3()
+                x = 6
+            } cleanup {
+                assertTrue(x == 5)
+                x = 7
+            }
+        }
+        assertEquals(2, thrown.suppressedExceptions.size)
+        assertTrue(thrown.suppressedExceptions[0] is TestException2)
+        assertTrue(thrown.suppressedExceptions[1] is TestException3)
+        assert(x == 7)
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java
index 83abfa1..8a13397 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java
@@ -20,6 +20,7 @@
 import static com.android.testutils.MiscAsserts.assertThrows;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.util.Log;
 
@@ -31,6 +32,7 @@
     private static final String TAG = CleanupTestJava.class.getSimpleName();
     private static final class TestException1 extends Exception {}
     private static final class TestException2 extends Exception {}
+    private static final class TestException3 extends Exception {}
 
     @Test
     public void testNotThrow() {
@@ -93,4 +95,27 @@
         );
         assertEquals(3, x.get());
     }
+
+    @Test
+    public void testMultipleCleanups() {
+        final AtomicInteger x = new AtomicInteger(1);
+        final TestException1 exception = assertThrows(TestException1.class, () ->
+                testAndCleanup(() -> {
+                    x.compareAndSet(1, 2);
+                    throw new TestException1();
+                }, () -> {
+                        x.compareAndSet(2, 3);
+                        throw new TestException2();
+                    }, () -> {
+                        x.compareAndSet(3, 4);
+                        throw new TestException3();
+                    }, () -> {
+                        x.compareAndSet(4, 5);
+                    })
+        );
+        assertEquals(2, exception.getSuppressed().length);
+        assertTrue(exception.getSuppressed()[0] instanceof TestException2);
+        assertTrue(exception.getSuppressed()[1] instanceof TestException3);
+        assertEquals(5, x.get());
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
index 5d446b8..9db63db 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
@@ -47,7 +47,7 @@
     private static final String RTM_NEWLINK_HEX =
             "64000000100000000000000000000000"   // struct nlmsghr
             + "000001001E0000000210000000000000" // struct ifinfo
-            + "0A000300776C616E30000000"         // IFLA_IFNAME
+            + "0A000300776C616E30000000"         // IFLA_IFNAME(wlan0)
             + "08000D00B80B0000"                 // IFLA_PROTINFO
             + "0500100002000000"                 // IFLA_OPERSTATE
             + "0500110001000000"                 // IFLA_LINKMODE
@@ -88,12 +88,47 @@
         assertTrue(linkMsg.getInterfaceName().equals("wlan0"));
     }
 
+    /**
+     * Example:
+     * # adb shell ip tunnel add トン0 mode sit local any remote 8.8.8.8
+     * # adb shell ip link show | grep トン
+     * 33: トン0@NONE: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group
+     *     default qlen 1000
+     *
+     * IFLA_IFNAME attribute: \x0c\x00\x03\x00\xe3\x83\x88\xe3\x83\xb3\x30\x00
+     *     length: 0x000c
+     *     type: 0x0003
+     *     value: \xe3\x83\x88\xe3\x83\xb3\x30\x00
+     *            ト (\xe3\x83\x88)
+     *            ン (\xe3\x83\xb3)
+     *            0  (\x30)
+     *            null terminated (\x00)
+     */
+    private static final String RTM_NEWLINK_UTF8_HEX =
+            "34000000100000000000000000000000"   // struct nlmsghr
+            + "000001001E0000000210000000000000" // struct ifinfo
+            + "08000400DC050000"                 // IFLA_MTU
+            + "0A00010092C3E3C9374E0000"         // IFLA_ADDRESS
+            + "0C000300E38388E383B33000";        // IFLA_IFNAME(トン0)
+
+    @Test
+    public void testParseRtmNewLink_utf8Ifname() {
+        final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_UTF8_HEX);
+        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
+        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
+        assertNotNull(msg);
+        assertTrue(msg instanceof RtNetlinkLinkMessage);
+        final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg;
+
+        assertTrue(linkMsg.getInterfaceName().equals("トン0"));
+    }
+
     private static final String RTM_NEWLINK_PACK_HEX =
             "34000000100000000000000000000000"   // struct nlmsghr
             + "000001001E0000000210000000000000" // struct ifinfo
             + "08000400DC050000"                 // IFLA_MTU
             + "0A00010092C3E3C9374E0000"         // IFLA_ADDRESS
-            + "0A000300776C616E30000000";        // IFLA_IFNAME
+            + "0A000300776C616E30000000";        // IFLA_IFNAME(wlan0)
 
     @Test
     public void testPackRtmNewLink() {
@@ -117,7 +152,7 @@
             + "0500100002000000"                 // IFLA_OPERSTATE
             + "0800010092C3E3C9"                 // IFLA_ADDRESS(truncated)
             + "0500110001000000"                 // IFLA_LINKMODE
-            + "0A000300776C616E30000000"         // IFLA_IFNAME
+            + "0A000300776C616E30000000"         // IFLA_IFNAME(wlan0)
             + "08000400DC050000";                // IFLA_MTU
 
     @Test
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
index 72e179b..af3fac2 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
@@ -16,6 +16,7 @@
 
 package com.android.net.module.util.netlink;
 
+import static com.android.net.module.util.netlink.RtNetlinkAddressMessage.IFA_FLAGS;
 import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_ADDRESS;
 import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_IFNAME;
 
@@ -35,6 +36,7 @@
 public class StructNlAttrTest {
     private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("00:11:22:33:44:55");
     private static final String TEST_INTERFACE_NAME = "wlan0";
+    private static final int TEST_ADDR_FLAGS = 0x80;
 
     @Test
     public void testGetValueAsMacAddress() {
@@ -65,4 +67,29 @@
         final String str2 = attr2.getValueAsString();
         assertEquals(str2, TEST_INTERFACE_NAME);
     }
+
+    @Test
+    public void testGetValueAsIntger() {
+        final StructNlAttr attr1 = new StructNlAttr(IFA_FLAGS, TEST_ADDR_FLAGS);
+        final Integer integer1 = attr1.getValueAsInteger();
+        final int int1 = attr1.getValueAsInt(0x08 /* default value */);
+        assertEquals(integer1, new Integer(TEST_ADDR_FLAGS));
+        assertEquals(int1, TEST_ADDR_FLAGS);
+
+        // Malformed attribute.
+        final byte[] malformed_int = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x80, };
+        final StructNlAttr attr2 = new StructNlAttr(IFA_FLAGS, malformed_int);
+        final Integer integer2 = attr2.getValueAsInteger();
+        final int int2 = attr2.getValueAsInt(0x08 /* default value */);
+        assertNull(integer2);
+        assertEquals(int2, 0x08 /* default value */);
+
+        // Null attribute value.
+        final byte[] null_int = null;
+        final StructNlAttr attr3 = new StructNlAttr(IFA_FLAGS, null_int);
+        final Integer integer3 = attr3.getValueAsInteger();
+        final int int3 = attr3.getValueAsInt(0x08 /* default value */);
+        assertNull(integer3);
+        assertEquals(int3, 0x08 /* default value */);
+    }
 }
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt
index be5c9b2..4a7b351 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt
@@ -17,6 +17,7 @@
 package com.android.testutils
 
 import android.net.netstats.provider.NetworkStatsProvider
+import android.util.Log
 import com.android.net.module.util.ArrayTrackRecord
 import kotlin.test.assertEquals
 import kotlin.test.assertTrue
@@ -43,23 +44,28 @@
         data class OnSetAlert(val quotaBytes: Long) : CallbackType()
     }
 
+    private val TAG = this::class.simpleName
     val history = ArrayTrackRecord<CallbackType>().newReadHead()
     // See ReadHead#mark
     val mark get() = history.mark
 
     override fun onRequestStatsUpdate(token: Int) {
+        Log.d(TAG, "onRequestStatsUpdate $token")
         history.add(CallbackType.OnRequestStatsUpdate(token))
     }
 
     override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) {
+        Log.d(TAG, "onSetWarningAndLimit $iface $warningBytes $limitBytes")
         history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes))
     }
 
     override fun onSetLimit(iface: String, quotaBytes: Long) {
+        Log.d(TAG, "onSetLimit $iface $quotaBytes")
         history.add(CallbackType.OnSetLimit(iface, quotaBytes))
     }
 
     override fun onSetAlert(quotaBytes: Long) {
+        Log.d(TAG, "onSetAlert $quotaBytes")
         history.add(CallbackType.OnSetAlert(quotaBytes))
     }
 
diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
index 1b67f68..45783d8 100644
--- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
+++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
@@ -22,14 +22,6 @@
 import com.android.testutils.ExceptionUtils.ThrowingSupplier
 import javax.annotation.CheckReturnValue
 
-@CheckReturnValue
-fun <T> tryTest(block: () -> T) = TryExpr(
-        try {
-            Result.success(block())
-        } catch (e: Throwable) {
-            Result.failure(e)
-        })
-
 /**
  * Utility to do cleanup in tests without replacing exceptions with those from a finally block.
  *
@@ -54,11 +46,15 @@
  * to the standard try{}finally{}, if both throws, the construct throws the exception that happened
  * in tryTest{} rather than the one that happened in cleanup{}.
  *
- * Kotlin usage is as try{}finally{} :
+ * Kotlin usage is as try{}finally{}, but with multiple finally{} blocks :
  * tryTest {
  *   testing code
+ * } cleanupStep {
+ *   cleanup code 1
+ * } cleanupStep {
+ *   cleanup code 2
  * } cleanup {
- *   cleanup code
+ *   cleanup code 3
  * }
  * Catch blocks can be added with the following syntax :
  * tryTest {
@@ -67,14 +63,24 @@
  *   do something to it
  * }
  *
- * Java doesn't allow this kind of syntax, so instead a function taking 2 lambdas is provided.
+ * Java doesn't allow this kind of syntax, so instead a function taking lambdas is provided.
  * testAndCleanup(() -> {
  *   testing code
  * }, () -> {
- *   cleanup code
+ *   cleanup code 1
+ * }, () -> {
+ *   cleanup code 2
  * });
  */
 
+@CheckReturnValue
+fun <T> tryTest(block: () -> T) = TryExpr(
+        try {
+            Result.success(block())
+        } catch (e: Throwable) {
+            Result.failure(e)
+        })
+
 // Some downstream branches have an older kotlin that doesn't know about value classes.
 // TODO : Change this to "value class" when aosp no longer merges into such branches.
 @Suppress("INLINE_CLASS_DEPRECATED")
@@ -89,30 +95,31 @@
         })
     }
 
-    inline infix fun cleanup(block: () -> Unit): T {
+    @CheckReturnValue
+    inline infix fun cleanupStep(block: () -> Unit): TryExpr<T> {
         try {
             block()
         } catch (e: Throwable) {
             val originalException = result.exceptionOrNull()
-            if (null == originalException) {
-                throw e
+            return TryExpr(if (null == originalException) {
+                Result.failure(e)
             } else {
                 originalException.addSuppressed(e)
-                throw originalException
-            }
+                Result.failure(originalException)
+            })
         }
-        return result.getOrThrow()
+        return this
     }
+
+    inline infix fun cleanup(block: () -> Unit): T = cleanupStep(block).result.getOrThrow()
 }
 
 // Java support
-fun <T> testAndCleanup(tryBlock: ThrowingSupplier<T>, cleanupBlock: ThrowingRunnable): T {
-    return tryTest {
-        tryBlock.get()
-    } cleanup {
-        cleanupBlock.run()
-    }
+fun <T> testAndCleanup(tryBlock: ThrowingSupplier<T>, vararg cleanupBlock: ThrowingRunnable): T {
+    return cleanupBlock.fold(tryTest { tryBlock.get() }) { previousExpr, nextCleanup ->
+        previousExpr.cleanupStep { nextCleanup.run() }
+    }.cleanup {}
 }
-fun testAndCleanup(tryBlock: ThrowingRunnable, cleanupBlock: ThrowingRunnable) {
-    return testAndCleanup(ThrowingSupplier { tryBlock.run() }, cleanupBlock)
+fun testAndCleanup(tryBlock: ThrowingRunnable, vararg cleanupBlock: ThrowingRunnable) {
+    return testAndCleanup(ThrowingSupplier { tryBlock.run() }, *cleanupBlock)
 }