Add InetDiagMessage.inetDiagReqV2 with different args

This CL also adds SOCK_DESTROY constants.
These changes will be used by upcoming CLs that implement socket destroy
in ConnectivityService.

Bug: 270298713
Test: atest NetworkStaticLibTests
Change-Id: Ief507b3f8cc4fe23c08699e7fc8f3f62e5acfcdc
diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
index 5a180e7..0a2f50d 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
@@ -58,8 +58,8 @@
     private static final int TIMEOUT_MS = 500;
 
     /**
-     * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
-     * if local and remote are not both null or both non-null.
+     * Construct an inet_diag_req_v2 message. This method will throw
+     * {@link IllegalArgumentException} if local and remote are not both null or both non-null.
      */
     public static byte[] inetDiagReqV2(int protocol, InetSocketAddress local,
             InetSocketAddress remote, int family, short flags) {
@@ -68,16 +68,16 @@
     }
 
     /**
-     * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
-     * if local and remote are not both null or both non-null.
+     * Construct an inet_diag_req_v2 message. This method will throw
+     * {@code IllegalArgumentException} if local and remote are not both null or both non-null.
      *
      * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
      *                 IPPROTO_UDP, or IPPROTO_UDPLITE.
      * @param local local socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+     *              {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of
      *              local or remote address is null.
      * @param remote remote socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+     *              {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of
      *              local or remote address is null.
      * @param family the ip family of the request message. This should be set to either AF_INET or
      *               AF_INET6 for IPv4 or IPv6 sockets respectively.
@@ -90,18 +90,47 @@
      */
     public static byte[] inetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
             @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
-            int state) throws NullPointerException {
+            int state) throws IllegalArgumentException {
+        // Request for all sockets if no specific socket is requested. Specify the local and remote
+        // socket address information for target request socket.
+        if ((local == null) != (remote == null)) {
+            throw new IllegalArgumentException(
+                    "Local and remote must be both null or both non-null");
+        }
+        final StructInetDiagSockId id = ((local != null && remote != null)
+                ? new StructInetDiagSockId(local, remote) : null);
+        return inetDiagReqV2(protocol, id, family,
+                SOCK_DIAG_BY_FAMILY, flags, pad, idiagExt, state);
+    }
+
+    /**
+     * Construct an inet_diag_req_v2 message.
+     *
+     * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
+     *                 IPPROTO_UDP, or IPPROTO_UDPLITE.
+     * @param id inet_diag_sockid. See {@link StructInetDiagSockId}
+     * @param family the ip family of the request message. This should be set to either AF_INET or
+     *               AF_INET6 for IPv4 or IPv6 sockets respectively.
+     * @param type message types.
+     * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h.
+     * @param pad for raw socket protocol specification.
+     * @param idiagExt a set of flags defining what kind of extended information to report.
+     * @param state a bit mask that defines a filter of socket states.
+     * @return bytes array representation of the message
+     */
+    public static byte[] inetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family,
+            short type, short flags, int pad, int idiagExt, int state) {
         final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
         final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
         byteBuffer.order(ByteOrder.nativeOrder());
 
         final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
         nlMsgHdr.nlmsg_len = bytes.length;
-        nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+        nlMsgHdr.nlmsg_type = type;
         nlMsgHdr.nlmsg_flags = flags;
         nlMsgHdr.pack(byteBuffer);
         final StructInetDiagReqV2 inetDiagReqV2 =
-                new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
+                new StructInetDiagReqV2(protocol, id, family, pad, idiagExt, state);
 
         inetDiagReqV2.pack(byteBuffer);
         return bytes;
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java
index c44a5b4..44c51d8 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java
@@ -141,6 +141,7 @@
 
     /* see include/uapi/linux/sock_diag.h */
     public static final short SOCK_DIAG_BY_FAMILY = 20;
+    public static final short SOCK_DESTROY = 21;
 
     // Netlink groups.
     public static final int RTMGRP_LINK = 1;
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java
index 6eef865..3b47008 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java
@@ -18,7 +18,6 @@
 
 import androidx.annotation.Nullable;
 
-import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 
 /**
@@ -48,23 +47,11 @@
     private final int mState;
     public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
 
-    public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
-            int family) {
-        this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
-                INET_DIAG_REQ_V2_ALL_STATES);
-    }
-
-    public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
-            @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
-            throws NullPointerException {
+    public StructInetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, int pad,
+            int extension, int state) {
         mSdiagFamily = (byte) family;
         mSdiagProtocol = (byte) protocol;
-        // Request for all sockets if no specific socket is requested. Specify the local and remote
-        // socket address information for target request socket.
-        if ((local == null) != (remote == null)) {
-            throw new NullPointerException("Local and remote must be both null or both non-null");
-        }
-        mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
+        mId = id;
         mPad = (byte) pad;
         mIdiagExt = (byte) extension;
         mState = state;
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
index ebc0b95..30796d2 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
@@ -22,6 +22,8 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.NETLINK_INET_DIAG;
 
+import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 
@@ -221,14 +223,14 @@
             msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
                     NLM_F_REQUEST);
             fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
+        } catch (IllegalArgumentException e) {
         }
 
         try {
             msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
                     NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
             fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
+        } catch (IllegalArgumentException e) {
         }
 
         msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
@@ -277,6 +279,45 @@
         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES, msg);
     }
 
+    // Hexadecimal representation of InetDiagReqV2 request with SOCK_DESTROY
+    private static final String INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX =
+            // struct nlmsghdr
+            "48000000" +     // length = 72
+            "1500" +         // type = SOCK_DESTROY
+            "0500" +         // flags = NLM_F_REQUEST | NLM_F_ACK
+            "00000000" +     // seqno
+            "00000000" +     // pid (0 == kernel)
+            // struct inet_diag_req_v2
+            "0a" +           // family = AF_INET6
+            "06" +           // protcol = IPPROTO_TCP
+            "00" +           // idiag_ext
+            "00" +           // pad
+            "ffffffff" +     // idiag_states = TCP_ALL_STATES
+            // inet_diag_sockid
+            "a817" +     // idiag_sport = 43031
+            "960f" +     // idiag_dport = 38415
+            "20010db8000000000000000000000001" + // idiag_src = 2001:db8::1
+            "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2
+            "07000000" + // idiag_if = 7
+            "5800000000000000"; // idiag_cookie = 88
+
+    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES =
+            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX.toCharArray(), false);
+
+    @Test
+    public void testInetDiagReqV2TcpInet6Destroy() throws Exception {
+        final StructInetDiagSockId sockId = new StructInetDiagSockId(
+                new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031),
+                new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415),
+                7  /* ifIndex */,
+                88 /* cookie */);
+        final byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, sockId, AF_INET6,
+                SOCK_DESTROY, (short) (NLM_F_REQUEST | NLM_F_ACK), 0 /* pad */, 0 /* idiagExt */,
+                TCP_ALL_STATES);
+
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES, msg);
+    }
+
     private void assertNlMsgHdr(StructNlMsgHdr hdr, short type, short flags, int seq, int pid) {
         assertNotNull(hdr);
         assertEquals(type, hdr.nlmsg_type);