Loading core/java/android/net/metrics/RaEvent.java +59 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import android.os.Parcelable; @SystemApi public final class RaEvent implements Parcelable { /** {@hide} */ public static final long NO_LIFETIME = -1L; // Lifetime in seconds of options found in a single RA packet. // When an option is not set, the value of the associated field is -1; public final long routerLifetime; Loading Loading @@ -92,4 +95,60 @@ public final class RaEvent implements Parcelable { return new RaEvent[size]; } }; /** {@hide} */ public static class Builder { long routerLifetime = NO_LIFETIME; long prefixValidLifetime = NO_LIFETIME; long prefixPreferredLifetime = NO_LIFETIME; long routeInfoLifetime = NO_LIFETIME; long rdnssLifetime = NO_LIFETIME; long dnsslLifetime = NO_LIFETIME; public Builder() { } public RaEvent build() { return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime, routeInfoLifetime, rdnssLifetime, dnsslLifetime); } public Builder updateRouterLifetime(long lifetime) { routerLifetime = updateLifetime(routerLifetime, lifetime); return this; } public Builder updatePrefixValidLifetime(long lifetime) { prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime); return this; } public Builder updatePrefixPreferredLifetime(long lifetime) { prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime); return this; } public Builder updateRouteInfoLifetime(long lifetime) { routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime); return this; } public Builder updateRdnssLifetime(long lifetime) { rdnssLifetime = updateLifetime(rdnssLifetime, lifetime); return this; } public Builder updateDnsslLifetime(long lifetime) { dnsslLifetime = updateLifetime(dnsslLifetime, lifetime); return this; } private long updateLifetime(long currentLifetime, long newLifetime) { if (currentLifetime == RaEvent.NO_LIFETIME) { return newLifetime; } return Math.min(currentLifetime, newLifetime); } } } services/net/java/android/net/apf/ApfFilter.java +32 −28 Original line number Diff line number Diff line Loading @@ -213,7 +213,7 @@ public class ApfFilter { private final ApfCapabilities mApfCapabilities; private final IpManager.Callback mIpManagerCallback; private final NetworkInterface mNetworkInterface; private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final IpConnectivityLog mMetricsLog; @VisibleForTesting byte[] mHardwareAddress; @VisibleForTesting Loading @@ -228,11 +228,12 @@ public class ApfFilter { @VisibleForTesting ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, boolean multicastFilter) { IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) { mApfCapabilities = apfCapabilities; mIpManagerCallback = ipManagerCallback; mNetworkInterface = networkInterface; mMulticastFilter = multicastFilter; mMetricsLog = log; maybeStartFilter(); } Loading Loading @@ -371,6 +372,14 @@ public class ApfFilter { return i & 0xffffffffL; } private long getUint16(ByteBuffer buffer, int position) { return uint16(buffer.getShort(position)); } private long getUint32(ByteBuffer buffer, int position) { return uint32(buffer.getInt(position)); } private void prefixOptionToString(StringBuffer sb, int offset) { String prefix = IPv6AddresstoString(offset + 16); int length = uint8(mPacket.get(offset + 2)); Loading Loading @@ -438,9 +447,9 @@ public class ApfFilter { // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with // specifications. Ra(byte[] packet, int length) { mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length)); mPacket.clear(); mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); mLastSeen = curTime(); RaEvent.Builder builder = new RaEvent.Builder(); // Ignore the checksum. int lastNonLifetimeStart = addNonLifetime(0, Loading @@ -451,14 +460,7 @@ public class ApfFilter { lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_RA_ROUTER_LIFETIME_OFFSET, ICMP6_RA_ROUTER_LIFETIME_LEN); long routerLifetime = uint16(mPacket.getShort( ICMP6_RA_ROUTER_LIFETIME_OFFSET + mPacket.position())); long prefixValidLifetime = -1L; long prefixPreferredLifetime = -1L; long routeInfoLifetime = -1L; long dnsslLifetime = - 1L; long rdnssLifetime = -1L; builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)); // Ensures that the RA is not truncated. mPacket.position(ICMP6_RA_OPTION_OFFSET); Loading @@ -466,39 +468,42 @@ public class ApfFilter { final int position = mPacket.position(); final int optionType = uint8(mPacket.get(position)); final int optionLength = uint8(mPacket.get(position + 1)) * 8; long lifetime; switch (optionType) { case ICMP6_PREFIX_OPTION_TYPE: // Parse valid lifetime lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN); lifetime = getUint32(mPacket, position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); builder.updatePrefixValidLifetime(lifetime); // Parse preferred lifetime lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN); lifetime = getUint32(mPacket, position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET); builder.updatePrefixPreferredLifetime(lifetime); mPrefixOptionOffsets.add(position); prefixValidLifetime = uint32(mPacket.getInt( ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET + position)); prefixPreferredLifetime = uint32(mPacket.getInt( ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET + position)); break; // These three options have the same lifetime offset and size, and // are processed with the same specialized addNonLifetime4B: // are processed with the same specialized addNonLifetimeU32: case ICMP6_RDNSS_OPTION_TYPE: mRdnssOptionOffsets.add(position); lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); rdnssLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateRdnssLifetime(lifetime); break; case ICMP6_ROUTE_INFO_OPTION_TYPE: lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); routeInfoLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateRouteInfoLifetime(lifetime); break; case ICMP6_DNSSL_OPTION_TYPE: lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); dnsslLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateDnsslLifetime(lifetime); break; default: // RFC4861 section 4.2 dictates we ignore unknown options for fowards Loading @@ -514,9 +519,7 @@ public class ApfFilter { // Mark non-lifetime bytes since last lifetime. addNonLifetime(lastNonLifetimeStart, 0, 0); mMinLifetime = minLifetime(packet, length); // TODO: record per-option minimum lifetimes instead of last seen lifetimes mMetricsLog.log(new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime, routeInfoLifetime, rdnssLifetime, dnsslLifetime)); mMetricsLog.log(builder.build()); } // Ignoring lifetimes (which may change) does {@code packet} match this RA? Loading Loading @@ -1000,7 +1003,8 @@ public class ApfFilter { Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); return null; } return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter); return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter, new IpConnectivityLog()); } public synchronized void shutdown() { Loading services/tests/servicestests/src/android/net/apf/ApfTest.java +59 −9 Original line number Diff line number Diff line Loading @@ -26,14 +26,23 @@ import android.net.apf.ApfGenerator; import android.net.apf.ApfGenerator.IllegalInstructionException; import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; import android.net.LinkAddress; import android.net.LinkProperties; import android.os.ConditionVariable; import android.os.Parcelable; import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; Loading @@ -43,6 +52,7 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; import libcore.io.IoUtils; import libcore.io.Streams; Loading @@ -56,9 +66,12 @@ import libcore.io.Streams; public class ApfTest extends AndroidTestCase { private static final int TIMEOUT_MS = 500; @Mock IpConnectivityLog mLog; @Override public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); // Load up native shared library containing APF interpreter exposed via JNI. System.loadLibrary("servicestestsjni"); } Loading @@ -70,6 +83,9 @@ public class ApfTest extends AndroidTestCase { // least the minimum packet size. private final static int MIN_PKT_SIZE = 15; private final static boolean DROP_MULTICAST = true; private final static boolean ALLOW_MULTICAST = false; private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { assertEquals(expected, apfSimulate(program, packet, filterAge)); } Loading Loading @@ -562,10 +578,10 @@ public class ApfTest extends AndroidTestCase { public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6}; private FileDescriptor mWriteSocket; public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter) throws Exception { public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) throws Exception { super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"), ipManagerCallback, multicastFilter); ipManagerCallback, multicastFilter, log); } // Pretend an RA packet has been received and show it to ApfFilter. Loading Loading @@ -667,7 +683,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify empty packet of 100 zero bytes is passed Loading Loading @@ -699,7 +715,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterIPv6() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify empty IPv6 packet is passed Loading @@ -726,7 +742,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterMulticast() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Construct IPv4 and IPv6 multicast packets. Loading Loading @@ -772,7 +788,7 @@ public class ApfTest extends AndroidTestCase { // Verify it can be initialized to on ipManagerCallback.resetApfProgramWait(); apfFilter.shutdown(); apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); program = ipManagerCallback.getApfProgram(); assertDrop(program, bcastv4packet.array(), 0); assertDrop(program, mcastv4packet.array(), 0); Loading Loading @@ -804,7 +820,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterArp() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify initially ARP filter is off Loading Loading @@ -867,6 +883,35 @@ public class ApfTest extends AndroidTestCase { verifyRaLifetime(ipManagerCallback, packet, lifetime); } private void verifyRaEvent(RaEvent expected) { ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class); verify(mLog, atLeastOnce()).log(captor.capture()); RaEvent got = lastRaEvent(captor.getAllValues()); if (!raEventEquals(expected, got)) { assertEquals(expected, got); // fail for printing an assertion error message. } } private RaEvent lastRaEvent(List<Parcelable> events) { RaEvent got = null; for (Parcelable ev : events) { if (ev instanceof RaEvent) { got = (RaEvent) ev; } } return got; } private boolean raEventEquals(RaEvent ev1, RaEvent ev2) { return (ev1 != null) && (ev2 != null) && (ev1.routerLifetime == ev2.routerLifetime) && (ev1.prefixValidLifetime == ev2.prefixValidLifetime) && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime) && (ev1.routeInfoLifetime == ev2.routeInfoLifetime) && (ev1.rdnssLifetime == ev2.rdnssLifetime) && (ev1.dnsslLifetime == ev2.dnsslLifetime); } private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, ByteBuffer packet) throws IOException, ErrnoException { ipManagerCallback.resetApfProgramWait(); Loading @@ -877,7 +922,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify RA is passed the first time Loading @@ -891,6 +936,7 @@ public class ApfTest extends AndroidTestCase { assertPass(program, basePacket.array(), 0); testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1)); // Ensure zero-length options cause the packet to be silently skipped. // Do this before we test other packets. http://b/29586253 Loading @@ -916,6 +962,7 @@ public class ApfTest extends AndroidTestCase { prefixOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200); testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100); verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1)); ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -926,6 +973,7 @@ public class ApfTest extends AndroidTestCase { rdnssOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300); testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300); verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1)); ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -936,6 +984,7 @@ public class ApfTest extends AndroidTestCase { routeInfoOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400); testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400); verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1)); ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -948,6 +997,7 @@ public class ApfTest extends AndroidTestCase { // Note that lifetime of 2000 will be ignored in favor of shorter // route lifetime of 1000. testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000); verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000)); // Verify that current program filters all five RAs: verifyRaLifetime(ipManagerCallback, basePacket, 1000); Loading Loading
core/java/android/net/metrics/RaEvent.java +59 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ import android.os.Parcelable; @SystemApi public final class RaEvent implements Parcelable { /** {@hide} */ public static final long NO_LIFETIME = -1L; // Lifetime in seconds of options found in a single RA packet. // When an option is not set, the value of the associated field is -1; public final long routerLifetime; Loading Loading @@ -92,4 +95,60 @@ public final class RaEvent implements Parcelable { return new RaEvent[size]; } }; /** {@hide} */ public static class Builder { long routerLifetime = NO_LIFETIME; long prefixValidLifetime = NO_LIFETIME; long prefixPreferredLifetime = NO_LIFETIME; long routeInfoLifetime = NO_LIFETIME; long rdnssLifetime = NO_LIFETIME; long dnsslLifetime = NO_LIFETIME; public Builder() { } public RaEvent build() { return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime, routeInfoLifetime, rdnssLifetime, dnsslLifetime); } public Builder updateRouterLifetime(long lifetime) { routerLifetime = updateLifetime(routerLifetime, lifetime); return this; } public Builder updatePrefixValidLifetime(long lifetime) { prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime); return this; } public Builder updatePrefixPreferredLifetime(long lifetime) { prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime); return this; } public Builder updateRouteInfoLifetime(long lifetime) { routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime); return this; } public Builder updateRdnssLifetime(long lifetime) { rdnssLifetime = updateLifetime(rdnssLifetime, lifetime); return this; } public Builder updateDnsslLifetime(long lifetime) { dnsslLifetime = updateLifetime(dnsslLifetime, lifetime); return this; } private long updateLifetime(long currentLifetime, long newLifetime) { if (currentLifetime == RaEvent.NO_LIFETIME) { return newLifetime; } return Math.min(currentLifetime, newLifetime); } } }
services/net/java/android/net/apf/ApfFilter.java +32 −28 Original line number Diff line number Diff line Loading @@ -213,7 +213,7 @@ public class ApfFilter { private final ApfCapabilities mApfCapabilities; private final IpManager.Callback mIpManagerCallback; private final NetworkInterface mNetworkInterface; private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final IpConnectivityLog mMetricsLog; @VisibleForTesting byte[] mHardwareAddress; @VisibleForTesting Loading @@ -228,11 +228,12 @@ public class ApfFilter { @VisibleForTesting ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, boolean multicastFilter) { IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) { mApfCapabilities = apfCapabilities; mIpManagerCallback = ipManagerCallback; mNetworkInterface = networkInterface; mMulticastFilter = multicastFilter; mMetricsLog = log; maybeStartFilter(); } Loading Loading @@ -371,6 +372,14 @@ public class ApfFilter { return i & 0xffffffffL; } private long getUint16(ByteBuffer buffer, int position) { return uint16(buffer.getShort(position)); } private long getUint32(ByteBuffer buffer, int position) { return uint32(buffer.getInt(position)); } private void prefixOptionToString(StringBuffer sb, int offset) { String prefix = IPv6AddresstoString(offset + 16); int length = uint8(mPacket.get(offset + 2)); Loading Loading @@ -438,9 +447,9 @@ public class ApfFilter { // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with // specifications. Ra(byte[] packet, int length) { mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length)); mPacket.clear(); mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); mLastSeen = curTime(); RaEvent.Builder builder = new RaEvent.Builder(); // Ignore the checksum. int lastNonLifetimeStart = addNonLifetime(0, Loading @@ -451,14 +460,7 @@ public class ApfFilter { lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_RA_ROUTER_LIFETIME_OFFSET, ICMP6_RA_ROUTER_LIFETIME_LEN); long routerLifetime = uint16(mPacket.getShort( ICMP6_RA_ROUTER_LIFETIME_OFFSET + mPacket.position())); long prefixValidLifetime = -1L; long prefixPreferredLifetime = -1L; long routeInfoLifetime = -1L; long dnsslLifetime = - 1L; long rdnssLifetime = -1L; builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)); // Ensures that the RA is not truncated. mPacket.position(ICMP6_RA_OPTION_OFFSET); Loading @@ -466,39 +468,42 @@ public class ApfFilter { final int position = mPacket.position(); final int optionType = uint8(mPacket.get(position)); final int optionLength = uint8(mPacket.get(position + 1)) * 8; long lifetime; switch (optionType) { case ICMP6_PREFIX_OPTION_TYPE: // Parse valid lifetime lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN); lifetime = getUint32(mPacket, position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); builder.updatePrefixValidLifetime(lifetime); // Parse preferred lifetime lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN); lifetime = getUint32(mPacket, position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET); builder.updatePrefixPreferredLifetime(lifetime); mPrefixOptionOffsets.add(position); prefixValidLifetime = uint32(mPacket.getInt( ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET + position)); prefixPreferredLifetime = uint32(mPacket.getInt( ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET + position)); break; // These three options have the same lifetime offset and size, and // are processed with the same specialized addNonLifetime4B: // are processed with the same specialized addNonLifetimeU32: case ICMP6_RDNSS_OPTION_TYPE: mRdnssOptionOffsets.add(position); lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); rdnssLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateRdnssLifetime(lifetime); break; case ICMP6_ROUTE_INFO_OPTION_TYPE: lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); routeInfoLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateRouteInfoLifetime(lifetime); break; case ICMP6_DNSSL_OPTION_TYPE: lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); dnsslLifetime = uint32(mPacket.getInt(ICMP6_4_BYTE_LIFETIME_OFFSET + position)); lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); builder.updateDnsslLifetime(lifetime); break; default: // RFC4861 section 4.2 dictates we ignore unknown options for fowards Loading @@ -514,9 +519,7 @@ public class ApfFilter { // Mark non-lifetime bytes since last lifetime. addNonLifetime(lastNonLifetimeStart, 0, 0); mMinLifetime = minLifetime(packet, length); // TODO: record per-option minimum lifetimes instead of last seen lifetimes mMetricsLog.log(new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime, routeInfoLifetime, rdnssLifetime, dnsslLifetime)); mMetricsLog.log(builder.build()); } // Ignoring lifetimes (which may change) does {@code packet} match this RA? Loading Loading @@ -1000,7 +1003,8 @@ public class ApfFilter { Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); return null; } return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter); return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, multicastFilter, new IpConnectivityLog()); } public synchronized void shutdown() { Loading
services/tests/servicestests/src/android/net/apf/ApfTest.java +59 −9 Original line number Diff line number Diff line Loading @@ -26,14 +26,23 @@ import android.net.apf.ApfGenerator; import android.net.apf.ApfGenerator.IllegalInstructionException; import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; import android.net.LinkAddress; import android.net.LinkProperties; import android.os.ConditionVariable; import android.os.Parcelable; import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; Loading @@ -43,6 +52,7 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; import libcore.io.IoUtils; import libcore.io.Streams; Loading @@ -56,9 +66,12 @@ import libcore.io.Streams; public class ApfTest extends AndroidTestCase { private static final int TIMEOUT_MS = 500; @Mock IpConnectivityLog mLog; @Override public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); // Load up native shared library containing APF interpreter exposed via JNI. System.loadLibrary("servicestestsjni"); } Loading @@ -70,6 +83,9 @@ public class ApfTest extends AndroidTestCase { // least the minimum packet size. private final static int MIN_PKT_SIZE = 15; private final static boolean DROP_MULTICAST = true; private final static boolean ALLOW_MULTICAST = false; private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { assertEquals(expected, apfSimulate(program, packet, filterAge)); } Loading Loading @@ -562,10 +578,10 @@ public class ApfTest extends AndroidTestCase { public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6}; private FileDescriptor mWriteSocket; public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter) throws Exception { public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) throws Exception { super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"), ipManagerCallback, multicastFilter); ipManagerCallback, multicastFilter, log); } // Pretend an RA packet has been received and show it to ApfFilter. Loading Loading @@ -667,7 +683,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify empty packet of 100 zero bytes is passed Loading Loading @@ -699,7 +715,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterIPv6() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify empty IPv6 packet is passed Loading @@ -726,7 +742,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterMulticast() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Construct IPv4 and IPv6 multicast packets. Loading Loading @@ -772,7 +788,7 @@ public class ApfTest extends AndroidTestCase { // Verify it can be initialized to on ipManagerCallback.resetApfProgramWait(); apfFilter.shutdown(); apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); program = ipManagerCallback.getApfProgram(); assertDrop(program, bcastv4packet.array(), 0); assertDrop(program, mcastv4packet.array(), 0); Loading Loading @@ -804,7 +820,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterArp() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify initially ARP filter is off Loading Loading @@ -867,6 +883,35 @@ public class ApfTest extends AndroidTestCase { verifyRaLifetime(ipManagerCallback, packet, lifetime); } private void verifyRaEvent(RaEvent expected) { ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class); verify(mLog, atLeastOnce()).log(captor.capture()); RaEvent got = lastRaEvent(captor.getAllValues()); if (!raEventEquals(expected, got)) { assertEquals(expected, got); // fail for printing an assertion error message. } } private RaEvent lastRaEvent(List<Parcelable> events) { RaEvent got = null; for (Parcelable ev : events) { if (ev instanceof RaEvent) { got = (RaEvent) ev; } } return got; } private boolean raEventEquals(RaEvent ev1, RaEvent ev2) { return (ev1 != null) && (ev2 != null) && (ev1.routerLifetime == ev2.routerLifetime) && (ev1.prefixValidLifetime == ev2.prefixValidLifetime) && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime) && (ev1.routeInfoLifetime == ev2.routeInfoLifetime) && (ev1.rdnssLifetime == ev2.rdnssLifetime) && (ev1.dnsslLifetime == ev2.dnsslLifetime); } private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, ByteBuffer packet) throws IOException, ErrnoException { ipManagerCallback.resetApfProgramWait(); Loading @@ -877,7 +922,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); byte[] program = ipManagerCallback.getApfProgram(); // Verify RA is passed the first time Loading @@ -891,6 +936,7 @@ public class ApfTest extends AndroidTestCase { assertPass(program, basePacket.array(), 0); testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1)); // Ensure zero-length options cause the packet to be silently skipped. // Do this before we test other packets. http://b/29586253 Loading @@ -916,6 +962,7 @@ public class ApfTest extends AndroidTestCase { prefixOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200); testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100); verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1)); ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -926,6 +973,7 @@ public class ApfTest extends AndroidTestCase { rdnssOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300); testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300); verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1)); ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -936,6 +984,7 @@ public class ApfTest extends AndroidTestCase { routeInfoOptionPacket.putInt( ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400); testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400); verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1)); ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); Loading @@ -948,6 +997,7 @@ public class ApfTest extends AndroidTestCase { // Note that lifetime of 2000 will be ignored in favor of shorter // route lifetime of 1000. testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000); verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000)); // Verify that current program filters all five RAs: verifyRaLifetime(ipManagerCallback, basePacket, 1000); Loading