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

Commit d17da130 authored by Hugo Benichi's avatar Hugo Benichi Committed by android-build-merger
Browse files

Better IPv4 multicast coverage in ApfTest am: 961ca49f am: 70611640

am: 8f6463cc

Change-Id: I56025dd51b3926906dbc76f8681d3dbf2152e18a
parents 82711d59 8f6463cc
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -171,8 +171,8 @@ public class ApfFilter {
    private static final int ETH_HEADER_LEN = 14;
    private static final int ETH_DEST_ADDR_OFFSET = 0;
    private static final int ETH_ETHERTYPE_OFFSET = 12;
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
    // Endianness is not an issue for this constant because the APF interpreter always operates in
@@ -188,7 +188,7 @@ public class ApfFilter {
    private static final int IPV6_HEADER_LEN = 40;
    // The IPv6 all nodes address ff02::1
    private static final byte[] IPV6_ALL_NODES_ADDRESS =
            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };

    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
@@ -206,7 +206,7 @@ public class ApfFilter {
    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
    private static final short ARP_OPCODE_REQUEST = 1;
    private static final short ARP_OPCODE_REPLY = 2;
    private static final byte[] ARP_IPV4_HEADER = new byte[]{
    private static final byte[] ARP_IPV4_HEADER = {
            0, 1, // Hardware type: Ethernet (1)
            8, 0, // Protocol type: IP (0x0800)
            6,    // Hardware size: 6
+146 −83
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ import libcore.io.Streams;
 * Tests for APF program generator and interpreter.
 *
 * Build, install and run with:
 *  runtest frameworks-services -c com.android.server.ApfTest
 *  runtest frameworks-services -c android.net.apf.ApfTest
 */
public class ApfTest extends AndroidTestCase {
    private static final int TIMEOUT_MS = 500;
@@ -86,21 +86,45 @@ public class ApfTest extends AndroidTestCase {
    private final static boolean DROP_MULTICAST = true;
    private final static boolean ALLOW_MULTICAST = false;

    private static String label(int code) {
        switch (code) {
            case PASS: return "PASS";
            case DROP: return "DROP";
            default:   return "UNKNOWN";
        }
    }

    private static void assertReturnCodesEqual(int expected, int got) {
        assertEquals(label(expected), label(got));
    }

    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
        assertEquals(expected, apfSimulate(program, packet, filterAge));
        assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge));
    }

    private void assertVerdict(int expected, byte[] program, byte[] packet) {
        assertReturnCodesEqual(expected, apfSimulate(program, packet, 0));
    }

    private void assertPass(byte[] program, byte[] packet, int filterAge) {
        assertVerdict(PASS, program, packet, filterAge);
    }

    private void assertPass(byte[] program, byte[] packet) {
        assertVerdict(PASS, program, packet);
    }

    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
        assertVerdict(DROP, program, packet, filterAge);
    }

    private void assertDrop(byte[] program, byte[] packet) {
        assertVerdict(DROP, program, packet);
    }

    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
            throws IllegalInstructionException {
        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
    }

    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
@@ -516,7 +540,7 @@ public class ApfTest extends AndroidTestCase {
        gen = new ApfGenerator();
        gen.addLoadImmediate(Register.R0, 1);
        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
        assertPass(gen, packet123, 0);
        gen = new ApfGenerator();
        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
@@ -524,7 +548,7 @@ public class ApfTest extends AndroidTestCase {
        gen = new ApfGenerator();
        gen.addLoadImmediate(Register.R0, 1);
        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
        assertDrop(gen, packet12345, 0);
        gen = new ApfGenerator();
        gen.addLoadImmediate(Register.R0, 1);
@@ -575,7 +599,7 @@ public class ApfTest extends AndroidTestCase {
    }

    private static class TestApfFilter extends ApfFilter {
        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
        public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
        private FileDescriptor mWriteSocket;

        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
@@ -620,19 +644,21 @@ public class ApfTest extends AndroidTestCase {
    private static final int ETH_HEADER_LEN = 14;
    private static final int ETH_DEST_ADDR_OFFSET = 0;
    private static final int ETH_ETHERTYPE_OFFSET = 12;
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };

    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    private static final byte[] IPV4_BROADCAST_ADDRESS =
            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};

    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
    private static final int IPV6_HEADER_LEN = 40;
    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
    // The IPv6 all nodes address ff02::1
    private static final byte[] IPV6_ALL_NODES_ADDRESS =
            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };

    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
@@ -670,14 +696,14 @@ public class ApfTest extends AndroidTestCase {
    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;

    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
            0, 1, // Hardware type: Ethernet (1)
            8, 0, // Protocol type: IP (0x0800)
            6,    // Hardware size: 6
            4,    // Protocol size: 4
            0, 1  // Opcode: request (1)
    };
    private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
    private static final byte[] ARP_IPV4_REPLY_HEADER = {
            0, 1, // Hardware type: Ethernet (1)
            8, 0, // Protocol type: IP (0x0800)
            6,    // Hardware size: 6
@@ -686,9 +712,11 @@ public class ApfTest extends AndroidTestCase {
    };
    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;

    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
    private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
    private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, (byte) 255, (byte) 255};
    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};

    @LargeTest
    public void testApfFilterIPv4() throws Exception {
@@ -698,26 +726,43 @@ public class ApfTest extends AndroidTestCase {

        // Verify empty packet of 100 zero bytes is passed
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        assertPass(program, packet.array(), 0);
        assertPass(program, packet.array());

        // Verify unicast IPv4 packet is passed
        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        assertPass(program, packet.array(), 0);

        // Verify broadcast IPv4, not DHCP to us, is dropped
        packet.put(ETH_BROADCAST_MAC_ADDRESS);
        assertDrop(program, packet.array(), 0);
        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
        assertPass(program, packet.array());

        // Verify L2 unicast to IPv4 broadcast addresses is passed (b/30231088)
        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
        assertPass(program, packet.array());
        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
        assertPass(program, packet.array());

        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
        assertDrop(program, packet.array());
        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
        assertDrop(program, packet.array());
        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
        assertDrop(program, packet.array());
        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
        assertDrop(program, packet.array());

        // Verify broadcast IPv4 DHCP to us is passed
        packet.position(DHCP_CLIENT_MAC_OFFSET);
        packet.put(TestApfFilter.MOCK_MAC_ADDR);
        assertPass(program, packet.array(), 0);
        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
        assertPass(program, packet.array());

        // Verify unicast IPv4 DHCP to us is passed
        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
        assertPass(program, packet.array());

        apfFilter.shutdown();
    }
@@ -731,20 +776,19 @@ public class ApfTest extends AndroidTestCase {
        // Verify empty IPv6 packet is passed
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
        assertPass(program, packet.array(), 0);
        assertPass(program, packet.array());

        // Verify empty ICMPv6 packet is passed
        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
        assertPass(program, packet.array(), 0);
        assertPass(program, packet.array());

        // Verify empty ICMPv6 NA packet is passed
        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
        assertPass(program, packet.array(), 0);
        assertPass(program, packet.array());

        // Verify ICMPv6 NA to ff02::1 is dropped
        packet.position(IPV6_DEST_ADDR_OFFSET);
        packet.put(IPV6_ALL_NODES_ADDRESS);
        assertDrop(program, packet.array(), 0);
        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
        assertDrop(program, packet.array());

        apfFilter.shutdown();
    }
@@ -755,58 +799,78 @@ public class ApfTest extends AndroidTestCase {
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
        byte[] program = ipManagerCallback.getApfProgram();

        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
        final byte[] broadcastIpv4Addr = {(byte)192,0,(byte)255,(byte)255};
        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};

        // Construct IPv4 and IPv6 multicast packets.
        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);

        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);

        // Construct IPv4 broadcast packet.
        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);

        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);

        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);

        // Verify initially disabled multicast filter is off
        assertPass(program, bcastv4packet.array(), 0);
        assertPass(program, mcastv4packet.array(), 0);
        assertPass(program, mcastv6packet.array(), 0);
        assertPass(program, mcastv4packet.array());
        assertPass(program, mcastv6packet.array());
        assertPass(program, bcastv4packet1.array());
        assertPass(program, bcastv4packet2.array());
        assertPass(program, bcastv4unicastl2packet.array());

        // Turn on multicast filter and verify it works
        ipManagerCallback.resetApfProgramWait();
        apfFilter.setMulticastFilter(true);
        program = ipManagerCallback.getApfProgram();
        assertDrop(program, bcastv4packet.array(), 0);
        assertDrop(program, mcastv4packet.array(), 0);
        assertDrop(program, mcastv6packet.array(), 0);
        assertDrop(program, mcastv4packet.array());
        assertDrop(program, mcastv6packet.array());
        assertDrop(program, bcastv4packet1.array());
        assertDrop(program, bcastv4packet2.array());
        assertPass(program, bcastv4unicastl2packet.array());

        // Turn off multicast filter and verify it's off
        ipManagerCallback.resetApfProgramWait();
        apfFilter.setMulticastFilter(false);
        program = ipManagerCallback.getApfProgram();
        assertPass(program, bcastv4packet.array(), 0);
        assertPass(program, mcastv4packet.array(), 0);
        assertPass(program, mcastv6packet.array(), 0);
        assertPass(program, mcastv4packet.array());
        assertPass(program, mcastv6packet.array());
        assertPass(program, bcastv4packet1.array());
        assertPass(program, bcastv4packet2.array());
        assertPass(program, bcastv4unicastl2packet.array());

        // Verify it can be initialized to on
        ipManagerCallback.resetApfProgramWait();
        apfFilter.shutdown();
        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
        program = ipManagerCallback.getApfProgram();
        assertDrop(program, bcastv4packet.array(), 0);
        assertDrop(program, mcastv4packet.array(), 0);
        assertDrop(program, mcastv6packet.array(), 0);
        assertDrop(program, mcastv4packet.array());
        assertDrop(program, mcastv6packet.array());
        assertDrop(program, bcastv4packet1.array());
        assertPass(program, bcastv4unicastl2packet.array());

        // Verify that ICMPv6 multicast is not dropped.
        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
        assertPass(program, mcastv6packet.array(), 0);
        assertPass(program, mcastv6packet.array());

        apfFilter.shutdown();
    }
@@ -819,17 +883,17 @@ public class ApfTest extends AndroidTestCase {

    private void verifyArpFilter(byte[] program, int filterResult) {
        // Verify ARP request packet
        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));

        // Verify unicast ARP reply packet is always accepted.
        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));

        // Verify GARP reply packets are always filtered
        assertDrop(program, garpReply(), 0);
        assertDrop(program, garpReply());
    }

    @LargeTest
@@ -855,34 +919,26 @@ public class ApfTest extends AndroidTestCase {
    private static byte[] arpRequestBroadcast(byte[] tip) {
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
        packet.position(ETH_DEST_ADDR_OFFSET);
        packet.put(ETH_BROADCAST_MAC_ADDRESS);
        packet.position(ARP_HEADER_OFFSET);
        packet.put(ARP_IPV4_REQUEST_HEADER);
        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
        packet.put(tip);
        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
        return packet.array();
    }

    private static byte[] arpReplyUnicast(byte[] tip) {
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
        packet.position(ARP_HEADER_OFFSET);
        packet.put(ARP_IPV4_REPLY_HEADER);
        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
        packet.put(tip);
        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
        return packet.array();
    }

    private static byte[] garpReply() {
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
        packet.position(ETH_DEST_ADDR_OFFSET);
        packet.put(ETH_BROADCAST_MAC_ADDRESS);
        packet.position(ARP_HEADER_OFFSET);
        packet.put(ARP_IPV4_REPLY_HEADER);
        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
        packet.put(IPV4_ANY_HOST_ADDR);
        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
        return packet.array();
    }

@@ -893,22 +949,22 @@ public class ApfTest extends AndroidTestCase {
        byte[] program = ipManagerCallback.getApfProgram();

        // Verify new program should drop RA for 1/6th its lifetime
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
        assertDrop(program, packet.array(), lifetime/6);
        assertPass(program, packet.array(), lifetime/6 + 1);
        assertPass(program, packet.array(), lifetime);

        // Verify RA checksum is ignored
        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());

        // Verify other changes to RA make it not match filter
        packet.put(0, (byte)-1);
        assertPass(program, packet.array(), 0);
        assertPass(program, packet.array());
        packet.put(0, (byte)0);
        assertDrop(program, packet.array(), 0);
        assertDrop(program, packet.array());
    }

    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -973,7 +1029,7 @@ public class ApfTest extends AndroidTestCase {
        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
        basePacket.position(IPV6_DEST_ADDR_OFFSET);
        basePacket.put(IPV6_ALL_NODES_ADDRESS);
        assertPass(program, basePacket.array(), 0);
        assertPass(program, basePacket.array());

        testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
@@ -1069,6 +1125,13 @@ public class ApfTest extends AndroidTestCase {
        return file.getAbsolutePath();
    }

    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
        final int original = buffer.position();
        buffer.position(position);
        buffer.put(bytes);
        buffer.position(original);
    }

    /**
     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
     * filter was installed {@code filter_age} seconds ago.