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

Commit 0d9b9422 authored by Aaron Huang's avatar Aaron Huang Committed by Gerrit Code Review
Browse files

Merge "Add an APF unit test to drop all packets in the pcap file"

parents f53c3981 785e5f1f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ public class ApfFilter {
     * the last writable 32bit word.
     */
    @VisibleForTesting
    private static enum Counter {
    public static enum Counter {
        RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
        TOTAL_PACKETS,
        PASSED_ARP,
+41 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.support.test.runner.AndroidJUnit4;
import android.system.ErrnoException;
import android.system.Os;
import android.text.format.DateUtils;
import android.util.Log;
import com.android.frameworks.tests.net.R;
import com.android.internal.util.HexDump;
import java.io.File;
@@ -89,6 +90,7 @@ public class ApfTest {
        System.loadLibrary("frameworksnettestsjni");
    }

    private static final String TAG = "ApfTest";
    // Expected return codes from APF interpreter.
    private static final int PASS = 1;
    private static final int DROP = 0;
@@ -869,6 +871,37 @@ public class ApfTest {
        }
    }

    /**
     * Generate APF program, run pcap file though APF filter, then check all the packets in the file
     * should be dropped.
     */
    @Test
    public void testApfFilterPcapFile() throws Exception {
        final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
        String pcapFilename = stageFile(R.raw.apfPcap);
        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
        LinkProperties lp = new LinkProperties();
        lp.addLinkAddress(link);

        ApfConfiguration config = getDefaultConfig();
        ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
        config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
        config.multicastFilter = DROP_MULTICAST;
        config.ieee802_3Filter = DROP_802_3_FRAMES;
        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
        apfFilter.setLinkProperties(lp);
        byte[] program = ipClientCallback.getApfProgram();
        byte[] data = new byte[ApfFilter.Counter.totalSize()];
        final boolean result;

        result = dropsAllPackets(program, data, pcapFilename);
        Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));

        assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
            HexDump.toHexString(data, false), result);
    }

    private class MockIpClientCallback extends IpClient.Callback {
        private final ConditionVariable mGotApfProgram = new ConditionVariable();
        private byte[] mLastApfProgram;
@@ -1706,6 +1739,14 @@ public class ApfTest {
    private native static boolean compareBpfApf(String filter, String pcap_filename,
            byte[] apf_program);


    /**
     * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
     * checks whether all the packets are dropped and populates data[] {@code data} with
     * the APF counters.
     */
    private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);

    @Test
    public void testBroadcastAddress() throws Exception {
        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
+74 −27
Original line number Diff line number Diff line
@@ -21,37 +21,40 @@
#include <stdlib.h>
#include <string>
#include <utils/Log.h>
#include <vector>

#include "apf_interpreter.h"
#include "nativehelper/scoped_primitive_array.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

// JNI function acting as simply call-through to native APF interpreter.
static jint com_android_server_ApfTest_apfSimulate(
        JNIEnv* env, jclass, jbyteArray program, jbyteArray packet,
        jbyteArray data, jint filter_age) {
    uint8_t* program_raw = (uint8_t*)env->GetByteArrayElements(program, nullptr);
    uint8_t* packet_raw = (uint8_t*)env->GetByteArrayElements(packet, nullptr);
    uint8_t* data_raw = (uint8_t*)(data ? env->GetByteArrayElements(data, nullptr) : nullptr);
    uint32_t program_len = env->GetArrayLength(program);
    uint32_t packet_len = env->GetArrayLength(packet);
    uint32_t data_len = data ? env->GetArrayLength(data) : 0;
        JNIEnv* env, jclass, jbyteArray jprogram, jbyteArray jpacket,
        jbyteArray jdata, jint filter_age) {

    ScopedByteArrayRO packet(env, jpacket);
    uint32_t packet_len = (uint32_t)packet.size();
    uint32_t program_len = env->GetArrayLength(jprogram);
    uint32_t data_len = jdata ? env->GetArrayLength(jdata) : 0;
    std::vector<uint8_t> buf(program_len + data_len, 0);

    env->GetByteArrayRegion(jprogram, 0, program_len, reinterpret_cast<jbyte*>(buf.data()));
    if (jdata) {
        // Merge program and data into a single buffer.
    uint8_t* program_and_data = (uint8_t*)malloc(program_len + data_len);
    memcpy(program_and_data, program_raw, program_len);
    memcpy(program_and_data + program_len, data_raw, data_len);
        env->GetByteArrayRegion(jdata, 0, data_len,
                                reinterpret_cast<jbyte*>(buf.data() + program_len));
    }

    jint result =
        accept_packet(program_and_data, program_len, program_len + data_len,
                      packet_raw, packet_len, filter_age);
    if (data) {
        memcpy(data_raw, program_and_data + program_len, data_len);
        env->ReleaseByteArrayElements(data, (jbyte*)data_raw, 0 /* copy back */);
    }
    free(program_and_data);
    env->ReleaseByteArrayElements(packet, (jbyte*)packet_raw, JNI_ABORT);
    env->ReleaseByteArrayElements(program, (jbyte*)program_raw, JNI_ABORT);
        accept_packet(buf.data(), program_len, program_len + data_len,
                        reinterpret_cast<const uint8_t*>(packet.get()), packet_len, filter_age);

    if (jdata) {
        env->SetByteArrayRegion(jdata, 0, data_len,
                                reinterpret_cast<jbyte*>(buf.data() + program_len));
    }

    return result;
}

@@ -118,8 +121,7 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
        jstring jpcap_filename, jbyteArray japf_program) {
    ScopedUtfChars filter(env, jfilter);
    ScopedUtfChars pcap_filename(env, jpcap_filename);
    uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL);
    uint32_t apf_program_len = env->GetArrayLength(japf_program);
    ScopedByteArrayRO apf_program(env, japf_program);

    // Open pcap file for BPF filtering
    ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb"));
@@ -161,7 +163,8 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
        do {
            apf_packet = pcap_next(apf_pcap.get(), &apf_header);
        } while (apf_packet != NULL && !accept_packet(
                apf_program, apf_program_len, 0 /* data_len */,
                reinterpret_cast<uint8_t*>(const_cast<int8_t*>(apf_program.get())),
                apf_program.size(), 0 /* data_len */,
                apf_packet, apf_header.len, 0 /* filter_age */));

        // Make sure both filters matched the same packet.
@@ -178,6 +181,48 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
    return true;
}

static jboolean com_android_server_ApfTest_dropsAllPackets(JNIEnv* env, jclass, jbyteArray jprogram,
        jbyteArray jdata, jstring jpcap_filename) {
    ScopedUtfChars pcap_filename(env, jpcap_filename);
    ScopedByteArrayRO apf_program(env, jprogram);
    uint32_t apf_program_len = (uint32_t)apf_program.size();
    uint32_t data_len = env->GetArrayLength(jdata);
    pcap_pkthdr apf_header;
    const uint8_t* apf_packet;
    char pcap_error[PCAP_ERRBUF_SIZE];
    std::vector<uint8_t> buf(apf_program_len + data_len, 0);

    // Merge program and data into a single buffer.
    env->GetByteArrayRegion(jprogram, 0, apf_program_len, reinterpret_cast<jbyte*>(buf.data()));
    env->GetByteArrayRegion(jdata, 0, data_len,
                            reinterpret_cast<jbyte*>(buf.data() + apf_program_len));

    // Open pcap file
    ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
    ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));

    if (apf_pcap.get() == NULL) {
        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
        return false;
    }

    while ((apf_packet = pcap_next(apf_pcap.get(), &apf_header)) != NULL) {
        int result = accept_packet(buf.data(), apf_program_len,
                                    apf_program_len + data_len, apf_packet, apf_header.len, 0);

        // Return false once packet passes the filter
        if (result) {
            env->SetByteArrayRegion(jdata, 0, data_len,
                                    reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
            return false;
         }
    }

    env->SetByteArrayRegion(jdata, 0, data_len,
                            reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
    return true;
}

extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -192,6 +237,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
                    (void*)com_android_server_ApfTest_compileToBpf },
            { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z",
                    (void*)com_android_server_ApfTest_compareBpfApf },
            { "dropsAllPackets", "([B[BLjava/lang/String;)Z",
                    (void*)com_android_server_ApfTest_dropsAllPackets },
    };

    jniRegisterNativeMethods(env, "android/net/apf/ApfTest",
+99.2 KiB

File added.

No diff preview for this file type.