Merge "Fix RAs with different retansmission timer would be dropped by apf"
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java
index 33f69f4..75a737d 100644
--- a/src/android/net/apf/ApfFilter.java
+++ b/src/android/net/apf/ApfFilter.java
@@ -514,9 +514,9 @@
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 @@
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 @@
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);
diff --git a/tests/unit/src/android/net/apf/ApfTest.java b/tests/unit/src/android/net/apf/ApfTest.java
index 24c67d7..ab92892 100644
--- a/tests/unit/src/android/net/apf/ApfTest.java
+++ b/tests/unit/src/android/net/apf/ApfTest.java
@@ -1056,10 +1056,14 @@
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 @@
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 @@
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 @@
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 @@
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.