Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11dbaed0 authored by Xiao Ma's avatar Xiao Ma
Browse files

Support Neighbor Advertisement packet w/o TLLA option parsing.

Sometimes the NA packet might not take target link-layer address option,
then parsing these packets will throw exception, fix this restriction.

Bug: 163492391
Test: atest NetworkStackTests NetworkStackIntegratonTests
Change-Id: I1b0517d1ebd70b3219f0a200d1f4aafaf8adb300
parent dce80e1d
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -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 class NeighborAdvertisement {
    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 @@ public class NeighborAdvertisement {
        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 @@ public class NeighborAdvertisement {
        ipv6Hdr.writeToByteBuffer(packet);
        icmpv6Hdr.writeToByteBuffer(packet);
        naHdr.writeToByteBuffer(packet);
        if (tlla != null) {
            tlla.writeToByteBuffer(packet);
        }
        packet.flip();

        return packet;
@@ -100,7 +103,7 @@ public class NeighborAdvertisement {
     */
    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 @@ public class NeighborAdvertisement {
        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);
    }
+2 −4
Original line number Diff line number Diff line
@@ -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 @@ import java.nio.ByteBuffer;
 * @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 class NeighborSolicitation {
     */
    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);
        }
+73 −10
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.networkstack.packets;
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 @@ public final class NeighborAdvertisementTest {
        // 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 @@ public final class NeighborAdvertisementTest {
        (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 @@ public final class NeighborAdvertisementTest {
        (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 @@ public final class NeighborAdvertisementTest {
        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,19 +218,45 @@ public final class NeighborAdvertisementTest {
        assertEquals(0, na.icmpv6Hdr.code);
        assertEquals(0, na.naHdr.flags);
        assertEquals(TEST_TARGET_ADDR, na.naHdr.target);
        assertEquals(2, na.tlla.type);
        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,
+4 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.networkstack.packets;
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 @@ public final class NeighborSolicitationTest {
        (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 @@ public final class NeighborSolicitationTest {
        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);
        }
    }