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

Commit e17d9966 authored by Aaron Huang's avatar Aaron Huang
Browse files

Fix RAs with different retansmission timer would be dropped by apf

When firmware receives RAs with different retransmission
timer, it is expected the RAs should be accepted by apf
filter. However, they are currently dropped since missing
fields which should be added into match section. It causes
to apf filter treats those RAs as the same and then drops.

This change adds the remaining fields to match section to
compare reachable time and retransmission timer with incoming
RAs.

Also, add test to check that RIOs differing only in the
first 4 bytes are different should be passed.

Bug: 143186590
Test: sent RAs with different rtt and check RAs are accepted
Change-Id: I7e2de29740f96b212634b5aeffe709d57afafc68
parent 0945160a
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -514,9 +514,9 @@ public class ApfFilter {
        public final Type type;
        /** Offset into the packet at which this section begins. */
        public final int start;
        /** Length of this section. */
        /** Length of this section in bytes. */
        public final int length;
        /** If this is a lifetime, the ICMP option that the defined it. 0 for router lifetime. */
        /** If this is a lifetime, the ICMP option that defined it. 0 for router lifetime. */
        public final int option;
        /** If this is a lifetime, the lifetime value. */
        public final long lifetime;
@@ -785,8 +785,9 @@ public class ApfFilter {
            addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, 0, routerLifetime);
            builder.updateRouterLifetime(routerLifetime);

            // Ensures that the RA is not truncated.
            mPacket.position(ICMP6_RA_OPTION_OFFSET);
            // Add remaining fields (reachable time and retransmission timer) to match section.
            addMatchUntil(ICMP6_RA_OPTION_OFFSET);

            while (mPacket.hasRemaining()) {
                final int position = mPacket.position();
                final int optionType = getUint8(mPacket, position);
@@ -797,7 +798,7 @@ public class ApfFilter {
                        mPrefixOptionOffsets.add(position);

                        // Parse valid lifetime
                        addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
                        addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
                        lifetime = getUint32(mPacket, mPacket.position());
                        addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
                                ICMP6_PREFIX_OPTION_TYPE, lifetime);
+76 −11
Original line number Diff line number Diff line
@@ -1056,10 +1056,14 @@ public class ApfTest {
    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;

    private static final int ICMP6_RA_HEADER_LEN = 16;
    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6;
    private static final int ICMP6_RA_CHECKSUM_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2;
    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6;
    private static final int ICMP6_RA_REACHABLE_TIME_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8;
    private static final int ICMP6_RA_RETRANSMISSION_TIMER_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + 12;
    private static final int ICMP6_RA_OPTION_OFFSET =
            IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;

@@ -2000,6 +2004,25 @@ public class ApfTest {
        ipClientCallback.assertNoProgramUpdate();
    }

    private ByteBuffer makeBaseRaPacket() {
        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
        final int ROUTER_LIFETIME = 1000;
        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
        // IPv6, traffic class = 0, flow label = 0x12345
        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;

        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
        basePacket.put(ICMP6_TYPE_OFFSET, (byte) ICMP6_ROUTER_ADVERTISEMENT);
        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short) ROUTER_LIFETIME);
        basePacket.position(IPV6_DEST_ADDR_OFFSET);
        basePacket.put(IPV6_ALL_NODES_ADDRESS);

        return basePacket;
    }

    @Test
    public void testApfFilterRa() throws Exception {
        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
@@ -2021,15 +2044,7 @@ public class ApfTest {
        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;

        // Verify RA is passed the first time
        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
        basePacket.position(IPV6_DEST_ADDR_OFFSET);
        basePacket.put(IPV6_ALL_NODES_ADDRESS);
        ByteBuffer basePacket = makeBaseRaPacket();
        assertPass(program, basePacket.array());

        verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
@@ -2083,6 +2098,16 @@ public class ApfTest {
        verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));

        // Check that RIOs differing only in the first 4 bytes are different.
        ByteBuffer similarRouteInfoOptionPacket = ByteBuffer.wrap(
                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
        basePacket.clear();
        similarRouteInfoOptionPacket.put(basePacket);
        addRioOption(similarRouteInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/64");
        // Packet should be passed because it is different.
        program = ipClientCallback.getApfProgram();
        assertPass(program, similarRouteInfoOptionPacket.array());

        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
        basePacket.clear();
@@ -2111,6 +2136,46 @@ public class ApfTest {
        apfFilter.shutdown();
    }

    @Test
    public void testRaWithDifferentReachableTimeAndRetransTimer() throws Exception {
        final MockIpClientCallback ipClientCallback = new MockIpClientCallback();
        final ApfConfiguration config = getDefaultConfig();
        config.multicastFilter = DROP_MULTICAST;
        config.ieee802_3Filter = DROP_802_3_FRAMES;
        final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
        byte[] program = ipClientCallback.getApfProgram();
        final int RA_REACHABLE_TIME = 1800;
        final int RA_RETRANSMISSION_TIMER = 1234;

        // Create an Ra packet without options
        // Reachable time = 1800, retransmission timer = 1234
        ByteBuffer raPacket = makeBaseRaPacket();
        raPacket.position(ICMP6_RA_REACHABLE_TIME_OFFSET);
        raPacket.putInt(RA_REACHABLE_TIME);
        raPacket.putInt(RA_RETRANSMISSION_TIMER);
        // First RA passes filter
        assertPass(program, raPacket.array());

        // Assume apf is shown the given RA, it generates program to filter it.
        ipClientCallback.resetApfProgramWait();
        apfFilter.pretendPacketReceived(raPacket.array());
        program = ipClientCallback.getApfProgram();
        assertDrop(program, raPacket.array());

        // A packet with different reachable time should be passed.
        // Reachable time = 2300, retransmission timer = 1234
        raPacket.clear();
        raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME + 500);
        assertPass(program, raPacket.array());

        // A packet with different retransmission timer should be passed.
        // Reachable time = 1800, retransmission timer = 2234
        raPacket.clear();
        raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME);
        raPacket.putInt(ICMP6_RA_RETRANSMISSION_TIMER_OFFSET, RA_RETRANSMISSION_TIMER + 1000);
        assertPass(program, raPacket.array());
    }

    /**
     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
     * copy that resource into the app's data directory and return the path to it.