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

Commit 8537c58c authored by Ahmed ElArabawy's avatar Ahmed ElArabawy Committed by Hugo Benichi
Browse files

Add Configuration to APF Policy



in b/37702435 battery was drained due to reception of
Ethernet frames with Eth-type < 0x600 (non ehternet II frames)

This change adds an XML file to drop/allow these frames
Dropping helps tp avoid acquiring a wakelock for the
reception of these packets, while allowing them may be needed
for some protocols
The Change allow the OEM to override the system settings

Bug: 37702435
Test: runtest frameworks-net
Merged-In: Idb6c215896ef230a8136ff4ecefc90ccdc5c1c6d
Merged-In: I16346bb98a0b9259f7c3f51e318c472cfc1bb492

Signed-off-by: default avatarAhmed ElArabawy <arabawy@google.com>

(cherry pick from commit 4dd7c58f)

Change-Id: Ie466baf1e6395d6c28245e41179232ea8e523845
parent 2627d485
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -288,6 +288,11 @@
    <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
    <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
    <integer name="config_networkWakeupPacketMask">0</integer>
    <integer name="config_networkWakeupPacketMask">0</integer>


    <!-- Whether the APF Filter in the device should filter out IEEE 802.3 Frames
         Those frames are identified by the field Eth-type having values
         less than 0x600 -->
    <bool translatable="false" name="config_apfDrop802_3Frames">true</bool>

    <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
    <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
         device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
         device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
         This is the default value of that setting. -->
         This is the default value of that setting. -->
+1 −0
Original line number Original line Diff line number Diff line
@@ -1790,6 +1790,7 @@
  <java-symbol type="integer" name="config_networkAvoidBadWifi" />
  <java-symbol type="integer" name="config_networkAvoidBadWifi" />
  <java-symbol type="integer" name="config_networkWakeupPacketMark" />
  <java-symbol type="integer" name="config_networkWakeupPacketMark" />
  <java-symbol type="integer" name="config_networkWakeupPacketMask" />
  <java-symbol type="integer" name="config_networkWakeupPacketMask" />
  <java-symbol type="bool" name="config_apfDrop802_3Frames" />
  <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
  <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
  <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
  <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
  <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
  <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
+18 −4
Original line number Original line Diff line number Diff line
@@ -181,6 +181,7 @@ public class ApfFilter {
    private static final int ETH_HEADER_LEN = 14;
    private static final int ETH_HEADER_LEN = 14;
    private static final int ETH_DEST_ADDR_OFFSET = 0;
    private static final int ETH_DEST_ADDR_OFFSET = 0;
    private static final int ETH_ETHERTYPE_OFFSET = 12;
    private static final int ETH_ETHERTYPE_OFFSET = 12;
    private static final int ETH_TYPE_MIN = 0x0600;
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
            {(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.
    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
@@ -236,6 +237,7 @@ public class ApfFilter {
    private final IpManager.Callback mIpManagerCallback;
    private final IpManager.Callback mIpManagerCallback;
    private final NetworkInterface mNetworkInterface;
    private final NetworkInterface mNetworkInterface;
    private final IpConnectivityLog mMetricsLog;
    private final IpConnectivityLog mMetricsLog;

    @VisibleForTesting
    @VisibleForTesting
    byte[] mHardwareAddress;
    byte[] mHardwareAddress;
    @VisibleForTesting
    @VisibleForTesting
@@ -244,6 +246,7 @@ public class ApfFilter {
    private long mUniqueCounter;
    private long mUniqueCounter;
    @GuardedBy("this")
    @GuardedBy("this")
    private boolean mMulticastFilter;
    private boolean mMulticastFilter;
    private final boolean mDrop802_3Frames;
    // Our IPv4 address, if we have just one, otherwise null.
    // Our IPv4 address, if we have just one, otherwise null.
    @GuardedBy("this")
    @GuardedBy("this")
    private byte[] mIPv4Address;
    private byte[] mIPv4Address;
@@ -253,11 +256,13 @@ public class ApfFilter {


    @VisibleForTesting
    @VisibleForTesting
    ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
    ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
            IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) {
            IpManager.Callback ipManagerCallback, boolean multicastFilter,
            boolean ieee802_3Filter, IpConnectivityLog log) {
        mApfCapabilities = apfCapabilities;
        mApfCapabilities = apfCapabilities;
        mIpManagerCallback = ipManagerCallback;
        mIpManagerCallback = ipManagerCallback;
        mNetworkInterface = networkInterface;
        mNetworkInterface = networkInterface;
        mMulticastFilter = multicastFilter;
        mMulticastFilter = multicastFilter;
        mDrop802_3Frames = ieee802_3Filter;
        mMetricsLog = log;
        mMetricsLog = log;


        maybeStartFilter();
        maybeStartFilter();
@@ -879,6 +884,7 @@ public class ApfFilter {
    /**
    /**
     * Begin generating an APF program to:
     * Begin generating an APF program to:
     * <ul>
     * <ul>
     * <li>Drop/Pass 802.3 frames (based on policy)
     * <li>Drop ARP requests not for us, if mIPv4Address is set,
     * <li>Drop ARP requests not for us, if mIPv4Address is set,
     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
@@ -900,6 +906,8 @@ public class ApfFilter {


        // Here's a basic summary of what the initial program does:
        // Here's a basic summary of what the initial program does:
        //
        //
        // if it's a 802.3 Frame (ethtype < 0x0600):
        //    drop or pass based on configurations
        // if it's ARP:
        // if it's ARP:
        //   insert ARP filter to drop or pass these appropriately
        //   insert ARP filter to drop or pass these appropriately
        // if it's IPv4:
        // if it's IPv4:
@@ -910,9 +918,15 @@ public class ApfFilter {
        //   pass
        //   pass
        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets


        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);

        if (mDrop802_3Frames) {
            // drop 802.3 frames (ethtype < 0x0600)
            gen.addJumpIfR0LessThan(ETH_TYPE_MIN, gen.DROP_LABEL);
        }

        // Add ARP filters:
        // Add ARP filters:
        String skipArpFiltersLabel = "skipArpFilters";
        String skipArpFiltersLabel = "skipArpFilters";
        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
        generateArpFilterLocked(gen);
        generateArpFilterLocked(gen);
        gen.defineLabel(skipArpFiltersLabel);
        gen.defineLabel(skipArpFiltersLabel);
@@ -1077,7 +1091,7 @@ public class ApfFilter {
     */
     */
    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
            boolean multicastFilter) {
            boolean multicastFilter, boolean ieee802_3Filter) {
        if (apfCapabilities == null || networkInterface == null) return null;
        if (apfCapabilities == null || networkInterface == null) return null;
        if (apfCapabilities.apfVersionSupported == 0) return null;
        if (apfCapabilities.apfVersionSupported == 0) return null;
        if (apfCapabilities.maximumApfProgramSize < 512) {
        if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -1094,7 +1108,7 @@ public class ApfFilter {
            return null;
            return null;
        }
        }
        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
                multicastFilter, new IpConnectivityLog());
                multicastFilter, ieee802_3Filter, new IpConnectivityLog());
    }
    }


    public synchronized void shutdown() {
    public synchronized void shutdown() {
+6 −1
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IState;
import com.android.internal.util.IState;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
@@ -1418,8 +1419,12 @@ public class IpManager extends StateMachine {


        @Override
        @Override
        public void enter() {
        public void enter() {
            // Get the Configuration for ApfFilter from Context
            boolean filter802_3Frames =
                    mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);

            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                    mCallback, mMulticastFiltering);
                    mCallback, mMulticastFiltering, filter802_3Frames);
            // TODO: investigate the effects of any multicast filtering racing/interfering with the
            // TODO: investigate the effects of any multicast filtering racing/interfering with the
            // rest of this IP configuration startup.
            // rest of this IP configuration startup.
            if (mApfFilter == null) {
            if (mApfFilter == null) {
+71 −10
Original line number Original line Diff line number Diff line
@@ -92,6 +92,9 @@ public class ApfTest extends AndroidTestCase {
    private final static boolean DROP_MULTICAST = true;
    private final static boolean DROP_MULTICAST = true;
    private final static boolean ALLOW_MULTICAST = false;
    private final static boolean ALLOW_MULTICAST = false;


    private final static boolean DROP_802_3_FRAMES = true;
    private final static boolean ALLOW_802_3_FRAMES = false;

    private static String label(int code) {
    private static String label(int code) {
        switch (code) {
        switch (code) {
            case PASS: return "PASS";
            case PASS: return "PASS";
@@ -611,9 +614,9 @@ public class ApfTest extends AndroidTestCase {
        private final long mFixedTimeMs = SystemClock.elapsedRealtime();
        private final long mFixedTimeMs = SystemClock.elapsedRealtime();


        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
                IpConnectivityLog log) throws Exception {
                boolean ieee802_3Filter, IpConnectivityLog log) throws Exception {
            super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
            super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
                    ipManagerCallback, multicastFilter, log);
                    ipManagerCallback, multicastFilter, ieee802_3Filter, log);
        }
        }


        // Pretend an RA packet has been received and show it to ApfFilter.
        // Pretend an RA packet has been received and show it to ApfFilter.
@@ -742,7 +745,8 @@ public class ApfTest extends AndroidTestCase {
        LinkProperties lp = new LinkProperties();
        LinkProperties lp = new LinkProperties();
        lp.addLinkAddress(link);
        lp.addLinkAddress(link);


        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
                ALLOW_802_3_FRAMES, mLog);
        apfFilter.setLinkProperties(lp);
        apfFilter.setLinkProperties(lp);


        byte[] program = ipManagerCallback.getApfProgram();
        byte[] program = ipManagerCallback.getApfProgram();
@@ -793,7 +797,8 @@ public class ApfTest extends AndroidTestCase {
    @SmallTest
    @SmallTest
    public void testApfFilterIPv6() throws Exception {
    public void testApfFilterIPv6() throws Exception {
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
                ALLOW_802_3_FRAMES, mLog);
        byte[] program = ipManagerCallback.getApfProgram();
        byte[] program = ipManagerCallback.getApfProgram();


        // Verify empty IPv6 packet is passed
        // Verify empty IPv6 packet is passed
@@ -834,7 +839,8 @@ public class ApfTest extends AndroidTestCase {
        LinkProperties lp = new LinkProperties();
        LinkProperties lp = new LinkProperties();
        lp.addLinkAddress(link);
        lp.addLinkAddress(link);


        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        apfFilter.setLinkProperties(lp);
        apfFilter.setLinkProperties(lp);


        byte[] program = ipManagerCallback.getApfProgram();
        byte[] program = ipManagerCallback.getApfProgram();
@@ -896,7 +902,8 @@ public class ApfTest extends AndroidTestCase {
        // Verify it can be initialized to on
        // Verify it can be initialized to on
        ipManagerCallback.resetApfProgramWait();
        ipManagerCallback.resetApfProgramWait();
        apfFilter.shutdown();
        apfFilter.shutdown();
        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        apfFilter.setLinkProperties(lp);
        apfFilter.setLinkProperties(lp);
        program = ipManagerCallback.getApfProgram();
        program = ipManagerCallback.getApfProgram();
        assertDrop(program, mcastv4packet.array());
        assertDrop(program, mcastv4packet.array());
@@ -911,6 +918,56 @@ public class ApfTest extends AndroidTestCase {
        apfFilter.shutdown();
        apfFilter.shutdown();
    }
    }


    @SmallTest
    public void testApfFilter802_3() throws Exception {
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
        LinkProperties lp = new LinkProperties();
        lp.addLinkAddress(link);

        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
                ALLOW_802_3_FRAMES, mLog);
        apfFilter.setLinkProperties(lp);

        byte[] program = ipManagerCallback.getApfProgram();

        // Verify empty packet of 100 zero bytes is passed
        // Note that eth-type = 0 makes it an IEEE802.3 frame
        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
        assertPass(program, packet.array());

        // Verify empty packet with IPv4 is passed
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        assertPass(program, packet.array());

        // Verify empty IPv6 packet is passed
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
        assertPass(program, packet.array());

        // Now turn on the filter
        ipManagerCallback.resetApfProgramWait();
        apfFilter.shutdown();
        apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        apfFilter.setLinkProperties(lp);
        program = ipManagerCallback.getApfProgram();

        // Verify that IEEE802.3 frame is dropped
        // In this case ethtype is used for payload length
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
        assertDrop(program, packet.array());

        // Verify that IPv4 (as example of Ethernet II) frame will pass
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
        assertPass(program, packet.array());

        // Verify that IPv6 (as example of Ethernet II) frame will pass
        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
        assertPass(program, packet.array());

        apfFilter.shutdown();
    }

    private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
    private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
        cb.resetApfProgramWait();
        cb.resetApfProgramWait();
        filter.setLinkProperties(lp);
        filter.setLinkProperties(lp);
@@ -935,7 +992,8 @@ public class ApfTest extends AndroidTestCase {
    @SmallTest
    @SmallTest
    public void testApfFilterArp() throws Exception {
    public void testApfFilterArp() throws Exception {
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
                DROP_802_3_FRAMES, mLog);


        // Verify initially ARP request filter is off, and GARP filter is on.
        // Verify initially ARP request filter is off, and GARP filter is on.
        verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
        verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1056,7 +1114,8 @@ public class ApfTest extends AndroidTestCase {
    @SmallTest
    @SmallTest
    public void testApfFilterRa() throws Exception {
    public void testApfFilterRa() throws Exception {
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        byte[] program = ipManagerCallback.getApfProgram();
        byte[] program = ipManagerCallback.getApfProgram();


        final int ROUTER_LIFETIME = 1000;
        final int ROUTER_LIFETIME = 1000;
@@ -1198,7 +1257,8 @@ public class ApfTest extends AndroidTestCase {
        final int maxRandomPacketSize = 512;
        final int maxRandomPacketSize = 512;
        final Random r = new Random();
        final Random r = new Random();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        for (int i = 0; i < 1000; i++) {
        for (int i = 0; i < 1000; i++) {
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            r.nextBytes(packet);
            r.nextBytes(packet);
@@ -1216,7 +1276,8 @@ public class ApfTest extends AndroidTestCase {
        final int maxRandomPacketSize = 512;
        final int maxRandomPacketSize = 512;
        final Random r = new Random();
        final Random r = new Random();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
                DROP_802_3_FRAMES, mLog);
        for (int i = 0; i < 1000; i++) {
        for (int i = 0; i < 1000; i++) {
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            r.nextBytes(packet);
            r.nextBytes(packet);