Add data structures to parse netlink IP address messages.
Bug: 163492391
Test: atest NetworkStaticLibsTests
Change-Id: I85f1b80925fa4a9397df931902d6de189902da72
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 11aee84..07b52d8 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java
@@ -144,6 +144,8 @@
// Netlink groups.
public static final int RTMGRP_LINK = 1;
+ public static final int RTMGRP_IPV4_IFADDR = 0x10;
+ public static final int RTMGRP_IPV6_IFADDR = 0x100;
public static final int RTNLGRP_ND_USEROPT = 20;
public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1);
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java
index d83c12f..708736e 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java
@@ -123,6 +123,9 @@
case NetlinkConstants.RTM_NEWLINK:
case NetlinkConstants.RTM_DELLINK:
return (NetlinkMessage) RtNetlinkLinkMessage.parse(nlmsghdr, byteBuffer);
+ case NetlinkConstants.RTM_NEWADDR:
+ case NetlinkConstants.RTM_DELADDR:
+ return (NetlinkMessage) RtNetlinkAddressMessage.parse(nlmsghdr, byteBuffer);
case NetlinkConstants.RTM_NEWNEIGH:
case NetlinkConstants.RTM_DELNEIGH:
case NetlinkConstants.RTM_GETNEIGH:
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
new file mode 100644
index 0000000..a518c76
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
@@ -0,0 +1,157 @@
+/*
+ * 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.netlink;
+
+import android.system.OsConstants;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.net.module.util.HexDump;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * A NetlinkMessage subclass for rtnetlink address messages.
+ *
+ * RtNetlinkAddressMessage.parse() must be called with a ByteBuffer that contains exactly one
+ * netlink message.
+ *
+ * see also:
+ *
+ * include/uapi/linux/rtnetlink.h
+ *
+ * @hide
+ */
+public class RtNetlinkAddressMessage extends NetlinkMessage {
+ public static final short IFA_ADDRESS = 1;
+ public static final short IFA_CACHEINFO = 6;
+ public static final short IFA_FLAGS = 8;
+
+ private int mFlags;
+ @NonNull
+ private StructIfaddrMsg mIfaddrmsg;
+ @NonNull
+ private InetAddress mIpAddress;
+ @Nullable
+ private StructIfacacheInfo mIfacacheInfo;
+
+ private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) {
+ super(header);
+ mIfaddrmsg = null;
+ mIpAddress = null;
+ mIfacacheInfo = null;
+ mFlags = 0;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ @NonNull
+ public StructIfaddrMsg getIfaddrHeader() {
+ return mIfaddrmsg;
+ }
+
+ @NonNull
+ public InetAddress getIpAddress() {
+ return mIpAddress;
+ }
+
+ @Nullable
+ public StructIfacacheInfo getIfacacheInfo() {
+ return mIfacacheInfo;
+ }
+
+ /**
+ * Parse rtnetlink address message from {@link ByteBuffer}. This method must be called with a
+ * ByteBuffer that contains exactly one netlink message.
+ *
+ * @param header netlink message header.
+ * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes.
+ */
+ @Nullable
+ public static RtNetlinkAddressMessage parse(@NonNull final StructNlMsgHdr header,
+ @NonNull final ByteBuffer byteBuffer) {
+ final RtNetlinkAddressMessage addrMsg = new RtNetlinkAddressMessage(header);
+
+ addrMsg.mIfaddrmsg = StructIfaddrMsg.parse(byteBuffer);
+ if (addrMsg.mIfaddrmsg == null) return null;
+
+ // IFA_ADDRESS
+ final int baseOffset = byteBuffer.position();
+ StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFA_ADDRESS, byteBuffer);
+ if (nlAttr == null) return null;
+ addrMsg.mIpAddress = nlAttr.getValueAsInetAddress();
+ if (addrMsg.mIpAddress == null) return null;
+
+ // IFA_CACHEINFO
+ byteBuffer.position(baseOffset);
+ nlAttr = StructNlAttr.findNextAttrOfType(IFA_CACHEINFO, byteBuffer);
+ if (nlAttr != null) {
+ addrMsg.mIfacacheInfo = StructIfacacheInfo.parse(nlAttr.getValueAsByteBuffer());
+ }
+
+ // The first 8 bits of flags are in the ifaddrmsg.
+ addrMsg.mFlags = addrMsg.mIfaddrmsg.flags;
+ // IFA_FLAGS. All the flags are in the IF_FLAGS attribute. This should always be present,
+ // 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 */);
+ }
+
+ return addrMsg;
+ }
+
+ /**
+ * Write a rtnetlink address message to {@link ByteBuffer}.
+ */
+ @VisibleForTesting
+ protected void pack(ByteBuffer byteBuffer) {
+ getHeader().pack(byteBuffer);
+ mIfaddrmsg.pack(byteBuffer);
+
+ final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, mIpAddress);
+ address.pack(byteBuffer);
+
+ if (mIfacacheInfo != null) {
+ final StructNlAttr cacheInfo = new StructNlAttr(IFA_CACHEINFO,
+ mIfacacheInfo.writeToBytes());
+ cacheInfo.pack(byteBuffer);
+ }
+
+ // If IFA_FLAGS attribute isn't present on the wire at parsing netlink message, it will
+ // still be packed to ByteBuffer even if the flag is 0.
+ final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags);
+ flags.pack(byteBuffer);
+ }
+
+ @Override
+ public String toString() {
+ return "RtNetlinkAddressMessage{ "
+ + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, "
+ + "Ifaddrmsg{" + mIfaddrmsg.toString() + "}, "
+ + "IP Address{" + mIpAddress.getHostAddress() + "}, "
+ + "IfacacheInfo{" + (mIfacacheInfo == null ? "" : mIfacacheInfo.toString()) + "}, "
+ + "Address Flags{" + HexDump.toHexString(mFlags) + "} "
+ + "}";
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java
new file mode 100644
index 0000000..360f56d
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.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.netlink;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+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.nio.ByteBuffer;
+
+/**
+ * struct ifa_cacheinfo
+ *
+ * see also:
+ *
+ * include/uapi/linux/if_addr.h
+ *
+ * @hide
+ */
+public class StructIfacacheInfo extends Struct {
+ // Already aligned.
+ public static final int STRUCT_SIZE = 16;
+
+ @Field(order = 0, type = Type.U32)
+ public final long preferred;
+ @Field(order = 1, type = Type.U32)
+ public final long valid;
+ @Field(order = 2, type = Type.U32)
+ public final long cstamp; // created timestamp, hundredths of seconds.
+ @Field(order = 3, type = Type.U32)
+ public final long tstamp; // updated timestamp, hundredths of seconds.
+
+ StructIfacacheInfo(long preferred, long valid, long cstamp, long tstamp) {
+ this.preferred = preferred;
+ this.valid = valid;
+ this.cstamp = cstamp;
+ this.tstamp = tstamp;
+ }
+
+ /**
+ * Parse an ifa_cacheinfo struct from a {@link ByteBuffer}.
+ *
+ * @param byteBuffer The buffer from which to parse the ifa_cacheinfo.
+ * @return the parsed ifa_cacheinfo struct, or {@code null} if the ifa_cacheinfo struct
+ * could not be parsed successfully (for example, if it was truncated).
+ */
+ @Nullable
+ public static StructIfacacheInfo parse(@NonNull final ByteBuffer byteBuffer) {
+ if (byteBuffer.remaining() < STRUCT_SIZE) return null;
+
+ // The ByteOrder must already have been set to native order.
+ return Struct.parse(StructIfacacheInfo.class, byteBuffer);
+ }
+
+ /**
+ * Write an ifa_cacheinfo struct to {@link ByteBuffer}.
+ */
+ public void pack(@NonNull final ByteBuffer byteBuffer) {
+ // The ByteOrder must already have been set to native order.
+ this.writeToByteBuffer(byteBuffer);
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java
new file mode 100644
index 0000000..9196feb
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java
@@ -0,0 +1,82 @@
+/*
+ * 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.netlink;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+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.nio.ByteBuffer;
+
+/**
+ * struct ifaddrmsg
+ *
+ * see also:
+ *
+ * include/uapi/linux/if_addr.h
+ *
+ * @hide
+ */
+public class StructIfaddrMsg extends Struct {
+ // Already aligned.
+ public static final int STRUCT_SIZE = 8;
+
+ @Field(order = 0, type = Type.U8)
+ public final short family;
+ @Field(order = 1, type = Type.U8)
+ public final short prefixLen;
+ @Field(order = 2, type = Type.U8)
+ public final short flags;
+ @Field(order = 3, type = Type.U8)
+ public final short scope;
+ @Field(order = 4, type = Type.S32)
+ public final int index;
+
+ StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) {
+ this.family = family;
+ this.prefixLen = prefixLen;
+ this.flags = flags;
+ this.scope = scope;
+ this.index = index;
+ }
+
+ /**
+ * Parse an ifaddrmsg struct from a {@link ByteBuffer}.
+ *
+ * @param byteBuffer The buffer from which to parse the ifaddrmsg.
+ * @return the parsed ifaddrmsg struct, or {@code null} if the ifaddrmsg struct
+ * could not be parsed successfully (for example, if it was truncated).
+ */
+ @Nullable
+ public static StructIfaddrMsg parse(@NonNull final ByteBuffer byteBuffer) {
+ if (byteBuffer.remaining() < STRUCT_SIZE) return null;
+
+ // The ByteOrder must already have been set to native order.
+ return Struct.parse(StructIfaddrMsg.class, byteBuffer);
+ }
+
+ /**
+ * Write an ifaddrmsg struct to {@link ByteBuffer}.
+ */
+ public void pack(@NonNull final ByteBuffer byteBuffer) {
+ // The ByteOrder must already have been set to native order.
+ this.writeToByteBuffer(byteBuffer);
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
index 881dc18..02d1574 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
@@ -58,22 +58,22 @@
}
/**
- * Parse a rtnetlink link message header from a {@link ByteBuffer}.
+ * Parse an ifinfomsg struct from a {@link ByteBuffer}.
*
- * @param byteBuffer The buffer from which to parse the rtnetlink link message header.
- * @return the parsed rtnetlink link message header, or {@code null} if the rtnetlink message
- * header could not be parsed successfully (for example, if it was truncated).
+ * @param byteBuffer The buffer from which to parse the ifinfomsg.
+ * @return the parsed ifinfomsg struct, or {@code null} if the ifinfomsg struct
+ * could not be parsed successfully (for example, if it was truncated).
*/
@Nullable
public static StructIfinfoMsg parse(@NonNull final ByteBuffer byteBuffer) {
if (byteBuffer.remaining() < STRUCT_SIZE) return null;
// The ByteOrder must already have been set to native order.
- return StructIfinfoMsg.parse(StructIfinfoMsg.class, byteBuffer);
+ return Struct.parse(StructIfinfoMsg.class, byteBuffer);
}
/**
- * Write ifinfomsg to {@link ByteBuffer}.
+ * Write an ifinfomsg struct to {@link ByteBuffer}.
*/
public void pack(@NonNull final ByteBuffer byteBuffer) {
// The ByteOrder must already have been set to native order.
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
new file mode 100644
index 0000000..7d8dbd2
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.netlink;
+
+import static android.system.OsConstants.NETLINK_ROUTE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.InetAddresses;
+import android.system.OsConstants;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.net.module.util.HexDump;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet6Address;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RtNetlinkAddressMessageTest {
+ private static final Inet6Address TEST_LINK_LOCAL =
+ (Inet6Address) InetAddresses.parseNumericAddress("fe80::2C41:5CFF:FE09:6665");
+
+ // An example of the full RTM_NEWADDR message.
+ private static final String RTM_NEWADDR_HEX =
+ "48000000140000000000000000000000" // struct nlmsghr
+ + "0A4080FD1E000000" // struct ifaddrmsg
+ + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS
+ + "14000600100E0000201C00002A70000045700000" // IFA_CACHEINFO
+ + "0800080080000000"; // IFA_FLAGS
+
+ private ByteBuffer toByteBuffer(final String hexString) {
+ return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString));
+ }
+
+ @Test
+ public void testParseRtmNewAddress() {
+ final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
+ assertNotNull(msg);
+ assertTrue(msg instanceof RtNetlinkAddressMessage);
+ final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg;
+
+ final StructNlMsgHdr hdr = addrMsg.getHeader();
+ assertNotNull(hdr);
+ assertEquals(72, hdr.nlmsg_len);
+ assertEquals(NetlinkConstants.RTM_NEWADDR, hdr.nlmsg_type);
+ assertEquals(0, hdr.nlmsg_flags);
+ assertEquals(0, hdr.nlmsg_seq);
+ assertEquals(0, hdr.nlmsg_pid);
+
+ final StructIfaddrMsg ifaddrMsgHdr = addrMsg.getIfaddrHeader();
+ assertNotNull(ifaddrMsgHdr);
+ assertEquals((byte) OsConstants.AF_INET6, ifaddrMsgHdr.family);
+ assertEquals(64, ifaddrMsgHdr.prefixLen);
+ assertEquals(0x80, ifaddrMsgHdr.flags);
+ assertEquals(0xFD, ifaddrMsgHdr.scope);
+ assertEquals(30, ifaddrMsgHdr.index);
+
+ assertEquals((Inet6Address) addrMsg.getIpAddress(), TEST_LINK_LOCAL);
+ assertEquals(3600L, addrMsg.getIfacacheInfo().preferred);
+ assertEquals(7200L, addrMsg.getIfacacheInfo().valid);
+ assertEquals(28714, addrMsg.getIfacacheInfo().cstamp);
+ assertEquals(28741, addrMsg.getIfacacheInfo().tstamp);
+ assertEquals(0x80, addrMsg.getFlags());
+ }
+
+ private static final String RTM_NEWADDR_PACK_HEX =
+ "48000000140000000000000000000000" // struct nlmsghr
+ + "0A4080FD1E000000" // struct ifaddrmsg
+ + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS
+ + "14000600FFFFFFFFFFFFFFFF2A7000002A700000" // IFA_CACHEINFO
+ + "0800080081000000"; // IFA_FLAGS(override ifa_flags)
+
+ @Test
+ public void testPackRtmNewAddr() {
+ final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_PACK_HEX);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
+ assertNotNull(msg);
+ assertTrue(msg instanceof RtNetlinkAddressMessage);
+ final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg;
+
+ final ByteBuffer packBuffer = ByteBuffer.allocate(72);
+ packBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
+ addrMsg.pack(packBuffer);
+ assertEquals(RTM_NEWADDR_PACK_HEX, HexDump.toHexString(packBuffer.array()));
+ }
+
+ private static final String RTM_NEWADDR_TRUNCATED_HEX =
+ "44000000140000000000000000000000" // struct nlmsghr
+ + "0A4080FD1E000000" // struct ifaddrmsg
+ + "10000100FE800000000000002C415CFF" // IFA_ADDRESS(truncated)
+ + "14000600FFFFFFFFFFFFFFFF2A7000002A700000" // IFA_CACHEINFO
+ + "0800080080000000"; // IFA_FLAGS
+
+ @Test
+ public void testTruncatedRtmNewAddr() {
+ final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_TRUNCATED_HEX);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
+ // Parsing RTM_NEWADDR with truncated IFA_ADDRESS attribute returns null.
+ assertNull(msg);
+ }
+
+ @Test
+ public void testToString() {
+ final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
+ assertNotNull(msg);
+ assertTrue(msg instanceof RtNetlinkAddressMessage);
+ final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg;
+ final String expected = "RtNetlinkAddressMessage{ "
+ + "nlmsghdr{"
+ + "StructNlMsgHdr{ nlmsg_len{72}, nlmsg_type{20(RTM_NEWADDR)}, nlmsg_flags{0()}, "
+ + "nlmsg_seq{0}, nlmsg_pid{0} }}, "
+ + "Ifaddrmsg{"
+ + "family: 10, prefixLen: 64, flags: 128, scope: 253, index: 30}, "
+ + "IP Address{fe80::2c41:5cff:fe09:6665}, "
+ + "IfacacheInfo{"
+ + "preferred: 3600, valid: 7200, cstamp: 28714, tstamp: 28741}, "
+ + "Address Flags{00000080} "
+ + "}";
+ assertEquals(expected, addrMsg.toString());
+ }
+}
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 58a7478..5d446b8 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
@@ -42,7 +42,6 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RtNetlinkLinkMessageTest {
- private static final String TAG = "RtNetlinkLinkMessageTest";
// An example of the full RTM_NEWLINK message.
private static final String RTM_NEWLINK_HEX =