From 0937911c419dc786d34aa94f0975a952ece30b8c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 2 Dec 2022 12:43:24 +0900 Subject: [PATCH] Add a method helper to create RTM_NEWADDR message in user space. Bug: 260934173 Test: atest NetworkStaticLibTests Change-Id: I39a53a3d8b0cd10437aeed502657dd34d8b7775d --- .../util/netlink/RtNetlinkAddressMessage.java | 47 ++++++++++++++++++ .../netlink/RtNetlinkAddressMessageTest.java | 48 ++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) 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 f7b0d02fb7..3748e46271 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 androidx.annotation.VisibleForTesting; 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 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { 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/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 7d8dbd2bbb..b21e06096d 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 androidx.test.runner.AndroidJUnit4; import com.android.net.module.util.HexDump; +import libcore.util.HexEncoding; + import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +47,7 @@ import java.nio.ByteOrder; @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 = @@ -127,6 +132,47 @@ public class RtNetlinkAddressMessageTest { assertNull(msg); } + @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);