Merge "Support Neighbor Advertisement packet w/o TLLA option parsing." am: c6eb439fcb am: a73d636cc5
Original change: https://android-review.googlesource.com/c/platform/packages/modules/NetworkStack/+/1736503
Change-Id: If32c3b7fa2f5f49039d7449c4856c0c6b9422250
diff --git a/src/com/android/networkstack/packets/NeighborAdvertisement.java b/src/com/android/networkstack/packets/NeighborAdvertisement.java
index e6cdfc8..ef38314 100644
--- a/src/com/android/networkstack/packets/NeighborAdvertisement.java
+++ b/src/com/android/networkstack/packets/NeighborAdvertisement.java
@@ -17,13 +17,14 @@
package com.android.networkstack.packets;
import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
-import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
import android.net.MacAddress;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.Struct;
@@ -50,12 +51,12 @@
public final Icmpv6Header icmpv6Hdr;
@NonNull
public final NaHeader naHdr;
- @NonNull
+ @Nullable
public final LlaOption tlla;
public NeighborAdvertisement(@NonNull final EthernetHeader ethHdr,
@NonNull final Ipv6Header ipv6Hdr, @NonNull final Icmpv6Header icmpv6Hdr,
- @NonNull final NaHeader naHdr, @NonNull final LlaOption tlla) {
+ @NonNull final NaHeader naHdr, @Nullable final LlaOption tlla) {
this.ethHdr = ethHdr;
this.ipv6Hdr = ipv6Hdr;
this.icmpv6Hdr = icmpv6Hdr;
@@ -71,7 +72,7 @@
final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class);
final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class);
final int naHeaderLen = Struct.getSize(NaHeader.class);
- final int tllaOptionLen = Struct.getSize(LlaOption.class);
+ final int tllaOptionLen = (tlla == null) ? 0 : Struct.getSize(LlaOption.class);
final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen
+ icmpv6HeaderLen + naHeaderLen + tllaOptionLen);
@@ -79,7 +80,9 @@
ipv6Hdr.writeToByteBuffer(packet);
icmpv6Hdr.writeToByteBuffer(packet);
naHdr.writeToByteBuffer(packet);
- tlla.writeToByteBuffer(packet);
+ if (tlla != null) {
+ tlla.writeToByteBuffer(packet);
+ }
packet.flip();
return packet;
@@ -100,7 +103,7 @@
*/
public static NeighborAdvertisement parse(@NonNull final byte[] recvbuf, final int length)
throws ParseException {
- if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN
+ if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NA_HEADER_LEN
|| recvbuf.length < length) {
throw new ParseException("Invalid packet length: " + length);
}
@@ -111,7 +114,9 @@
final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, packet);
final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, packet);
final NaHeader naHdr = Struct.parse(NaHeader.class, packet);
- final LlaOption tlla = Struct.parse(LlaOption.class, packet);
+ final LlaOption tlla = (packet.remaining() == 0)
+ ? null
+ : Struct.parse(LlaOption.class, packet);
return new NeighborAdvertisement(ethHdr, ipv6Hdr, icmpv6Hdr, naHdr, tlla);
}
diff --git a/src/com/android/networkstack/packets/NeighborSolicitation.java b/src/com/android/networkstack/packets/NeighborSolicitation.java
index e743209..5c3e40a 100644
--- a/src/com/android/networkstack/packets/NeighborSolicitation.java
+++ b/src/com/android/networkstack/packets/NeighborSolicitation.java
@@ -17,8 +17,8 @@
package com.android.networkstack.packets;
import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
-import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NS_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
import android.net.MacAddress;
@@ -43,8 +43,6 @@
* @hide
*/
public class NeighborSolicitation {
- private static final int NS_HEADER_LEN = Struct.getSize(NsHeader.class);
-
@NonNull
public final EthernetHeader ethHdr;
@NonNull
@@ -105,7 +103,7 @@
*/
public static NeighborSolicitation parse(@NonNull final byte[] recvbuf, final int length)
throws ParseException {
- if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN + NS_HEADER_LEN
+ if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NS_HEADER_LEN
|| recvbuf.length < length) {
throw new ParseException("Invalid packet length: " + length);
}
diff --git a/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java b/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
index 3317b2b..c689d7b 100644
--- a/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
+++ b/tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java
@@ -19,6 +19,7 @@
import static android.system.OsConstants.ETH_P_IPV6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
import static com.android.testutils.MiscAsserts.assertThrows;
@@ -90,6 +91,41 @@
// Link-Layer address
(byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25,
};
+ private static final byte[] TEST_GRATUITOUS_NA_WITHOUT_TLLA = new byte[] {
+ // dst mac address
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ // src mac address
+ (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25,
+ // ether type
+ (byte) 0x86, (byte) 0xdd,
+ // version, priority and flow label
+ (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ // length
+ (byte) 0x00, (byte) 0x20,
+ // next header
+ (byte) 0x3a,
+ // hop limit
+ (byte) 0xff,
+ // source address
+ (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0,
+ (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d,
+ // destination address
+ (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+ // ICMP type, code, checksum
+ (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c,
+ // flags
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ // target address
+ (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d,
+ (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78,
+ };
private static final byte[] TEST_GRATUITOUS_NA_LESS_LENGTH = new byte[] {
// dst mac address
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
@@ -115,6 +151,10 @@
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
+ // ICMP type, code, checksum
+ (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c,
+ // flags
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
private static final byte[] TEST_GRATUITOUS_NA_TRUNCATED = new byte[] {
// dst mac address
@@ -152,7 +192,7 @@
(byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78,
// TLLA option
(byte) 0x02, (byte) 0x01,
- // Link-Layer address
+ // truncatd Link-Layer address: 4bytes
(byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25,
};
@@ -165,11 +205,8 @@
assertArrayEquals(na.array(), TEST_GRATUITOUS_NA);
}
- @Test
- public void testGratuitousNa_parse() throws Exception {
- final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA,
- TEST_GRATUITOUS_NA.length);
-
+ private void assertNeighborAdvertisement(final NeighborAdvertisement na,
+ boolean hasTllaOption) {
assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.ethHdr.srcMac.toByteArray());
assertArrayEquals(TEST_DST_MAC_ADDR, na.ethHdr.dstMac.toByteArray());
assertEquals(ETH_P_IPV6, na.ethHdr.etherType);
@@ -181,20 +218,46 @@
assertEquals(0, na.icmpv6Hdr.code);
assertEquals(0, na.naHdr.flags);
assertEquals(TEST_TARGET_ADDR, na.naHdr.target);
- assertEquals(2, na.tlla.type);
- assertEquals(1, na.tlla.length);
- assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray());
+ if (hasTllaOption) {
+ assertEquals(ICMPV6_ND_OPTION_TLLA, na.tlla.type);
+ assertEquals(1, na.tlla.length);
+ assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray());
+ }
+ }
+ @Test
+ public void testGratuitousNa_parse() throws Exception {
+ final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA,
+ TEST_GRATUITOUS_NA.length);
+
+ assertNeighborAdvertisement(na, true /* hasTllaOption */);
assertArrayEquals(TEST_GRATUITOUS_NA, na.toByteBuffer().array());
}
@Test
- public void testGratuitousNa_invalidByteBufferParameters() throws Exception {
+ public void testGratuitousNa_parseWithoutTllaOption() throws Exception {
+ final NeighborAdvertisement na =
+ NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_WITHOUT_TLLA,
+ TEST_GRATUITOUS_NA_WITHOUT_TLLA.length);
+
+ assertNeighborAdvertisement(na, false /* hasTllaOption */);
+ assertArrayEquals(TEST_GRATUITOUS_NA_WITHOUT_TLLA, na.toByteBuffer().array());
+ }
+
+ @Test
+ public void testGratuitousNa_zeroPacketLength() throws Exception {
assertThrows(NeighborAdvertisement.ParseException.class,
() -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, 0));
}
@Test
+ public void testGratuitousNa_invalidByteBufferLength() throws Exception {
+ assertThrows(NeighborAdvertisement.ParseException.class,
+ () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_TRUNCATED,
+ TEST_GRATUITOUS_NA.length));
+ }
+
+ @Test
public void testGratuitousNa_lessPacketLength() throws Exception {
assertThrows(NeighborAdvertisement.ParseException.class,
() -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_LESS_LENGTH,
diff --git a/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java b/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
index c3ff239..18a3ef3 100644
--- a/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
+++ b/tests/unit/src/com/android/networkstack/packets/NeighborSolicitationTest.java
@@ -19,6 +19,7 @@
import static android.system.OsConstants.ETH_P_IPV6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
import static com.android.testutils.MiscAsserts.assertThrows;
@@ -193,7 +194,7 @@
(byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44,
// slla option
(byte) 0x01, (byte) 0x01,
- // link-layer address
+ // truncatd link-layer address: 4bytes
(byte) 0x06, (byte) 0x5a, (byte) 0xac, (byte) 0x02,
};
@@ -218,6 +219,8 @@
assertEquals(0, ns.icmpv6Hdr.code);
assertEquals(TEST_TARGET_ADDR, ns.nsHdr.target);
if (hasSllaOption) {
+ assertEquals(ICMPV6_ND_OPTION_SLLA, ns.slla.type);
+ assertEquals(1, ns.slla.length);
assertEquals(MacAddress.fromBytes(TEST_SOURCE_MAC_ADDR), ns.slla.linkLayerAddress);
}
}