Merge "Add the name of the expected callback"
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index f4997a1..63c8b4e 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -70,6 +70,7 @@
   libs: [
       "androidx.annotation_annotation",
       "framework-annotations-lib",
+      "framework-configinfrastructure",
       "framework-connectivity.stubs.module_lib",
   ],
   lint: { strict_updatability_linting: true },
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 f7b0d02..3748e46 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
@@ -16,6 +16,10 @@
 
 package com.android.net.module.util.netlink;
 
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+
 import android.system.OsConstants;
 
 import androidx.annotation.NonNull;
@@ -24,8 +28,10 @@
 
 import com.android.net.module.util.HexDump;
 
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 /**
  * A NetlinkMessage subclass for rtnetlink address messages.
@@ -145,6 +151,47 @@
         flags.pack(byteBuffer);
     }
 
+    /**
+     * A convenience method to create an RTM_NEWADDR message.
+     */
+    public static byte[] newRtmNewAddressMessage(int seqNo, final InetAddress ip, short prefixlen,
+            byte flags, byte scope, int ifIndex, long preferred, long valid) {
+        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR;
+        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
+        nlmsghdr.nlmsg_seq = seqNo;
+
+        final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr);
+        final byte family =
+                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+        msg.mIfaddrmsg = new StructIfaddrMsg(family, prefixlen, flags, scope, ifIndex);
+        msg.mIpAddress = ip;
+        msg.mIfacacheInfo = new StructIfacacheInfo(preferred, valid, 0 /* cstamp */,
+                0 /* tstamp */);
+        msg.mFlags = (int) (flags & 0xFF);
+
+        final byte[] bytes = new byte[msg.getRequiredSpace()];
+        nlmsghdr.nlmsg_len = bytes.length;
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        msg.pack(byteBuffer);
+        return bytes;
+    }
+
+    private int getRequiredSpace() {
+        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE;
+        if (mIpAddress != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length);
+        }
+        if (mIfacacheInfo != null) {
+            spaceRequired += NetlinkConstants.alignedLengthOf(
+                    StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE);
+        }
+        spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; // IFA_FLAGS "u32" attr
+        return spaceRequired;
+    }
+
     @Override
     public String toString() {
         return "RtNetlinkAddressMessage{ "
diff --git a/staticlibs/framework/com/android/net/module/util/BinderUtils.java b/staticlibs/framework/com/android/net/module/util/BinderUtils.java
index eb695d1..e4d14ea 100644
--- a/staticlibs/framework/com/android/net/module/util/BinderUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/BinderUtils.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.os.Binder;
 
+import java.util.function.Supplier;
+
 /**
  * Collection of utilities for {@link Binder} and related classes.
  * @hide
@@ -56,4 +58,39 @@
         /** @see java.lang.Runnable */
         void run() throws T;
     }
+
+    /**
+     * Convenience method for running the provided action enclosed in
+     * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} returning the
+     * result.
+     *
+     * <p>Any exception thrown by the given action will be caught and rethrown after
+     * the call to {@link Binder#restoreCallingIdentity}.
+     *
+     * Note that this is copied from Binder#withCleanCallingIdentity with minor changes
+     * since it is not public.
+     *
+     * @hide
+     */
+    public static final <T, E extends Exception> T withCleanCallingIdentity(
+            @NonNull ThrowingSupplier<T, E> action) throws E {
+        final long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            return action.get();
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+    }
+
+    /**
+     * An equivalent of {@link Supplier}
+     *
+     * @param <T> The class which is declared to be returned.
+     * @param <E> The exception class which is declared to be thrown.
+     */
+    @FunctionalInterface
+    public interface ThrowingSupplier<T, E extends Exception> {
+        /** @see java.util.function.Supplier */
+        T get() throws E;
+    }
 }
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index c652c76..ea56593 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -137,6 +137,14 @@
         BPF_FUNC_map_update_elem;
 static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
                                          const void* key) = (void*)BPF_FUNC_map_delete_elem;
+static int (*bpf_ringbuf_output_unsafe)(const struct bpf_map_def* ringbuf,
+                                        const void* data, __u64 size, __u64 flags) = (void*)
+        BPF_FUNC_ringbuf_output;
+static void* (*bpf_ringbuf_reserve_unsafe)(const struct bpf_map_def* ringbuf,
+                                           __u64 size, __u64 flags) = (void*)
+        BPF_FUNC_ringbuf_reserve;
+static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void*)
+        BPF_FUNC_ringbuf_submit;
 
 #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)  \
         struct ____btf_map_##name {                     \
@@ -147,6 +155,50 @@
         __attribute__ ((section(".maps." #name), used)) \
                 ____btf_map_##name = { }
 
+#define DEFINE_BPF_MAP_BASE(the_map, TYPE, keysize, valuesize, num_entries, \
+                            usr, grp, md, selinux, pindir, share, minkver,  \
+                            maxkver)                                        \
+  const struct bpf_map_def SECTION("maps") the_map = {                      \
+      .type = BPF_MAP_TYPE_##TYPE,                                          \
+      .key_size = (keysize),                                                \
+      .value_size = (valuesize),                                            \
+      .max_entries = (num_entries),                                         \
+      .map_flags = 0,                                                       \
+      .uid = (usr),                                                         \
+      .gid = (grp),                                                         \
+      .mode = (md),                                                         \
+      .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                       \
+      .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                       \
+      .min_kver = (minkver),                                                \
+      .max_kver = (maxkver),                                                \
+      .selinux_context = (selinux),                                         \
+      .pin_subdir = (pindir),                                               \
+      .shared = (share),                                                    \
+  };
+
+// Type safe macro to declare a ring buffer and related output functions.
+// Compatibility:
+// * BPF ring buffers are only available kernels 5.8 and above. Any program
+//   accessing the ring buffer should set a program level min_kver >= 5.8.
+// * The definition below sets a map min_kver of 5.8 which requires targeting
+//   a BPFLOADER_MIN_VER >= BPFLOADER_S_VERSION.
+#define DEFINE_BPF_RINGBUF(the_map, ValueType, size_bytes, usr, grp, md, \
+                           selinux, pindir, share)                       \
+  DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md,  \
+                      selinux, pindir, share, KVER(5, 8, 0), KVER_INF);  \
+  static inline __always_inline __unused int bpf_##the_map##_output(    \
+      const ValueType* v) {                                              \
+    return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0);        \
+  }                                                                      \
+  static inline __always_inline __unused                                 \
+      ValueType* bpf_##the_map##_reserve() {                             \
+    return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0);   \
+  }                                                                      \
+  static inline __always_inline __unused void bpf_##the_map##_submit(    \
+      const ValueType* v) {                                              \
+    bpf_ringbuf_submit_unsafe(v, 0);                                     \
+  }
+
 /* There exist buggy kernels with pre-T OS, that due to
  * kernel patch "[ALPS05162612] bpf: fix ubsan error"
  * do not support userspace writes into non-zero index of bpf map arrays.
@@ -167,23 +219,9 @@
 /* type safe macro to declare a map and related accessor functions */
 #define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md,         \
                            selinux, pindir, share)                                               \
-    const struct bpf_map_def SECTION("maps") the_map = {                                         \
-            .type = BPF_MAP_TYPE_##TYPE,                                                         \
-            .key_size = sizeof(KeyType),                                                         \
-            .value_size = sizeof(ValueType),                                                     \
-            .max_entries = (num_entries),                                                        \
-            .map_flags = 0,                                                                      \
-            .uid = (usr),                                                                        \
-            .gid = (grp),                                                                        \
-            .mode = (md),                                                                        \
-            .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                      \
-            .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                      \
-            .min_kver = KVER_NONE,                                                               \
-            .max_kver = KVER_INF,                                                                \
-            .selinux_context = selinux,                                                          \
-            .pin_subdir = pindir,                                                                \
-            .shared = share,                                                                     \
-    };                                                                                           \
+  DEFINE_BPF_MAP_BASE(the_map, TYPE, sizeof(KeyType), sizeof(ValueType),                         \
+                      num_entries, usr, grp, md, selinux, pindir, share,                         \
+                      KVER_NONE, KVER_INF);                                                      \
     BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md));                                 \
     BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType);                                           \
                                                                                                  \
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
index 7d8dbd2..b21e060 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
@@ -16,8 +16,11 @@
 
 package com.android.net.module.util.netlink;
 
+import static android.system.OsConstants.IFA_F_PERMANENT;
 import static android.system.OsConstants.NETLINK_ROUTE;
+import static android.system.OsConstants.RT_SCOPE_LINK;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -31,6 +34,8 @@
 
 import com.android.net.module.util.HexDump;
 
+import libcore.util.HexEncoding;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -42,7 +47,7 @@
 @SmallTest
 public class RtNetlinkAddressMessageTest {
     private static final Inet6Address TEST_LINK_LOCAL =
-            (Inet6Address) InetAddresses.parseNumericAddress("fe80::2C41:5CFF:FE09:6665");
+            (Inet6Address) InetAddresses.parseNumericAddress("FE80::2C41:5CFF:FE09:6665");
 
     // An example of the full RTM_NEWADDR message.
     private static final String RTM_NEWADDR_HEX =
@@ -128,6 +133,47 @@
     }
 
     @Test
+    public void testCreateRtmNewAddressMessage() {
+        // Hexadecimal representation of our created packet.
+        final String expectedNewAddressHex =
+                // struct nlmsghdr
+                "48000000" +    // length = 72
+                "1400" +        // type = 20 (RTM_NEWADDR)
+                "0501" +        // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE
+                "01000000" +    // seqno = 1
+                "00000000" +    // pid = 0 (send to kernel)
+                // struct IfaddrMsg
+                "0A" +          // family = inet6
+                "40" +          // prefix len = 64
+                "80" +          // flags = IFA_F_PERMANENT
+                "FD" +          // scope = RT_SCOPE_LINK
+                "17000000" +    // ifindex = 23
+                // struct nlattr: IFA_ADDRESS
+                "1400" +        // len
+                "0100" +        // type
+                "FE800000000000002C415CFFFE096665" + // IP address = fe80::2C41:5cff:fe09:6665
+                // struct nlattr: IFA_CACHEINFO
+                "1400" +        // len
+                "0600" +        // type
+                "FFFFFFFF" +    // preferred = infinite
+                "FFFFFFFF" +    // valid = infinite
+                "00000000" +    // cstamp
+                "00000000" +    // tstamp
+                // struct nlattr: IFA_FLAGS
+                "0800" +        // len
+                "0800" +        // type
+                "80000000";     // flags = IFA_F_PERMANENT
+        final byte[] expectedNewAddress =
+                HexEncoding.decode(expectedNewAddressHex.toCharArray(), false);
+
+        final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */,
+                TEST_LINK_LOCAL, (short) 64 /* prefix len */, (byte) IFA_F_PERMANENT /* flags */,
+                (byte) RT_SCOPE_LINK /* scope */, 23 /* ifindex */,
+                (long) 0xFFFFFFFF /* preferred */, (long) 0xFFFFFFFF /* valid */);
+        assertArrayEquals(expectedNewAddress, bytes);
+    }
+
+    @Test
     public void testToString() {
         final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX);
         byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.