• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.apf;
18 
19 import static android.net.apf.ApfCounterTracker.Counter.getCounterEnumFromOffset;
20 import static android.net.apf.ApfTestHelpers.TIMEOUT_MS;
21 import static android.net.apf.ApfTestHelpers.DROP;
22 import static android.net.apf.ApfTestHelpers.MIN_PKT_SIZE;
23 import static android.net.apf.ApfTestHelpers.PASS;
24 import static android.net.apf.ApfTestHelpers.assertProgramEquals;
25 import static android.net.apf.BaseApfGenerator.APF_VERSION_3;
26 import static android.net.apf.BaseApfGenerator.APF_VERSION_4;
27 import static android.net.apf.BaseApfGenerator.APF_VERSION_6;
28 import static android.net.apf.BaseApfGenerator.DROP_LABEL;
29 import static android.net.apf.BaseApfGenerator.MemorySlot;
30 import static android.net.apf.BaseApfGenerator.PASS_LABEL;
31 import static android.net.apf.BaseApfGenerator.Register.R0;
32 import static android.net.apf.BaseApfGenerator.Register.R1;
33 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
34 import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
35 import static android.system.OsConstants.AF_UNIX;
36 import static android.system.OsConstants.ETH_P_ARP;
37 import static android.system.OsConstants.ETH_P_IP;
38 import static android.system.OsConstants.ETH_P_IPV6;
39 import static android.system.OsConstants.IPPROTO_ICMPV6;
40 import static android.system.OsConstants.IPPROTO_IPV6;
41 import static android.system.OsConstants.IPPROTO_UDP;
42 import static android.system.OsConstants.SOCK_STREAM;
43 
44 import static com.android.net.module.util.HexDump.hexStringToByteArray;
45 import static com.android.net.module.util.HexDump.toHexString;
46 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
47 
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertTrue;
50 import static org.junit.Assert.fail;
51 import static org.mockito.ArgumentMatchers.anyInt;
52 import static org.mockito.Mockito.any;
53 import static org.mockito.Mockito.clearInvocations;
54 import static org.mockito.Mockito.doAnswer;
55 import static org.mockito.Mockito.doReturn;
56 import static org.mockito.Mockito.never;
57 import static org.mockito.Mockito.reset;
58 import static org.mockito.Mockito.times;
59 import static org.mockito.Mockito.verify;
60 
61 import android.content.BroadcastReceiver;
62 import android.content.Context;
63 import android.content.Intent;
64 import android.net.InetAddresses;
65 import android.net.IpPrefix;
66 import android.net.LinkAddress;
67 import android.net.LinkProperties;
68 import android.net.MacAddress;
69 import android.net.apf.ApfCounterTracker.Counter;
70 import android.net.apf.ApfFilter.ApfConfiguration;
71 import android.net.apf.BaseApfGenerator.IllegalInstructionException;
72 import android.net.metrics.IpConnectivityLog;
73 import android.os.Build;
74 import android.os.Handler;
75 import android.os.HandlerThread;
76 import android.os.PowerManager;
77 import android.os.SystemClock;
78 import android.stats.connectivity.NetworkQuirkEvent;
79 import android.system.ErrnoException;
80 import android.system.Os;
81 import android.text.TextUtils;
82 import android.text.format.DateUtils;
83 import android.util.ArrayMap;
84 import android.util.Log;
85 import android.util.Pair;
86 
87 import androidx.test.InstrumentationRegistry;
88 import androidx.test.filters.SmallTest;
89 
90 import com.android.internal.annotations.GuardedBy;
91 import com.android.internal.util.HexDump;
92 import com.android.modules.utils.build.SdkLevel;
93 import com.android.net.module.util.DnsPacket;
94 import com.android.net.module.util.Inet4AddressUtils;
95 import com.android.net.module.util.InterfaceParams;
96 import com.android.net.module.util.NetworkStackConstants;
97 import com.android.net.module.util.PacketBuilder;
98 import com.android.networkstack.metrics.ApfSessionInfoMetrics;
99 import com.android.networkstack.metrics.IpClientRaInfoMetrics;
100 import com.android.networkstack.metrics.NetworkQuirkMetrics;
101 import com.android.server.networkstack.tests.R;
102 import com.android.testutils.ConcurrentUtils;
103 import com.android.testutils.DevSdkIgnoreRule;
104 import com.android.testutils.DevSdkIgnoreRunner;
105 import com.android.testutils.HandlerUtils;
106 
107 import libcore.io.IoUtils;
108 import libcore.io.Streams;
109 
110 import org.junit.After;
111 import org.junit.Before;
112 import org.junit.Rule;
113 import org.junit.Test;
114 import org.junit.runner.RunWith;
115 import org.junit.runners.Parameterized;
116 import org.mockito.ArgumentCaptor;
117 import org.mockito.Mock;
118 import org.mockito.Mockito;
119 import org.mockito.MockitoAnnotations;
120 
121 import java.io.ByteArrayOutputStream;
122 import java.io.File;
123 import java.io.FileDescriptor;
124 import java.io.FileOutputStream;
125 import java.io.IOException;
126 import java.io.InputStream;
127 import java.io.InterruptedIOException;
128 import java.io.OutputStream;
129 import java.net.Inet4Address;
130 import java.net.Inet6Address;
131 import java.net.InetAddress;
132 import java.nio.ByteBuffer;
133 import java.nio.charset.StandardCharsets;
134 import java.util.ArrayList;
135 import java.util.Arrays;
136 import java.util.HashMap;
137 import java.util.List;
138 import java.util.Map;
139 import java.util.Random;
140 import java.util.concurrent.atomic.AtomicReference;
141 
142 /**
143  * Tests for APF program generator and interpreter.
144  *
145  * The test cases will be executed by both APFv4 and APFv6 interpreter.
146  */
147 @DevSdkIgnoreRunner.MonitorThreadLeak
148 @RunWith(DevSdkIgnoreRunner.class)
149 @SmallTest
150 public class ApfTest {
151     private static final int APF_VERSION_2 = 2;
152     private int mRamSize = 1024;
153     private int mClampSize = 1024;
154 
155     @Rule
156     public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
157     // Indicates which apf interpreter to run.
158     @Parameterized.Parameter()
159     public int mApfVersion;
160 
161     @Parameterized.Parameters
data()162     public static Iterable<? extends Object> data() {
163         return Arrays.asList(4, 6);
164     }
165 
166     @Mock private Context mContext;
167     @Mock
168     private ApfFilter.Dependencies mDependencies;
169     @Mock private PowerManager mPowerManager;
170     @Mock private IpConnectivityLog mIpConnectivityLog;
171     @Mock private NetworkQuirkMetrics mNetworkQuirkMetrics;
172     @Mock private ApfSessionInfoMetrics mApfSessionInfoMetrics;
173     @Mock private IpClientRaInfoMetrics mIpClientRaInfoMetrics;
174     @Mock private ApfFilter.IApfController mApfController;
175     @GuardedBy("mApfFilterCreated")
176     private final ArrayList<ApfFilter> mApfFilterCreated = new ArrayList<>();
177     private FileDescriptor mWriteSocket;
178     private HandlerThread mHandlerThread;
179     private Handler mHandler;
180     private long mCurrentTimeMs;
181     private ApfTestHelpers mApfTestHelpers;
182 
183     @Before
setUp()184     public void setUp() throws Exception {
185         MockitoAnnotations.initMocks(this);
186         doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
187         doReturn(mApfSessionInfoMetrics).when(mDependencies).getApfSessionInfoMetrics();
188         doReturn(mIpClientRaInfoMetrics).when(mDependencies).getIpClientRaInfoMetrics();
189         FileDescriptor readSocket = new FileDescriptor();
190         mWriteSocket = new FileDescriptor();
191         Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
192         doReturn(readSocket).when(mDependencies).createPacketReaderSocket(anyInt());
193         mCurrentTimeMs = SystemClock.elapsedRealtime();
194         doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime();
195         doReturn(true).when(mApfController).installPacketFilter(any(), any());
196         doAnswer((invocation) -> {
197             synchronized (mApfFilterCreated) {
198                 mApfFilterCreated.add(invocation.getArgument(0));
199             }
200             return null;
201         }).when(mDependencies).onApfFilterCreated(any());
202         mHandlerThread = new HandlerThread("ApfTestThread");
203         mHandlerThread.start();
204         mHandler = new Handler(mHandlerThread.getLooper());
205         mApfTestHelpers = new ApfTestHelpers(ApfJniUtils.APF_INTERPRETER_VERSION_V6);
206     }
207 
shutdownApfFilters()208     private void shutdownApfFilters() throws Exception {
209         ConcurrentUtils.quitResources(THREAD_QUIT_MAX_RETRY_COUNT, () -> {
210             synchronized (mApfFilterCreated) {
211                 final ArrayList<ApfFilter> ret =
212                         new ArrayList<>(mApfFilterCreated);
213                 mApfFilterCreated.clear();
214                 return ret;
215             }
216         }, (apf) -> mHandler.post(apf::shutdown));
217         synchronized (mApfFilterCreated) {
218             assertEquals("ApfFilters did not fully shutdown.",
219                     0, mApfFilterCreated.size());
220         }
221     }
222 
223     @After
tearDown()224     public void tearDown() throws Exception {
225         IoUtils.closeQuietly(mWriteSocket);
226         shutdownApfFilters();
227         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
228         // Clear mocks to prevent from stubs holding instances and cause memory leaks.
229         Mockito.framework().clearInlineMocks();
230         mHandlerThread.quitSafely();
231         mHandlerThread.join();
232     }
233 
234     private static final String TAG = "ApfTest";
235     // Expected return codes from APF interpreter.
236 
237     private static final boolean DROP_MULTICAST = true;
238     private static final boolean ALLOW_MULTICAST = false;
239 
240     private static final boolean DROP_802_3_FRAMES = true;
241     private static final boolean ALLOW_802_3_FRAMES = false;
242 
243     private static final int MIN_RDNSS_LIFETIME_SEC = 0;
244     private static final int MIN_METRICS_SESSION_DURATIONS_MS = 300_000;
245 
246     private static final int NO_CALLBACK_TIMEOUT_MS = 500;
247     private static final int THREAD_QUIT_MAX_RETRY_COUNT = 3;
248 
249     // Constants for opcode encoding
250     private static final byte LI_OP   = (byte)(13 << 3);
251     private static final byte LDDW_OP = (byte)(22 << 3);
252     private static final byte STDW_OP = (byte)(23 << 3);
253     private static final byte SIZE0   = (byte)(0 << 1);
254     private static final byte SIZE8   = (byte)(1 << 1);
255     private static final byte SIZE16  = (byte)(2 << 1);
256     private static final byte SIZE32  = (byte)(3 << 1);
257     private static final byte R1_REG = 1;
258 
259     private static final byte[] TEST_MAC_ADDR = {2, 3, 4, 5, 6, 7};
260     private static final int TEST_IFACE_IDX = 1234;
261     private static final InterfaceParams TEST_PARAMS = new InterfaceParams("lo", TEST_IFACE_IDX,
262             MacAddress.fromBytes(TEST_MAC_ADDR), 1500 /* defaultMtu */);
263 
getDefaultConfig()264     private static ApfConfiguration getDefaultConfig() {
265         ApfFilter.ApfConfiguration config = new ApfConfiguration();
266         config.apfVersionSupported = 2;
267         config.apfRamSize = 4096;
268         config.multicastFilter = ALLOW_MULTICAST;
269         config.ieee802_3Filter = ALLOW_802_3_FRAMES;
270         config.ethTypeBlackList = new int[0];
271         config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC;
272         config.minRdnssLifetimeSec = 67;
273         config.minMetricsSessionDurationMs = MIN_METRICS_SESSION_DURATIONS_MS;
274         return config;
275     }
276 
assertPass(ApfV4Generator gen)277     private void assertPass(ApfV4Generator gen) throws ApfV4Generator.IllegalInstructionException {
278         mApfTestHelpers.assertPass(mApfVersion, gen);
279     }
280 
assertDrop(ApfV4Generator gen)281     private void assertDrop(ApfV4Generator gen) throws ApfV4Generator.IllegalInstructionException {
282         mApfTestHelpers.assertDrop(mApfVersion, gen);
283     }
284 
assertPass(byte[] program, byte[] packet)285     private void assertPass(byte[] program, byte[] packet) {
286         mApfTestHelpers.assertPass(mApfVersion, program, packet);
287     }
288 
assertDrop(byte[] program, byte[] packet)289     private void assertDrop(byte[] program, byte[] packet) {
290         mApfTestHelpers.assertDrop(mApfVersion, program, packet);
291     }
292 
assertPass(byte[] program, byte[] packet, int filterAge)293     private void assertPass(byte[] program, byte[] packet, int filterAge) {
294         mApfTestHelpers.assertPass(mApfVersion, program, packet, filterAge);
295     }
296 
assertDrop(byte[] program, byte[] packet, int filterAge)297     private void assertDrop(byte[] program, byte[] packet, int filterAge) {
298         mApfTestHelpers.assertDrop(mApfVersion, program, packet, filterAge);
299     }
300 
assertPass(ApfV4Generator gen, byte[] packet, int filterAge)301     private void assertPass(ApfV4Generator gen, byte[] packet, int filterAge)
302             throws ApfV4Generator.IllegalInstructionException {
303         mApfTestHelpers.assertPass(mApfVersion, gen, packet, filterAge);
304     }
305 
assertDrop(ApfV4Generator gen, byte[] packet, int filterAge)306     private void assertDrop(ApfV4Generator gen, byte[] packet, int filterAge)
307             throws ApfV4Generator.IllegalInstructionException {
308         mApfTestHelpers.assertDrop(mApfVersion, gen, packet, filterAge);
309     }
310 
assertDataMemoryContents(int expected, byte[] program, byte[] packet, byte[] data, byte[] expectedData)311     private void assertDataMemoryContents(int expected, byte[] program, byte[] packet,
312             byte[] data, byte[] expectedData) throws Exception {
313         mApfTestHelpers.assertDataMemoryContents(mApfVersion, expected, program, packet, data,
314                 expectedData, false /* ignoreInterpreterVersion */);
315     }
316 
assertDataMemoryContentsIgnoreVersion(int expected, byte[] program, byte[] packet, byte[] data, byte[] expectedData)317     private void assertDataMemoryContentsIgnoreVersion(int expected, byte[] program,
318             byte[] packet, byte[] data, byte[] expectedData) throws Exception {
319         mApfTestHelpers.assertDataMemoryContents(mApfVersion, expected, program, packet, data,
320                 expectedData, true /* ignoreInterpreterVersion */);
321     }
322 
assertVerdict(String msg, int expected, byte[] program, byte[] packet, int filterAge)323     private void assertVerdict(String msg, int expected, byte[] program,
324             byte[] packet, int filterAge) {
325         mApfTestHelpers.assertVerdict(mApfVersion, msg, expected, program, packet, filterAge);
326     }
327 
assertVerdict(int expected, byte[] program, byte[] packet)328     private void assertVerdict(int expected, byte[] program, byte[] packet) {
329         mApfTestHelpers.assertVerdict(mApfVersion, expected, program, packet);
330     }
331 
332     /**
333      * Test each instruction by generating a program containing the instruction,
334      * generating bytecode for that program and running it through the
335      * interpreter to verify it functions correctly.
336      */
337     @Test
testApfInstructions()338     public void testApfInstructions() throws IllegalInstructionException {
339         // Empty program should pass because having the program counter reach the
340         // location immediately after the program indicates the packet should be
341         // passed to the AP.
342         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
343         assertPass(gen);
344 
345         // Test pass opcode
346         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
347         gen.addPass();
348         gen.addJump(DROP_LABEL);
349         assertPass(gen);
350 
351         // Test jumping to pass label.
352         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
353         gen.addJump(PASS_LABEL);
354         byte[] program = gen.generate();
355         assertEquals(1, program.length);
356         assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
357         assertPass(program, new byte[MIN_PKT_SIZE], 0);
358 
359         // Test jumping to drop label.
360         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
361         gen.addJump(DROP_LABEL);
362         program = gen.generate();
363         assertEquals(2, program.length);
364         assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
365         assertEquals(1, program[1]);
366         assertDrop(program, new byte[15], 15);
367 
368         // Test jumping if equal to 0.
369         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
370         gen.addJumpIfR0Equals(0, DROP_LABEL);
371         assertDrop(gen);
372 
373         // Test jumping if not equal to 0.
374         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
375         gen.addJumpIfR0NotEquals(0, DROP_LABEL);
376         assertPass(gen);
377         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
378         gen.addLoadImmediate(R0, 1);
379         gen.addJumpIfR0NotEquals(0, DROP_LABEL);
380         assertDrop(gen);
381 
382         // Test jumping if registers equal.
383         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
384         gen.addJumpIfR0EqualsR1(DROP_LABEL);
385         assertDrop(gen);
386 
387         // Test jumping if registers not equal.
388         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
389         gen.addJumpIfR0NotEqualsR1(DROP_LABEL);
390         assertPass(gen);
391         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
392         gen.addLoadImmediate(R0, 1);
393         gen.addJumpIfR0NotEqualsR1(DROP_LABEL);
394         assertDrop(gen);
395 
396         // Test load immediate.
397         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
398         gen.addLoadImmediate(R0, 1234567890);
399         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
400         assertDrop(gen);
401 
402         // Test add.
403         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
404         gen.addAdd(1234567890);
405         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
406         assertDrop(gen);
407 
408         // Test add with a small signed negative value.
409         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
410         gen.addAdd(-1);
411         gen.addJumpIfR0Equals(-1, DROP_LABEL);
412         assertDrop(gen);
413 
414         // Test subtract.
415         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
416         gen.addAdd(-1234567890);
417         gen.addJumpIfR0Equals(-1234567890, DROP_LABEL);
418         assertDrop(gen);
419 
420         // Test or.
421         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
422         gen.addOr(1234567890);
423         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
424         assertDrop(gen);
425 
426         // Test and.
427         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
428         gen.addLoadImmediate(R0, 1234567890);
429         gen.addAnd(123456789);
430         gen.addJumpIfR0Equals(1234567890 & 123456789, DROP_LABEL);
431         assertDrop(gen);
432 
433         // Test left shift.
434         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
435         gen.addLoadImmediate(R0, 1234567890);
436         gen.addLeftShift(1);
437         gen.addJumpIfR0Equals(1234567890 << 1, DROP_LABEL);
438         assertDrop(gen);
439 
440         // Test right shift.
441         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
442         gen.addLoadImmediate(R0, 1234567890);
443         gen.addRightShift(1);
444         gen.addJumpIfR0Equals(1234567890 >> 1, DROP_LABEL);
445         assertDrop(gen);
446 
447         // Test multiply.
448         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
449         gen.addLoadImmediate(R0, 123456789);
450         gen.addMul(2);
451         gen.addJumpIfR0Equals(123456789 * 2, DROP_LABEL);
452         assertDrop(gen);
453 
454         // Test divide.
455         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
456         gen.addLoadImmediate(R0, 1234567890);
457         gen.addDiv(2);
458         gen.addJumpIfR0Equals(1234567890 / 2, DROP_LABEL);
459         assertDrop(gen);
460 
461         // Test divide by zero.
462         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
463         gen.addDiv(0);
464         gen.addJump(DROP_LABEL);
465         assertPass(gen);
466 
467         // Test add.
468         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
469         gen.addLoadImmediate(R1, 1234567890);
470         gen.addAddR1ToR0();
471         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
472         assertDrop(gen);
473 
474         // Test subtract.
475         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
476         gen.addLoadImmediate(R1, -1234567890);
477         gen.addAddR1ToR0();
478         gen.addJumpIfR0Equals(-1234567890, DROP_LABEL);
479         assertDrop(gen);
480 
481         // Test or.
482         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
483         gen.addLoadImmediate(R1, 1234567890);
484         gen.addOrR0WithR1();
485         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
486         assertDrop(gen);
487 
488         // Test and.
489         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
490         gen.addLoadImmediate(R0, 1234567890);
491         gen.addLoadImmediate(R1, 123456789);
492         gen.addAndR0WithR1();
493         gen.addJumpIfR0Equals(1234567890 & 123456789, DROP_LABEL);
494         assertDrop(gen);
495 
496         // Test left shift.
497         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
498         gen.addLoadImmediate(R0, 1234567890);
499         gen.addLoadImmediate(R1, 1);
500         gen.addLeftShiftR0ByR1();
501         gen.addJumpIfR0Equals(1234567890 << 1, DROP_LABEL);
502         assertDrop(gen);
503 
504         // Test right shift.
505         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
506         gen.addLoadImmediate(R0, 1234567890);
507         gen.addLoadImmediate(R1, -1);
508         gen.addLeftShiftR0ByR1();
509         gen.addJumpIfR0Equals(1234567890 >> 1, DROP_LABEL);
510         assertDrop(gen);
511 
512         // Test multiply.
513         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
514         gen.addLoadImmediate(R0, 123456789);
515         gen.addLoadImmediate(R1, 2);
516         gen.addMulR0ByR1();
517         gen.addJumpIfR0Equals(123456789 * 2, DROP_LABEL);
518         assertDrop(gen);
519 
520         // Test divide.
521         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
522         gen.addLoadImmediate(R0, 1234567890);
523         gen.addLoadImmediate(R1, 2);
524         gen.addDivR0ByR1();
525         gen.addJumpIfR0Equals(1234567890 / 2, DROP_LABEL);
526         assertDrop(gen);
527 
528         // Test divide by zero.
529         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
530         gen.addDivR0ByR1();
531         gen.addJump(DROP_LABEL);
532         assertPass(gen);
533 
534         // Test byte load.
535         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
536         gen.addLoad8intoR0(1);
537         gen.addJumpIfR0Equals(45, DROP_LABEL);
538         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
539 
540         // Test out of bounds load.
541         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
542         gen.addLoad8intoR0(16);
543         gen.addJumpIfR0Equals(0, DROP_LABEL);
544         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
545 
546         // Test half-word load.
547         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
548         gen.addLoad16intoR0(1);
549         gen.addJumpIfR0Equals((45 << 8) | 67, DROP_LABEL);
550         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
551 
552         // Test word load.
553         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
554         gen.addLoad32intoR0(1);
555         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, DROP_LABEL);
556         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
557 
558         // Test byte indexed load.
559         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
560         gen.addLoadImmediate(R1, 1);
561         gen.addLoad8R1IndexedIntoR0(0);
562         gen.addJumpIfR0Equals(45, DROP_LABEL);
563         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
564 
565         // Test out of bounds indexed load.
566         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
567         gen.addLoadImmediate(R1, 8);
568         gen.addLoad8R1IndexedIntoR0(8);
569         gen.addJumpIfR0Equals(0, DROP_LABEL);
570         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
571 
572         // Test half-word indexed load.
573         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
574         gen.addLoadImmediate(R1, 1);
575         gen.addLoad16R1IndexedIntoR0(0);
576         gen.addJumpIfR0Equals((45 << 8) | 67, DROP_LABEL);
577         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
578 
579         // Test word indexed load.
580         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
581         gen.addLoadImmediate(R1, 1);
582         gen.addLoad32R1IndexedIntoR0(0);
583         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, DROP_LABEL);
584         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
585 
586         // Test jumping if greater than.
587         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
588         gen.addJumpIfR0GreaterThan(0, DROP_LABEL);
589         assertPass(gen);
590         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
591         gen.addLoadImmediate(R0, 1);
592         gen.addJumpIfR0GreaterThan(0, DROP_LABEL);
593         assertDrop(gen);
594 
595         // Test jumping if less than.
596         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
597         gen.addJumpIfR0LessThan(0, DROP_LABEL);
598         assertPass(gen);
599         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
600         gen.addJumpIfR0LessThan(1, DROP_LABEL);
601         assertDrop(gen);
602 
603         // Test jumping if any bits set.
604         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
605         gen.addJumpIfR0AnyBitsSet(3, DROP_LABEL);
606         assertPass(gen);
607         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
608         gen.addLoadImmediate(R0, 1);
609         gen.addJumpIfR0AnyBitsSet(3, DROP_LABEL);
610         assertDrop(gen);
611         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
612         gen.addLoadImmediate(R0, 3);
613         gen.addJumpIfR0AnyBitsSet(3, DROP_LABEL);
614         assertDrop(gen);
615 
616         // Test jumping if register greater than.
617         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
618         gen.addJumpIfR0GreaterThanR1(DROP_LABEL);
619         assertPass(gen);
620         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
621         gen.addLoadImmediate(R0, 2);
622         gen.addLoadImmediate(R1, 1);
623         gen.addJumpIfR0GreaterThanR1(DROP_LABEL);
624         assertDrop(gen);
625 
626         // Test jumping if register less than.
627         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
628         gen.addJumpIfR0LessThanR1(DROP_LABEL);
629         assertPass(gen);
630         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
631         gen.addLoadImmediate(R1, 1);
632         gen.addJumpIfR0LessThanR1(DROP_LABEL);
633         assertDrop(gen);
634 
635         // Test jumping if any bits set in register.
636         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
637         gen.addLoadImmediate(R1, 3);
638         gen.addJumpIfR0AnyBitsSetR1(DROP_LABEL);
639         assertPass(gen);
640         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
641         gen.addLoadImmediate(R1, 3);
642         gen.addLoadImmediate(R0, 1);
643         gen.addJumpIfR0AnyBitsSetR1(DROP_LABEL);
644         assertDrop(gen);
645         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
646         gen.addLoadImmediate(R1, 3);
647         gen.addLoadImmediate(R0, 3);
648         gen.addJumpIfR0AnyBitsSetR1(DROP_LABEL);
649         assertDrop(gen);
650 
651         // Test load from memory.
652         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
653         gen.addLoadFromMemory(R0, MemorySlot.SLOT_0);
654         gen.addJumpIfR0Equals(0, DROP_LABEL);
655         assertDrop(gen);
656 
657         // Test store to memory.
658         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
659         gen.addLoadImmediate(R1, 1234567890);
660         gen.addStoreToMemory(MemorySlot.RAM_LEN, R1);
661         gen.addLoadFromMemory(R0, MemorySlot.RAM_LEN);
662         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
663         assertDrop(gen);
664 
665         // Test filter age pre-filled memory.
666         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
667         gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
668         gen.addJumpIfR0Equals(123, DROP_LABEL);
669         assertDrop(gen, new byte[MIN_PKT_SIZE], 123);
670 
671         // Test packet size pre-filled memory.
672         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
673         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE);
674         gen.addJumpIfR0Equals(MIN_PKT_SIZE, DROP_LABEL);
675         assertDrop(gen);
676 
677         // Test IPv4 header size pre-filled memory.
678         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
679         gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
680         gen.addJumpIfR0Equals(20, DROP_LABEL);
681         assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,8,0,0x45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
682 
683         // Test not.
684         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
685         gen.addLoadImmediate(R0, 1234567890);
686         gen.addNot(R0);
687         gen.addJumpIfR0Equals(~1234567890, DROP_LABEL);
688         assertDrop(gen);
689 
690         // Test negate.
691         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
692         gen.addLoadImmediate(R0, 1234567890);
693         gen.addNeg(R0);
694         gen.addJumpIfR0Equals(-1234567890, DROP_LABEL);
695         assertDrop(gen);
696 
697         // Test move.
698         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
699         gen.addLoadImmediate(R1, 1234567890);
700         gen.addMove(R0);
701         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
702         assertDrop(gen);
703         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
704         gen.addLoadImmediate(R0, 1234567890);
705         gen.addMove(R1);
706         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
707         assertDrop(gen);
708 
709         // Test swap.
710         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
711         gen.addLoadImmediate(R1, 1234567890);
712         gen.addSwap();
713         gen.addJumpIfR0Equals(1234567890, DROP_LABEL);
714         assertDrop(gen);
715         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
716         gen.addLoadImmediate(R0, 1234567890);
717         gen.addSwap();
718         gen.addJumpIfR0Equals(0, DROP_LABEL);
719         assertDrop(gen);
720 
721         // Test jump if bytes not equal.
722         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
723         gen.addLoadImmediate(R0, 1);
724         gen.addJumpIfBytesAtR0NotEqual(new byte[]{123}, DROP_LABEL);
725         program = gen.generate();
726         assertEquals(6, program.length);
727         assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
728         assertEquals(1, program[1]);
729         assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
730         assertEquals(1, program[3]);
731         assertEquals(1, program[4]);
732         assertEquals(123, program[5]);
733         assertDrop(program, new byte[MIN_PKT_SIZE], 0);
734         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
735         gen.addLoadImmediate(R0, 1);
736         gen.addJumpIfBytesAtR0NotEqual(new byte[]{123}, DROP_LABEL);
737         byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
738         assertPass(gen, packet123, 0);
739         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
740         gen.addJumpIfBytesAtR0NotEqual(new byte[]{123}, DROP_LABEL);
741         assertDrop(gen, packet123, 0);
742         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
743         gen.addLoadImmediate(R0, 1);
744         gen.addJumpIfBytesAtR0NotEqual(new byte[]{1, 2, 30, 4, 5}, DROP_LABEL);
745         byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
746         assertDrop(gen, packet12345, 0);
747         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
748         gen.addLoadImmediate(R0, 1);
749         gen.addJumpIfBytesAtR0NotEqual(new byte[]{1, 2, 3, 4, 5}, DROP_LABEL);
750         assertPass(gen, packet12345, 0);
751     }
752 
753     @Test(expected = ApfV4Generator.IllegalInstructionException.class)
testApfGeneratorWantsV2OrGreater()754     public void testApfGeneratorWantsV2OrGreater() throws Exception {
755         // The minimum supported APF version is 2.
756         new ApfV4Generator(1, mRamSize, mClampSize);
757     }
758 
759     @Test
testApfDataOpcodesWantApfV3()760     public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
761         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
762         try {
763             gen.addStoreData(R0, 0);
764             fail();
765         } catch (IllegalInstructionException expected) {
766             /* pass */
767         }
768         try {
769             gen.addLoadData(R0, 0);
770             fail();
771         } catch (IllegalInstructionException expected) {
772             /* pass */
773         }
774     }
775 
776     /**
777      * Test that the generator emits immediates using the shortest possible encoding.
778      */
779     @Test
testImmediateEncoding()780     public void testImmediateEncoding() throws IllegalInstructionException {
781         ApfV4Generator gen;
782 
783         // 0-byte immediate: li R0, 0
784         gen = new ApfV4Generator(APF_VERSION_4, mRamSize, mClampSize);
785         gen.addLoadImmediate(R0, 0);
786         assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
787 
788         // 1-byte immediate: li R0, 42
789         gen = new ApfV4Generator(APF_VERSION_4, mRamSize, mClampSize);
790         gen.addLoadImmediate(R0, 42);
791         assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
792 
793         // 2-byte immediate: li R1, 0x1234
794         gen = new ApfV4Generator(APF_VERSION_4, mRamSize, mClampSize);
795         gen.addLoadImmediate(R1, 0x1234);
796         assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, 0x12, 0x34}, gen.generate());
797 
798         // 4-byte immediate: li R0, 0x12345678
799         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
800         gen.addLoadImmediate(R0, 0x12345678);
801         assertProgramEquals(
802                 new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
803                 gen.generate());
804     }
805 
806     /**
807      * Test that the generator emits negative immediates using the shortest possible encoding.
808      */
809     @Test
testNegativeImmediateEncoding()810     public void testNegativeImmediateEncoding() throws IllegalInstructionException {
811         ApfV4Generator gen;
812 
813         // 1-byte negative immediate: li R0, -42
814         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
815         gen.addLoadImmediate(R0, -42);
816         assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
817 
818         // 2-byte negative immediate: li R1, -0x1122
819         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
820         gen.addLoadImmediate(R1, -0x1122);
821         assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE},
822                 gen.generate());
823 
824         // 4-byte negative immediate: li R0, -0x11223344
825         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
826         gen.addLoadImmediate(R0, -0x11223344);
827         assertProgramEquals(
828                 new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
829                 gen.generate());
830     }
831 
832     /**
833      * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
834      */
835     @Test
testLoadStoreDataEncoding()836     public void testLoadStoreDataEncoding() throws IllegalInstructionException {
837         ApfV4Generator gen;
838 
839         // Load data with no offset: lddw R0, [0 + r1]
840         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
841         gen.addLoadData(R0, 0);
842         assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
843 
844         // Store data with 8bit negative offset: lddw r0, [-42 + r1]
845         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
846         gen.addStoreData(R0, -42);
847         assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
848 
849         // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
850         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
851         gen.addStoreData(R1, -0x1122);
852         assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE},
853                 gen.generate());
854 
855         // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
856         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
857         gen.addLoadData(R1, 0xDEADBEEF);
858         assertProgramEquals(
859                 new byte[]{LDDW_OP | SIZE32 | R1_REG,
860                         (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
861                 gen.generate());
862     }
863 
864     /**
865      * Test that the interpreter correctly executes STDW with a negative 8bit offset
866      */
867     @Test
testApfDataWrite()868     public void testApfDataWrite() throws IllegalInstructionException, Exception {
869         byte[] packet = new byte[MIN_PKT_SIZE];
870         byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
871         byte[] expected_data = data.clone();
872 
873         // No memory access instructions: should leave the data segment untouched.
874         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
875         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
876 
877         // Expect value 0x87654321 to be stored starting from address -11 from the end of the
878         // data buffer, in big-endian order.
879         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
880         gen.addLoadImmediate(R0, 0x87654321);
881         gen.addLoadImmediate(R1, -5);
882         gen.addStoreData(R0, -6);  // -5 + -6 = -11 (offset +5 with data_len=16)
883         expected_data[5] = (byte)0x87;
884         expected_data[6] = (byte)0x65;
885         expected_data[7] = (byte)0x43;
886         expected_data[8] = (byte)0x21;
887         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
888     }
889 
890     /**
891      * Test that the interpreter correctly executes LDDW with a negative 16bit offset
892      */
893     @Test
testApfDataRead()894     public void testApfDataRead() throws IllegalInstructionException, Exception {
895         // Program that DROPs if address 10 (-6) contains 0x87654321.
896         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
897         gen.addLoadImmediate(R1, 1000);
898         gen.addLoadData(R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
899         gen.addJumpIfR0Equals(0x87654321, DROP_LABEL);
900         byte[] program = gen.generate();
901         byte[] packet = new byte[MIN_PKT_SIZE];
902 
903         // Content is incorrect (last byte does not match) -> PASS
904         byte[] data = new byte[16];
905         data[10] = (byte)0x87;
906         data[11] = (byte)0x65;
907         data[12] = (byte)0x43;
908         data[13] = (byte)0x00;  // != 0x21
909         byte[] expected_data = data.clone();
910         assertDataMemoryContents(PASS, program, packet, data, expected_data);
911 
912         // Fix the last byte -> conditional jump taken -> DROP
913         data[13] = (byte)0x21;
914         expected_data = data;
915         assertDataMemoryContents(DROP, program, packet, data, expected_data);
916     }
917 
918     /**
919      * Test that the interpreter correctly executes LDDW followed by a STDW.
920      * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
921      * offset.
922      */
923     @Test
testApfDataReadModifyWrite()924     public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
925         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
926         gen.addLoadImmediate(R1, -22);
927         gen.addLoadData(R0, 0);  // Load from address 32 -22 + 0 = 10
928         gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
929         gen.addStoreData(R0, 4);  // Write back to address 32 -22 + 4 = 14
930 
931         byte[] packet = new byte[MIN_PKT_SIZE];
932         byte[] data = new byte[32];
933         data[10] = (byte)0x87;
934         data[11] = (byte)0x65;
935         data[12] = (byte)0x43;
936         data[13] = (byte)0x21;
937         byte[] expected_data = data.clone();
938         expected_data[14] = (byte)0xFF;
939         expected_data[15] = (byte)0xAA;
940         expected_data[16] = (byte)0x77;
941         expected_data[17] = (byte)0x33;
942         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
943     }
944 
945     @Test
testApfDataBoundChecking()946     public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
947         byte[] packet = new byte[MIN_PKT_SIZE];
948         byte[] data = new byte[32];
949         byte[] expected_data = data;
950 
951         // Program that DROPs unconditionally. This is our the baseline.
952         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
953         gen.addLoadImmediate(R0, 3);
954         gen.addLoadData(R1, 7);
955         gen.addJump(DROP_LABEL);
956         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
957 
958         // Same program as before, but this time we're trying to load past the end of the data.
959         // 3 instructions, all normal opcodes (LI, LDDW, JMP) with 1 byte immediate = 6 byte program
960         // 32 byte data length, for a total of 38 byte ram len.
961         // APFv6 needs to round this up to be a multiple of 4, so 40.
962         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
963         gen.addLoadImmediate(R0, 20);
964         if (mApfVersion == 4) {
965             gen.addLoadData(R1, 15);  // R0(20)+15+U32[0..3] >= 6 prog + 32 data, so invalid
966         } else {
967             gen.addLoadData(R1, 17);  // R0(20)+17+U32[0..3] >= 6 prog + 2 pad + 32 data, so invalid
968         }
969         gen.addJump(DROP_LABEL);  // Not reached.
970         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
971 
972         // Subtracting an immediate should work...
973         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
974         gen.addLoadImmediate(R0, 20);
975         gen.addLoadData(R1, -4);
976         gen.addJump(DROP_LABEL);
977         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
978 
979         // ...and underflowing simply wraps around to the end of the buffer...
980         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
981         gen.addLoadImmediate(R0, 20);
982         gen.addLoadData(R1, -30);
983         gen.addJump(DROP_LABEL);
984         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
985 
986         // ...but doesn't allow accesses before the start of the buffer
987         gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize);
988         gen.addLoadImmediate(R0, 20);
989         gen.addLoadData(R1, -1000);
990         gen.addJump(DROP_LABEL);  // Not reached.
991         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
992     }
993 
pretendPacketReceived(byte[] packet)994     private void pretendPacketReceived(byte[] packet)
995             throws InterruptedIOException, ErrnoException {
996         Os.write(mWriteSocket, packet, 0, packet.length);
997     }
998 
getApfFilter(ApfFilter.ApfConfiguration config)999     private ApfFilter getApfFilter(ApfFilter.ApfConfiguration config) {
1000         AtomicReference<ApfFilter> apfFilter = new AtomicReference<>();
1001         mHandler.post(() ->
1002                 apfFilter.set(new ApfFilter(mHandler, mContext, config, TEST_PARAMS,
1003                         mApfController, mNetworkQuirkMetrics, mDependencies)));
1004         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
1005         return apfFilter.get();
1006     }
1007 
1008     /**
1009      * Generate APF program, run pcap file though APF filter, then check all the packets in the file
1010      * should be dropped.
1011      */
1012     @Test
testApfFilterPcapFile()1013     public void testApfFilterPcapFile() throws Exception {
1014         final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
1015         String pcapFilename = stageFile(R.raw.apfPcap);
1016         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
1017         LinkProperties lp = new LinkProperties();
1018         lp.addLinkAddress(link);
1019 
1020         ApfConfiguration config = getDefaultConfig();
1021         config.apfVersionSupported = 4;
1022         config.apfRamSize = 1700;
1023         config.multicastFilter = DROP_MULTICAST;
1024         config.ieee802_3Filter = DROP_802_3_FRAMES;
1025         final ApfFilter apfFilter = getApfFilter(config);
1026         mApfTestHelpers.consumeInstalledProgram(mApfController, 2 /* installCnt */);
1027         apfFilter.setLinkProperties(lp);
1028         byte[] program =
1029             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1030         byte[] data = new byte[Counter.totalSize()];
1031         final boolean result;
1032 
1033         result = mApfTestHelpers.dropsAllPackets(
1034             mApfVersion, program, data, pcapFilename);
1035         Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
1036 
1037         assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
1038             HexDump.toHexString(data, false), result);
1039     }
1040 
1041     private static final int ETH_HEADER_LEN               = 14;
1042     private static final int ETH_DEST_ADDR_OFFSET         = 0;
1043     private static final int ETH_ETHERTYPE_OFFSET         = 12;
1044     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
1045             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
1046     private static final byte[] ETH_MULTICAST_MDNS_v4_MAC_ADDRESS =
1047             {(byte) 0x01, (byte) 0x00, (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
1048     private static final byte[] ETH_MULTICAST_MDNS_V6_MAC_ADDRESS =
1049             {(byte) 0x33, (byte) 0x33, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
1050 
1051     private static final int IP_HEADER_OFFSET = ETH_HEADER_LEN;
1052 
1053     private static final int IPV4_HEADER_LEN          = 20;
1054     private static final int IPV4_PROTOCOL_OFFSET     = IP_HEADER_OFFSET + 9;
1055     private static final int IPV4_DEST_ADDR_OFFSET    = IP_HEADER_OFFSET + 16;
1056 
1057     private static final int IPV4_TCP_HEADER_OFFSET        = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
1058 
1059     private static final int IPV4_UDP_HEADER_OFFSET    = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
1060     private static final byte[] IPV4_BROADCAST_ADDRESS =
1061             {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
1062 
1063     private static final int IPV6_HEADER_LEN             = 40;
1064     private static final int IPV6_PAYLOAD_LENGTH_OFFSET  = IP_HEADER_OFFSET + 4;
1065     private static final int IPV6_NEXT_HEADER_OFFSET     = IP_HEADER_OFFSET + 6;
1066     private static final int IPV6_SRC_ADDR_OFFSET        = IP_HEADER_OFFSET + 8;
1067     private static final int IPV6_DEST_ADDR_OFFSET       = IP_HEADER_OFFSET + 24;
1068     private static final int IPV6_PAYLOAD_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
1069     // The IPv6 all nodes address ff02::1
1070     private static final byte[] IPV6_ALL_NODES_ADDRESS   =
1071             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1072     private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
1073             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
1074     private static final byte[] IPV6_SOLICITED_NODE_MULTICAST_ADDRESS = {
1075             (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1076             (byte) 0xff, (byte) 0xab, (byte) 0xcd, (byte) 0xef,
1077     };
1078 
1079     private static final int ICMP6_TYPE_OFFSET           = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
1080     private static final int ICMP6_ROUTER_SOLICITATION   = 133;
1081     private static final int ICMP6_ROUTER_ADVERTISEMENT  = 134;
1082     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
1083 
1084     private static final int ICMP6_RA_HEADER_LEN = 16;
1085     private static final int ICMP6_RA_CHECKSUM_OFFSET =
1086             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2;
1087     private static final int ICMP6_RA_REACHABLE_TIME_OFFSET =
1088             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8;
1089     private static final int ICMP6_RA_OPTION_OFFSET =
1090             IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
1091 
1092     private static final int ICMP6_PREFIX_OPTION_TYPE                      = 3;
1093     private static final int ICMP6_PREFIX_OPTION_LEN                       = 32;
1094 
1095     // From RFC6106: Recursive DNS Server option
1096     private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
1097     // From RFC6106: DNS Search List option
1098     private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
1099 
1100     // From RFC4191: Route Information option
1101     private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
1102     // Above three options all have the same format:
1103     private static final int ICMP6_4_BYTE_OPTION_LEN      = 8;
1104 
1105     private static final int UDP_HEADER_LEN              = 8;
1106     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
1107 
1108     private static final int DHCP_CLIENT_PORT       = 68;
1109     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
1110 
1111     private static final int ARP_HEADER_OFFSET          = ETH_HEADER_LEN;
1112     private static final byte[] ARP_IPV4_REQUEST_HEADER = {
1113             0, 1, // Hardware type: Ethernet (1)
1114             8, 0, // Protocol type: IP (0x0800)
1115             6,    // Hardware size: 6
1116             4,    // Protocol size: 4
1117             0, 1  // Opcode: request (1)
1118     };
1119     private static final byte[] ARP_IPV4_REPLY_HEADER = {
1120             0, 1, // Hardware type: Ethernet (1)
1121             8, 0, // Protocol type: IP (0x0800)
1122             6,    // Hardware size: 6
1123             4,    // Protocol size: 4
1124             0, 2  // Opcode: reply (2)
1125     };
1126     private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
1127     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
1128 
1129     private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
1130     private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
1131     private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
1132     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
1133     private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
1134     private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
1135     private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
1136     private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
1137     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
1138     private static final byte[] IPV4_MDNS_MULTICAST_ADDR = {(byte) 224, 0, 0, (byte) 251};
1139     private static final byte[] IPV6_MDNS_MULTICAST_ADDR =
1140             {(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfb};
1141     private static final int MDNS_UDP_PORT = 5353;
1142 
setIpv4VersionFields(ByteBuffer packet)1143     private static void setIpv4VersionFields(ByteBuffer packet) {
1144         packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
1145         packet.put(IP_HEADER_OFFSET, (byte) 0x45);
1146     }
1147 
setIpv6VersionFields(ByteBuffer packet)1148     private static void setIpv6VersionFields(ByteBuffer packet) {
1149         packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
1150         packet.put(IP_HEADER_OFFSET, (byte) 0x60);
1151     }
1152 
makeIpv4Packet(int proto)1153     private static ByteBuffer makeIpv4Packet(int proto) {
1154         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1155         setIpv4VersionFields(packet);
1156         packet.put(IPV4_PROTOCOL_OFFSET, (byte) proto);
1157         return packet;
1158     }
1159 
makeIpv6Packet(int nextHeader)1160     private static ByteBuffer makeIpv6Packet(int nextHeader) {
1161         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1162         setIpv6VersionFields(packet);
1163         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) nextHeader);
1164         return packet;
1165     }
1166 
1167     @Test
testApfFilterIPv4()1168     public void testApfFilterIPv4() throws Exception {
1169         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
1170         LinkProperties lp = new LinkProperties();
1171         lp.addLinkAddress(link);
1172 
1173         ApfConfiguration config = getDefaultConfig();
1174         config.multicastFilter = DROP_MULTICAST;
1175         final ApfFilter apfFilter = getApfFilter(config);
1176         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1177         apfFilter.setLinkProperties(lp);
1178 
1179         byte[] program =
1180             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1181 
1182         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1183         if (SdkLevel.isAtLeastV()) {
1184             // Verify empty packet of 100 zero bytes is dropped
1185             assertDrop(program, packet.array());
1186         } else {
1187             // Verify empty packet of 100 zero bytes is passed
1188             assertPass(program, packet.array());
1189         }
1190 
1191         // Verify unicast IPv4 packet is passed
1192         put(packet, ETH_DEST_ADDR_OFFSET, TEST_MAC_ADDR);
1193         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1194         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
1195         assertPass(program, packet.array());
1196 
1197         // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
1198         put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1199         assertDrop(program, packet.array());
1200         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
1201         assertDrop(program, packet.array());
1202 
1203         // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
1204         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1205         assertDrop(program, packet.array());
1206         packet.put(IP_HEADER_OFFSET, (byte) 0x45);
1207         assertDrop(program, packet.array());
1208         packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
1209         assertDrop(program, packet.array());
1210         packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
1211         assertDrop(program, packet.array());
1212         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
1213         assertDrop(program, packet.array());
1214         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
1215         assertDrop(program, packet.array());
1216         put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1217         assertDrop(program, packet.array());
1218 
1219         // Verify broadcast IPv4 DHCP to us is passed
1220         put(packet, DHCP_CLIENT_MAC_OFFSET, TEST_MAC_ADDR);
1221         assertPass(program, packet.array());
1222 
1223         // Verify unicast IPv4 DHCP to us is passed
1224         put(packet, ETH_DEST_ADDR_OFFSET, TEST_MAC_ADDR);
1225         assertPass(program, packet.array());
1226     }
1227 
1228     @Test
testApfFilterIPv6()1229     public void testApfFilterIPv6() throws Exception {
1230         ApfConfiguration config = getDefaultConfig();
1231         ApfFilter apfFilter = getApfFilter(config);
1232         byte[] program =
1233             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1234 
1235         // Verify empty IPv6 packet is passed
1236         ByteBuffer packet = makeIpv6Packet(IPPROTO_UDP);
1237         assertPass(program, packet.array());
1238 
1239         // Verify empty ICMPv6 packet is passed
1240         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1241         assertPass(program, packet.array());
1242 
1243         // Verify empty ICMPv6 NA packet is passed
1244         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
1245         assertPass(program, packet.array());
1246 
1247         // Verify ICMPv6 NA to ff02::1 is dropped
1248         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
1249         assertDrop(program, packet.array());
1250 
1251         // Verify ICMPv6 NA to ff02::2 is dropped
1252         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
1253         assertDrop(program, packet.array());
1254 
1255         // Verify ICMPv6 NA to Solicited-Node Multicast is passed
1256         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODE_MULTICAST_ADDRESS);
1257         assertPass(program, packet.array());
1258 
1259         // Verify ICMPv6 RS to any is dropped
1260         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
1261         assertDrop(program, packet.array());
1262         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
1263         assertDrop(program, packet.array());
1264     }
1265 
fillQuestionSection(ByteBuffer buf, String... qnames)1266     private static void fillQuestionSection(ByteBuffer buf, String... qnames) throws IOException {
1267         buf.put(new DnsPacket.DnsHeader(0 /* id */, 0 /* flags */, qnames.length, 0 /* ancount */)
1268                 .getBytes());
1269         for (String qname : qnames) {
1270             buf.put(DnsPacket.DnsRecord.makeQuestion(qname, 0 /* nsType */, 0 /* nsClass */)
1271                     .getBytes());
1272         }
1273     }
1274 
makeMdnsV4Packet(String... qnames)1275     private static byte[] makeMdnsV4Packet(String... qnames) throws IOException {
1276         final ByteBuffer buf = ByteBuffer.wrap(new byte[256]);
1277         final PacketBuilder builder = new PacketBuilder(buf);
1278         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1279                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_v4_MAC_ADDRESS),
1280                 (short) ETH_P_IP);
1281         builder.writeIpv4Header((byte) 0 /* tos */, (short) 0 /* id */,
1282                 (short) 0 /* flagsAndFragmentOffset */, (byte) 0 /* ttl */, (byte) IPPROTO_UDP,
1283                 (Inet4Address) Inet4Address.getByAddress(IPV4_SOURCE_ADDR),
1284                 (Inet4Address) Inet4Address.getByAddress(IPV4_MDNS_MULTICAST_ADDR));
1285         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1286         fillQuestionSection(buf, qnames);
1287         return builder.finalizePacket().array();
1288     }
1289 
makeMdnsV6Packet(String... qnames)1290     private static byte[] makeMdnsV6Packet(String... qnames) throws IOException {
1291         ByteBuffer buf = ByteBuffer.wrap(new byte[256]);
1292         final PacketBuilder builder = new PacketBuilder(buf);
1293         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1294                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS),
1295                 (short) ETH_P_IPV6);
1296         builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */,
1297                 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR),
1298                 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR));
1299         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1300         fillQuestionSection(buf, qnames);
1301         return builder.finalizePacket().array();
1302     }
1303 
putLabel(ByteBuffer buf, String label)1304     private static void putLabel(ByteBuffer buf, String label) {
1305         final byte[] bytes = label.getBytes(StandardCharsets.UTF_8);
1306         buf.put((byte) bytes.length);
1307         buf.put(bytes);
1308     }
1309 
putPointer(ByteBuffer buf, int offset)1310     private static void putPointer(ByteBuffer buf, int offset) {
1311         short pointer = (short) (offset | 0xc000);
1312         buf.putShort(pointer);
1313     }
1314 
1315 
1316     // Simplistic DNS compression code that intentionally does not depend on production code.
getDnsLabels(int startOffset, String... names)1317     private static List<Pair<Integer, String>> getDnsLabels(int startOffset, String... names) {
1318         // Maps all possible name suffixes to packet offsets.
1319         final HashMap<String, Integer> mPointerOffsets = new HashMap<>();
1320         final List<Pair<Integer, String>> out = new ArrayList<>();
1321         int offset = startOffset;
1322         for (int i = 0; i < names.length; i++) {
1323             String name = names[i];
1324             while (true) {
1325                 if (name.length() == 0) {
1326                     out.add(label(""));
1327                     offset += 1 + 4;  // 1-byte label, DNS query
1328                     break;
1329                 }
1330 
1331                 final int pointerOffset = mPointerOffsets.getOrDefault(name, -1);
1332                 if (pointerOffset != -1) {
1333                     out.add(pointer(pointerOffset));
1334                     offset += 2 + 4; // 2-byte pointer, DNS query
1335                     break;
1336                 }
1337 
1338                 mPointerOffsets.put(name, offset);
1339 
1340                 final int indexOfDot = name.indexOf(".");
1341                 final String label;
1342                 if (indexOfDot == -1) {
1343                     label = name;
1344                     name = "";
1345                 } else {
1346                     label = name.substring(0, indexOfDot);
1347                     name = name.substring(indexOfDot + 1);
1348                 }
1349                 out.add(label(label));
1350                 offset += 1 + label.length();
1351             }
1352         }
1353         return out;
1354     }
1355 
label(String label)1356     static Pair<Integer, String> label(String label) {
1357         return Pair.create(label.length(), label);
1358     }
1359 
pointer(int offset)1360     static Pair<Integer, String> pointer(int offset) {
1361         return Pair.create(0xc000 | offset, null);
1362     }
1363 
1364     @Test
testGetDnsLabels()1365     public void testGetDnsLabels() throws Exception {
1366         int startOffset = 12;
1367         List<Pair<Integer, String>> actual = getDnsLabels(startOffset, "myservice.tcp.local");
1368         assertEquals(4, actual.size());
1369         assertEquals(label("myservice"), actual.get(0));
1370         assertEquals(label("tcp"), actual.get(1));
1371         assertEquals(label("local"), actual.get(2));
1372         assertEquals(label(""), actual.get(3));
1373 
1374         startOffset = 30;
1375         actual = getDnsLabels(startOffset,
1376                 "myservice.tcp.local", "foo.tcp.local", "myhostname.local", "bar.udp.local",
1377                 "foo.myhostname.local");
1378         final int tcpLocalOffset = startOffset + 1 + "myservice".length();
1379         final int localOffset = startOffset + 1 + "myservice".length() + 1 + "tcp".length();
1380         final int myhostnameLocalOffset = 30
1381                 + 1 + "myservice".length() + 1 + "tcp".length() + 1 + "local".length() + 1 + 4
1382                 + 1 + "foo".length() + 2 + 4;
1383 
1384         assertEquals(13, actual.size());
1385         assertEquals(label("myservice"), actual.get(0));
1386         assertEquals(label("tcp"), actual.get(1));
1387         assertEquals(label("local"), actual.get(2));
1388         assertEquals(label(""), actual.get(3));
1389         assertEquals(label("foo"), actual.get(4));
1390         assertEquals(pointer(tcpLocalOffset), actual.get(5));
1391         assertEquals(label("myhostname"), actual.get(6));
1392         assertEquals(pointer(localOffset), actual.get(7));
1393         assertEquals(label("bar"), actual.get(8));
1394         assertEquals(label("udp"), actual.get(9));
1395         assertEquals(pointer(localOffset), actual.get(10));
1396         assertEquals(label("foo"), actual.get(11));
1397         assertEquals(pointer(myhostnameLocalOffset), actual.get(12));
1398 
1399     }
1400 
makeMdnsCompressedV6Packet(String... names)1401     private static byte[] makeMdnsCompressedV6Packet(String... names) throws IOException {
1402         ByteBuffer questions = ByteBuffer.allocate(1500);
1403         questions.put(new DnsPacket.DnsHeader(123, 0, names.length, 0).getBytes());
1404         final List<Pair<Integer, String>> labels = getDnsLabels(questions.position(), names);
1405         for (Pair<Integer, String> label : labels) {
1406             final String name = label.second;
1407             if (name == null) {
1408                 putPointer(questions, label.first);
1409             } else {
1410                 putLabel(questions, name);
1411             }
1412             if (TextUtils.isEmpty(name)) {
1413                 questions.put(new byte[4]);
1414             }
1415         }
1416         questions.flip();
1417 
1418         ByteBuffer buf = PacketBuilder.allocate(/*hasEther=*/ true, IPPROTO_IPV6, IPPROTO_UDP,
1419                 questions.limit());
1420         final PacketBuilder builder = new PacketBuilder(buf);
1421         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1422                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS),
1423                 (short) ETH_P_IPV6);
1424         builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */,
1425                 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR),
1426                 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR));
1427         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1428 
1429         buf.put(questions);
1430 
1431         return builder.finalizePacket().array();
1432     }
1433 
makeMdnsCompressedV6Packet()1434     private static byte[] makeMdnsCompressedV6Packet() throws IOException {
1435         return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local",
1436                 "matter.tcp.local", "myhostname.local");
1437     }
1438 
makeMdnsCompressedV6PacketWithManyNames()1439     private static byte[] makeMdnsCompressedV6PacketWithManyNames() throws IOException {
1440         return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local",
1441                 "matter.tcp.local", "myhostname.local", "myhostname2.local", "myhostname3.local",
1442                 "myhostname4.local", "myhostname5.local", "myhostname6.local", "myhostname7.local");
1443 
1444     }
1445 
1446     @Test
testAddNopAddsOneByte()1447     public void testAddNopAddsOneByte() throws Exception {
1448         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
1449         gen.addNop();
1450         assertEquals(1, gen.generate().length);
1451 
1452         final int count = 42;
1453         gen = new ApfV4Generator(APF_VERSION_2, mRamSize, mClampSize);
1454         for (int i = 0; i < count; i++) {
1455             gen.addNop();
1456         }
1457         assertEquals(count, gen.generate().length);
1458     }
1459 
1460     @Test
testApfFilterMulticast()1461     public void testApfFilterMulticast() throws Exception {
1462         final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
1463         final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
1464         final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
1465         final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1466 
1467         LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
1468         LinkProperties lp = new LinkProperties();
1469         lp.addLinkAddress(link);
1470 
1471         ApfConfiguration config = getDefaultConfig();
1472         config.ieee802_3Filter = DROP_802_3_FRAMES;
1473         final ApfFilter apfFilter = getApfFilter(config);
1474         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1475         apfFilter.setLinkProperties(lp);
1476 
1477         byte[] program =
1478             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1479 
1480         // Construct IPv4 and IPv6 multicast packets.
1481         ByteBuffer mcastv4packet = makeIpv4Packet(IPPROTO_UDP);
1482         put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
1483 
1484         ByteBuffer mcastv6packet = makeIpv6Packet(IPPROTO_UDP);
1485         put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
1486 
1487         // Construct IPv4 broadcast packet.
1488         ByteBuffer bcastv4packet1 = makeIpv4Packet(IPPROTO_UDP);
1489         bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
1490         bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1491         put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
1492 
1493         ByteBuffer bcastv4packet2 = makeIpv4Packet(IPPROTO_UDP);
1494         bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
1495         bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1496         put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1497 
1498         // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
1499         ByteBuffer bcastv4unicastl2packet = makeIpv4Packet(IPPROTO_UDP);
1500         bcastv4unicastl2packet.put(TEST_MAC_ADDR);
1501         bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1502         put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
1503 
1504         // Verify initially disabled multicast filter is off
1505         assertPass(program, mcastv4packet.array());
1506         assertPass(program, mcastv6packet.array());
1507         assertPass(program, bcastv4packet1.array());
1508         assertPass(program, bcastv4packet2.array());
1509         assertPass(program, bcastv4unicastl2packet.array());
1510 
1511         // Turn on multicast filter and verify it works
1512         apfFilter.setMulticastFilter(true);
1513         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1514         assertDrop(program, mcastv4packet.array());
1515         assertDrop(program, mcastv6packet.array());
1516         assertDrop(program, bcastv4packet1.array());
1517         assertDrop(program, bcastv4packet2.array());
1518         assertDrop(program, bcastv4unicastl2packet.array());
1519 
1520         // Turn off multicast filter and verify it's off
1521         apfFilter.setMulticastFilter(false);
1522         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1523         assertPass(program, mcastv4packet.array());
1524         assertPass(program, mcastv6packet.array());
1525         assertPass(program, bcastv4packet1.array());
1526         assertPass(program, bcastv4packet2.array());
1527         assertPass(program, bcastv4unicastl2packet.array());
1528 
1529         // Verify it can be initialized to on
1530         config.multicastFilter = DROP_MULTICAST;
1531         config.ieee802_3Filter = DROP_802_3_FRAMES;
1532         clearInvocations(mApfController);
1533         final ApfFilter apfFilter2 = getApfFilter(config);
1534         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1535         apfFilter2.setLinkProperties(lp);
1536         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1537         assertDrop(program, mcastv4packet.array());
1538         assertDrop(program, mcastv6packet.array());
1539         assertDrop(program, bcastv4packet1.array());
1540         assertDrop(program, bcastv4unicastl2packet.array());
1541 
1542         // Verify that ICMPv6 multicast is not dropped.
1543         mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1544         assertPass(program, mcastv6packet.array());
1545     }
1546 
1547     @Test
testApfFilterMulticastPingWhileDozing()1548     public void testApfFilterMulticastPingWhileDozing() throws Exception {
1549         doTestApfFilterMulticastPingWhileDozing(false /* isLightDozing */);
1550     }
1551 
1552     @Test
1553     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
testApfFilterMulticastPingWhileLightDozing()1554     public void testApfFilterMulticastPingWhileLightDozing() throws Exception {
1555         doTestApfFilterMulticastPingWhileDozing(true /* isLightDozing */);
1556     }
1557 
doTestApfFilterMulticastPingWhileDozing(boolean isLightDozing)1558     private void doTestApfFilterMulticastPingWhileDozing(boolean isLightDozing) throws Exception {
1559         final ApfConfiguration configuration = getDefaultConfig();
1560         final ApfFilter apfFilter = getApfFilter(configuration);
1561         byte[] program =
1562             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1563         final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
1564                 ArgumentCaptor.forClass(BroadcastReceiver.class);
1565         verify(mDependencies).addDeviceIdleReceiver(receiverCaptor.capture());
1566         final BroadcastReceiver receiver = receiverCaptor.getValue();
1567 
1568         // Construct a multicast ICMPv6 ECHO request.
1569         final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1570         final ByteBuffer packet = makeIpv6Packet(IPPROTO_ICMPV6);
1571         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
1572         put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
1573 
1574         // Normally, we let multicast pings alone...
1575         assertPass(program, packet.array());
1576 
1577         if (isLightDozing) {
1578             doReturn(true).when(mPowerManager).isDeviceLightIdleMode();
1579             receiver.onReceive(mContext, new Intent(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
1580         } else {
1581             doReturn(true).when(mPowerManager).isDeviceIdleMode();
1582             receiver.onReceive(mContext, new Intent(ACTION_DEVICE_IDLE_MODE_CHANGED));
1583         }
1584         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1585         // ...and even while dozing...
1586         assertPass(program, packet.array());
1587 
1588         // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
1589         apfFilter.setMulticastFilter(true);
1590         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1591         assertDrop(program, packet.array());
1592 
1593         // However, we should still let through all other ICMPv6 types.
1594         ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
1595         setIpv6VersionFields(packet);
1596         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
1597         raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
1598         assertPass(program, raPacket.array());
1599 
1600         // Now wake up from doze mode to ensure that we no longer drop the packets.
1601         // (The multicast filter is still enabled at this point).
1602         if (isLightDozing) {
1603             doReturn(false).when(mPowerManager).isDeviceLightIdleMode();
1604             receiver.onReceive(mContext, new Intent(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
1605         } else {
1606             doReturn(false).when(mPowerManager).isDeviceIdleMode();
1607             receiver.onReceive(mContext, new Intent(ACTION_DEVICE_IDLE_MODE_CHANGED));
1608         }
1609         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1610         assertPass(program, packet.array());
1611     }
1612 
1613     @Test
1614     @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
testApfFilter802_3()1615     public void testApfFilter802_3() throws Exception {
1616         ApfConfiguration config = getDefaultConfig();
1617         ApfFilter apfFilter = getApfFilter(config);
1618         byte[] program =
1619             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1620 
1621         // Verify empty packet of 100 zero bytes is passed
1622         // Note that eth-type = 0 makes it an IEEE802.3 frame
1623         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1624         assertPass(program, packet.array());
1625 
1626         // Verify empty packet with IPv4 is passed
1627         setIpv4VersionFields(packet);
1628         assertPass(program, packet.array());
1629 
1630         // Verify empty IPv6 packet is passed
1631         setIpv6VersionFields(packet);
1632         assertPass(program, packet.array());
1633 
1634         // Now turn on the filter
1635         config.ieee802_3Filter = DROP_802_3_FRAMES;
1636         apfFilter = getApfFilter(config);
1637         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1638 
1639         // Verify that IEEE802.3 frame is dropped
1640         // In this case ethtype is used for payload length
1641         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
1642         assertDrop(program, packet.array());
1643 
1644         // Verify that IPv4 (as example of Ethernet II) frame will pass
1645         setIpv4VersionFields(packet);
1646         assertPass(program, packet.array());
1647 
1648         // Verify that IPv6 (as example of Ethernet II) frame will pass
1649         setIpv6VersionFields(packet);
1650         assertPass(program, packet.array());
1651     }
1652 
1653     @Test
1654     @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
testApfFilterEthTypeBL()1655     public void testApfFilterEthTypeBL() throws Exception {
1656         final int[] emptyBlackList = {};
1657         final int[] ipv4BlackList = {ETH_P_IP};
1658         final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
1659 
1660         ApfConfiguration config = getDefaultConfig();
1661         ApfFilter apfFilter = getApfFilter(config);
1662         byte[] program =
1663             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1664 
1665         // Verify empty packet of 100 zero bytes is passed
1666         // Note that eth-type = 0 makes it an IEEE802.3 frame
1667         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1668         assertPass(program, packet.array());
1669 
1670         // Verify empty packet with IPv4 is passed
1671         setIpv4VersionFields(packet);
1672         assertPass(program, packet.array());
1673 
1674         // Verify empty IPv6 packet is passed
1675         setIpv6VersionFields(packet);
1676         assertPass(program, packet.array());
1677 
1678         // Now add IPv4 to the black list
1679         config.ethTypeBlackList = ipv4BlackList;
1680         apfFilter = getApfFilter(config);
1681         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1682 
1683         // Verify that IPv4 frame will be dropped
1684         setIpv4VersionFields(packet);
1685         assertDrop(program, packet.array());
1686 
1687         // Verify that IPv6 frame will pass
1688         setIpv6VersionFields(packet);
1689         assertPass(program, packet.array());
1690 
1691         // Now let us have both IPv4 and IPv6 in the black list
1692         config.ethTypeBlackList = ipv4Ipv6BlackList;
1693         apfFilter = getApfFilter(config);
1694         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1695 
1696         // Verify that IPv4 frame will be dropped
1697         setIpv4VersionFields(packet);
1698         assertDrop(program, packet.array());
1699 
1700         // Verify that IPv6 frame will be dropped
1701         setIpv6VersionFields(packet);
1702         assertDrop(program, packet.array());
1703     }
1704 
verifyArpFilter(byte[] program, int filterResult)1705     private void verifyArpFilter(byte[] program, int filterResult) {
1706         // Verify ARP request packet
1707         assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
1708         assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
1709         assertVerdict(filterResult, program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
1710 
1711         // Verify ARP reply packets from different source ip
1712         assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
1713         assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
1714         assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
1715         assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
1716 
1717         // Verify unicast ARP reply packet is always accepted.
1718         assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
1719         assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
1720         assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
1721 
1722         // Verify GARP reply packets are always filtered
1723         assertDrop(program, garpReply());
1724     }
1725 
1726     @Test
testApfFilterArp()1727     public void testApfFilterArp() throws Exception {
1728         ApfConfiguration config = getDefaultConfig();
1729         config.multicastFilter = DROP_MULTICAST;
1730         config.ieee802_3Filter = DROP_802_3_FRAMES;
1731         ApfFilter apfFilter = getApfFilter(config);
1732         byte[] program =
1733             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1734 
1735         // Verify initially ARP request filter is off, and GARP filter is on.
1736         verifyArpFilter(program, PASS);
1737 
1738         // Inform ApfFilter of our address and verify ARP filtering is on
1739         LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
1740         LinkProperties lp = new LinkProperties();
1741         assertTrue(lp.addLinkAddress(linkAddress));
1742         apfFilter.setLinkProperties(lp);
1743         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1744         verifyArpFilter(program, DROP);
1745 
1746         apfFilter.setLinkProperties(new LinkProperties());
1747         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
1748         // Inform ApfFilter of loss of IP and verify ARP filtering is off
1749         verifyArpFilter(program, PASS);
1750     }
1751 
arpReply(byte[] sip, byte[] tip)1752     private static byte[] arpReply(byte[] sip, byte[] tip) {
1753         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1754         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
1755         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
1756         put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
1757         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
1758         return packet.array();
1759     }
1760 
arpRequestBroadcast(byte[] tip)1761     private static byte[] arpRequestBroadcast(byte[] tip) {
1762         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1763         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
1764         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1765         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
1766         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
1767         return packet.array();
1768     }
1769 
garpReply()1770     private static byte[] garpReply() {
1771         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1772         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
1773         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1774         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
1775         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
1776         return packet.array();
1777     }
1778 
1779     private static final byte[] IPV6_ANOTHER_ADDR =
1780             {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
1781 
1782     private static class RaPacketBuilder {
1783         final ByteArrayOutputStream mPacket = new ByteArrayOutputStream();
1784         int mFlowLabel = 0x12345;
1785         int mReachableTime = 30_000;
1786         int mRetransmissionTimer = 1000;
1787 
RaPacketBuilder(int routerLft)1788         public RaPacketBuilder(int routerLft) throws Exception {
1789             InetAddress src = InetAddress.getByName("fe80::1234:abcd");
1790             ByteBuffer buffer = ByteBuffer.allocate(ICMP6_RA_OPTION_OFFSET);
1791 
1792             buffer.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
1793             buffer.position(ETH_HEADER_LEN);
1794 
1795             // skip version, tclass, flowlabel; set in build()
1796             buffer.position(buffer.position() + 4);
1797 
1798             buffer.putShort((short) 0);                     // Payload length; updated later
1799             buffer.put((byte) IPPROTO_ICMPV6);              // Next header
1800             buffer.put((byte) 0xff);                        // Hop limit
1801             buffer.put(src.getAddress());                   // Source address
1802             buffer.put(IPV6_ALL_NODES_ADDRESS);             // Destination address
1803 
1804             buffer.put((byte) ICMP6_ROUTER_ADVERTISEMENT);  // Type
1805             buffer.put((byte) 0);                           // Code (0)
1806             buffer.putShort((short) 0);                     // Checksum (ignored)
1807             buffer.put((byte) 64);                          // Hop limit
1808             buffer.put((byte) 0);                           // M/O, reserved
1809             buffer.putShort((short) routerLft);             // Router lifetime
1810             // skip reachable time; set in build()
1811             // skip retransmission timer; set in build();
1812 
1813             mPacket.write(buffer.array(), 0, buffer.capacity());
1814         }
1815 
setFlowLabel(int flowLabel)1816         public RaPacketBuilder setFlowLabel(int flowLabel) {
1817             mFlowLabel = flowLabel;
1818             return this;
1819         }
1820 
setReachableTime(int reachable)1821         public RaPacketBuilder setReachableTime(int reachable) {
1822             mReachableTime = reachable;
1823             return this;
1824         }
1825 
setRetransmissionTimer(int retrans)1826         public RaPacketBuilder setRetransmissionTimer(int retrans) {
1827             mRetransmissionTimer = retrans;
1828             return this;
1829         }
1830 
addPioOption(int valid, int preferred, String prefixString)1831         public RaPacketBuilder addPioOption(int valid, int preferred, String prefixString)
1832                 throws Exception {
1833             ByteBuffer buffer = ByteBuffer.allocate(ICMP6_PREFIX_OPTION_LEN);
1834 
1835             IpPrefix prefix = new IpPrefix(prefixString);
1836             buffer.put((byte) ICMP6_PREFIX_OPTION_TYPE);  // Type
1837             buffer.put((byte) 4);                         // Length in 8-byte units
1838             buffer.put((byte) prefix.getPrefixLength());  // Prefix length
1839             buffer.put((byte) 0b11000000);                // L = 1, A = 1
1840             buffer.putInt(valid);
1841             buffer.putInt(preferred);
1842             buffer.putInt(0);                             // Reserved
1843             buffer.put(prefix.getRawAddress());
1844 
1845             mPacket.write(buffer.array(), 0, buffer.capacity());
1846             return this;
1847         }
1848 
addRioOption(int lifetime, String prefixString)1849         public RaPacketBuilder addRioOption(int lifetime, String prefixString) throws Exception {
1850             IpPrefix prefix = new IpPrefix(prefixString);
1851 
1852             int optionLength;
1853             if (prefix.getPrefixLength() == 0) {
1854                 optionLength = 1;
1855             } else if (prefix.getPrefixLength() <= 64) {
1856                 optionLength = 2;
1857             } else {
1858                 optionLength = 3;
1859             }
1860 
1861             ByteBuffer buffer = ByteBuffer.allocate(optionLength * 8);
1862 
1863             buffer.put((byte) ICMP6_ROUTE_INFO_OPTION_TYPE);  // Type
1864             buffer.put((byte) optionLength);                  // Length in 8-byte units
1865             buffer.put((byte) prefix.getPrefixLength());      // Prefix length
1866             buffer.put((byte) 0b00011000);                    // Pref = high
1867             buffer.putInt(lifetime);                          // Lifetime
1868 
1869             byte[] prefixBytes = prefix.getRawAddress();
1870             buffer.put(prefixBytes, 0, (optionLength - 1) * 8);
1871 
1872             mPacket.write(buffer.array(), 0, buffer.capacity());
1873             return this;
1874         }
1875 
addDnsslOption(int lifetime, String... domains)1876         public RaPacketBuilder addDnsslOption(int lifetime, String... domains) {
1877             ByteArrayOutputStream dnssl = new ByteArrayOutputStream();
1878             for (String domain : domains) {
1879                 for (String label : domain.split("\\.")) {
1880                     final byte[] bytes = label.getBytes(StandardCharsets.UTF_8);
1881                     dnssl.write((byte) bytes.length);
1882                     dnssl.write(bytes, 0, bytes.length);
1883                 }
1884                 dnssl.write((byte) 0);
1885             }
1886 
1887             // Extend with 0s to make it 8-byte aligned.
1888             while (dnssl.size() % 8 != 0) {
1889                 dnssl.write((byte) 0);
1890             }
1891 
1892             final int length = ICMP6_4_BYTE_OPTION_LEN + dnssl.size();
1893             ByteBuffer buffer = ByteBuffer.allocate(length);
1894 
1895             buffer.put((byte) ICMP6_DNSSL_OPTION_TYPE);  // Type
1896             buffer.put((byte) (length / 8));             // Length
1897             // skip past reserved bytes
1898             buffer.position(buffer.position() + 2);
1899             buffer.putInt(lifetime);                     // Lifetime
1900             buffer.put(dnssl.toByteArray());             // Domain names
1901 
1902             mPacket.write(buffer.array(), 0, buffer.capacity());
1903             return this;
1904         }
1905 
addRdnssOption(int lifetime, String... servers)1906         public RaPacketBuilder addRdnssOption(int lifetime, String... servers) throws Exception {
1907             int optionLength = 1 + 2 * servers.length;   // In 8-byte units
1908             ByteBuffer buffer = ByteBuffer.allocate(optionLength * 8);
1909 
1910             buffer.put((byte) ICMP6_RDNSS_OPTION_TYPE);  // Type
1911             buffer.put((byte) optionLength);             // Length
1912             buffer.putShort((short) 0);                  // Reserved
1913             buffer.putInt(lifetime);                     // Lifetime
1914             for (String server : servers) {
1915                 buffer.put(InetAddress.getByName(server).getAddress());
1916             }
1917 
1918             mPacket.write(buffer.array(), 0, buffer.capacity());
1919             return this;
1920         }
1921 
addZeroLengthOption()1922         public RaPacketBuilder addZeroLengthOption() throws Exception {
1923             ByteBuffer buffer = ByteBuffer.allocate(ICMP6_4_BYTE_OPTION_LEN);
1924             buffer.put((byte) ICMP6_PREFIX_OPTION_TYPE);
1925             buffer.put((byte) 0);
1926 
1927             mPacket.write(buffer.array(), 0, buffer.capacity());
1928             return this;
1929         }
1930 
build()1931         public byte[] build() {
1932             ByteBuffer buffer = ByteBuffer.wrap(mPacket.toByteArray());
1933             // IPv6, traffic class = 0, flow label = mFlowLabel
1934             buffer.putInt(IP_HEADER_OFFSET, 0x60000000 | (0xFFFFF & mFlowLabel));
1935             buffer.putShort(IPV6_PAYLOAD_LENGTH_OFFSET, (short) buffer.capacity());
1936 
1937             buffer.position(ICMP6_RA_REACHABLE_TIME_OFFSET);
1938             buffer.putInt(mReachableTime);
1939             buffer.putInt(mRetransmissionTimer);
1940 
1941             return buffer.array();
1942         }
1943     }
1944 
buildLargeRa()1945     private byte[] buildLargeRa() throws Exception {
1946         RaPacketBuilder builder = new RaPacketBuilder(1800 /* router lft */);
1947 
1948         builder.addRioOption(1200, "64:ff9b::/96");
1949         builder.addRdnssOption(7200, "2001:db8:1::1", "2001:db8:1::2");
1950         builder.addRioOption(2100, "2000::/3");
1951         builder.addRioOption(2400, "::/0");
1952         builder.addPioOption(600, 300, "2001:db8:a::/64");
1953         builder.addRioOption(1500, "2001:db8:c:d::/64");
1954         builder.addPioOption(86400, 43200, "fd95:d1e:12::/64");
1955 
1956         return builder.build();
1957     }
1958 
1959     @Test
testRaToString()1960     public void testRaToString() throws Exception {
1961         ApfConfiguration config = getDefaultConfig();
1962         ApfFilter apfFilter = getApfFilter(config);
1963 
1964         byte[] packet = buildLargeRa();
1965         ApfFilter.Ra ra = apfFilter.new Ra(packet, packet.length);
1966         String expected = "RA fe80::1234:abcd -> ff02::1 1800s "
1967                 + "2001:db8:a::/64 600s/300s fd95:d1e:12::/64 86400s/43200s "
1968                 + "DNS 7200s 2001:db8:1::1 2001:db8:1::2 "
1969                 + "RIO 1200s 64:ff9b::/96 RIO 2100s 2000::/3 "
1970                 + "RIO 2400s ::/0 RIO 1500s 2001:db8:c:d::/64 ";
1971         assertEquals(expected, ra.toString());
1972     }
1973 
1974     // Verify that the last program pushed to the IpClient.Callback properly filters the
1975     // given packet for the given lifetime.
verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime)1976     private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
1977         verifyRaLifetime(program, packet, lifetime, 0);
1978     }
1979 
1980     // Verify that the last program pushed to the IpClient.Callback properly filters the
1981     // given packet for the given lifetime and programInstallTime. programInstallTime is
1982     // the time difference between when RA is last seen and the program is installed.
verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime, int programInstallTime)1983     private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime,
1984             int programInstallTime) {
1985         final int FRACTION_OF_LIFETIME = 6;
1986         final int ageLimit = lifetime / FRACTION_OF_LIFETIME - programInstallTime;
1987 
1988         // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
1989         assertDrop(program, packet.array());
1990         assertDrop(program, packet.array(), ageLimit);
1991         assertPass(program, packet.array(), ageLimit + 1);
1992         assertPass(program, packet.array(), lifetime);
1993         // Verify RA checksum is ignored
1994         final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
1995         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
1996         assertDrop(program, packet.array());
1997         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
1998         assertDrop(program, packet.array());
1999         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
2000 
2001         // Verify other changes to RA (e.g., a change in the source address) make it not match.
2002         final int offset = IPV6_SRC_ADDR_OFFSET + 5;
2003         final byte originalByte = packet.get(offset);
2004         packet.put(offset, (byte) (~originalByte));
2005         assertPass(program, packet.array());
2006         packet.put(offset, originalByte);
2007         assertDrop(program, packet.array());
2008     }
2009 
2010     // Test that when ApfFilter is shown the given packet, it generates a program to filter it
2011     // for the given lifetime.
verifyRaLifetime(ByteBuffer packet, int lifetime)2012     private byte[] verifyRaLifetime(ByteBuffer packet, int lifetime)
2013             throws IOException, ErrnoException {
2014         // Verify new program generated if ApfFilter witnesses RA
2015         clearInvocations(mApfController);
2016         pretendPacketReceived(packet.array());
2017         byte[] program =
2018             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2019         verifyRaLifetime(program, packet, lifetime);
2020         return program;
2021     }
2022 
assertInvalidRa(ByteBuffer packet)2023     private void assertInvalidRa(ByteBuffer packet)
2024             throws IOException, ErrnoException, InterruptedException {
2025         clearInvocations(mApfController);
2026         pretendPacketReceived(packet.array());
2027         Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
2028         verify(mApfController, never()).installPacketFilter(any(), any());
2029     }
2030 
2031     @Test
testApfFilterRa()2032     public void testApfFilterRa() throws Exception {
2033         ApfConfiguration config = getDefaultConfig();
2034         config.multicastFilter = DROP_MULTICAST;
2035         config.ieee802_3Filter = DROP_802_3_FRAMES;
2036         ApfFilter apfFilter = getApfFilter(config);
2037         byte[] program =
2038             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2039 
2040         final int ROUTER_LIFETIME = 1000;
2041         final int PREFIX_VALID_LIFETIME = 200;
2042         final int PREFIX_PREFERRED_LIFETIME = 100;
2043         final int RDNSS_LIFETIME  = 300;
2044         final int ROUTE_LIFETIME  = 400;
2045         // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
2046         final int DNSSL_LIFETIME  = 2000;
2047 
2048         // Verify RA is passed the first time
2049         RaPacketBuilder ra = new RaPacketBuilder(ROUTER_LIFETIME);
2050         ByteBuffer basePacket = ByteBuffer.wrap(ra.build());
2051         assertPass(program, basePacket.array());
2052 
2053         verifyRaLifetime(basePacket, ROUTER_LIFETIME);
2054 
2055         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2056         // Check that changes are ignored in every byte of the flow label.
2057         ra.setFlowLabel(0x56789);
2058         ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(ra.build());
2059 
2060         // Ensure zero-length options cause the packet to be silently skipped.
2061         // Do this before we test other packets. http://b/29586253
2062         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2063         ra.addZeroLengthOption();
2064         ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(ra.build());
2065         assertInvalidRa(zeroLengthOptionPacket);
2066 
2067         // Generate several RAs with different options and lifetimes, and verify when
2068         // ApfFilter is shown these packets, it generates programs to filter them for the
2069         // appropriate lifetime.
2070         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2071         ra.addPioOption(PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, "2001:db8::/64");
2072         ByteBuffer prefixOptionPacket = ByteBuffer.wrap(ra.build());
2073         verifyRaLifetime(prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
2074 
2075         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2076         ra.addRdnssOption(RDNSS_LIFETIME, "2001:4860:4860::8888", "2001:4860:4860::8844");
2077         ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(ra.build());
2078         verifyRaLifetime(rdnssOptionPacket, RDNSS_LIFETIME);
2079 
2080         final int lowLifetime = 60;
2081         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2082         ra.addRdnssOption(lowLifetime, "2620:fe::9");
2083         ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap(ra.build());
2084         verifyRaLifetime(lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME);
2085 
2086         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2087         ra.addRioOption(ROUTE_LIFETIME, "64:ff9b::/96");
2088         ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(ra.build());
2089         program = verifyRaLifetime(routeInfoOptionPacket, ROUTE_LIFETIME);
2090 
2091         // Check that RIOs differing only in the first 4 bytes are different.
2092         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2093         ra.addRioOption(ROUTE_LIFETIME, "64:ff9b::/64");
2094         // Packet should be passed because it is different.
2095         assertPass(program, ra.build());
2096 
2097         ra = new RaPacketBuilder(ROUTER_LIFETIME);
2098         ra.addDnsslOption(DNSSL_LIFETIME, "test.example.com", "one.more.example.com");
2099         ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(ra.build());
2100         verifyRaLifetime(dnsslOptionPacket, ROUTER_LIFETIME);
2101 
2102         ByteBuffer largeRaPacket = ByteBuffer.wrap(buildLargeRa());
2103         program = verifyRaLifetime(largeRaPacket, 300);
2104 
2105         // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10).
2106         verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
2107         verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
2108         verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
2109         verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
2110         verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME);
2111         verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
2112         verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
2113         verifyRaLifetime(program, largeRaPacket, 300);
2114     }
2115 
2116     @Test
testRaWithDifferentReachableTimeAndRetransTimer()2117     public void testRaWithDifferentReachableTimeAndRetransTimer() throws Exception {
2118         final ApfConfiguration config = getDefaultConfig();
2119         config.multicastFilter = DROP_MULTICAST;
2120         config.ieee802_3Filter = DROP_802_3_FRAMES;
2121         final ApfFilter apfFilter = getApfFilter(config);
2122         byte[] program =
2123             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2124         final int RA_REACHABLE_TIME = 1800;
2125         final int RA_RETRANSMISSION_TIMER = 1234;
2126 
2127         // Create an Ra packet without options
2128         // Reachable time = 1800, retransmission timer = 1234
2129         RaPacketBuilder ra = new RaPacketBuilder(1800 /* router lft */);
2130         ra.setReachableTime(RA_REACHABLE_TIME);
2131         ra.setRetransmissionTimer(RA_RETRANSMISSION_TIMER);
2132         byte[] raPacket = ra.build();
2133         // First RA passes filter
2134         assertPass(program, raPacket);
2135 
2136         // Assume apf is shown the given RA, it generates program to filter it.
2137         pretendPacketReceived(raPacket);
2138         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2139         assertDrop(program, raPacket);
2140 
2141         // A packet with different reachable time should be passed.
2142         // Reachable time = 2300, retransmission timer = 1234
2143         ra.setReachableTime(RA_REACHABLE_TIME + 500);
2144         raPacket = ra.build();
2145         assertPass(program, raPacket);
2146 
2147         // A packet with different retransmission timer should be passed.
2148         // Reachable time = 1800, retransmission timer = 2234
2149         ra.setReachableTime(RA_REACHABLE_TIME);
2150         ra.setRetransmissionTimer(RA_RETRANSMISSION_TIMER + 1000);
2151         raPacket = ra.build();
2152         assertPass(program, raPacket);
2153     }
2154 
2155     // The ByteBuffer is always created by ByteBuffer#wrap in the helper functions
2156     @SuppressWarnings("ByteBufferBackingArray")
2157     @Test
testRaWithProgramInstalledSomeTimeAfterLastSeen()2158     public void testRaWithProgramInstalledSomeTimeAfterLastSeen() throws Exception {
2159         final ApfConfiguration config = getDefaultConfig();
2160         config.multicastFilter = DROP_MULTICAST;
2161         config.ieee802_3Filter = DROP_802_3_FRAMES;
2162         final ApfFilter apfFilter = getApfFilter(config);
2163         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2164 
2165         final int routerLifetime = 1000;
2166         final int timePassedSeconds = 12;
2167 
2168         // Verify that when the program is generated and installed some time after RA is last seen
2169         // it should be installed with the correct remaining lifetime.
2170         ByteBuffer basePacket = ByteBuffer.wrap(new RaPacketBuilder(routerLifetime).build());
2171         verifyRaLifetime(basePacket, routerLifetime);
2172 
2173         mCurrentTimeMs += timePassedSeconds * DateUtils.SECOND_IN_MILLIS;
2174         doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime();
2175         synchronized (apfFilter) {
2176             apfFilter.installNewProgram();
2177         }
2178         byte[] program =
2179             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2180         verifyRaLifetime(program, basePacket, routerLifetime, timePassedSeconds);
2181 
2182         // Packet should be passed if the program is installed after 1/6 * lifetime from last seen
2183         mCurrentTimeMs +=
2184                 ((routerLifetime / 6) - timePassedSeconds - 1) * DateUtils.SECOND_IN_MILLIS;
2185         doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime();
2186         synchronized (apfFilter) {
2187             apfFilter.installNewProgram();
2188         }
2189         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2190         assertDrop(program, basePacket.array());
2191 
2192         mCurrentTimeMs += DateUtils.SECOND_IN_MILLIS;
2193         doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime();
2194         synchronized (apfFilter) {
2195             apfFilter.installNewProgram();
2196         }
2197         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2198         assertPass(program, basePacket.array());
2199     }
2200 
2201     /**
2202      * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
2203      * copy that resource into the app's data directory and return the path to it.
2204      */
stageFile(int rawId)2205     private String stageFile(int rawId) throws Exception {
2206         File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
2207         new File(file.getParent()).mkdirs();
2208         InputStream in = null;
2209         OutputStream out = null;
2210         try {
2211             in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
2212             out = new FileOutputStream(file);
2213             Streams.copy(in, out);
2214         } finally {
2215             if (in != null) in.close();
2216             if (out != null) out.close();
2217         }
2218         return file.getAbsolutePath();
2219     }
2220 
put(ByteBuffer buffer, int position, byte[] bytes)2221     private static void put(ByteBuffer buffer, int position, byte[] bytes) {
2222         final int original = buffer.position();
2223         buffer.position(position);
2224         buffer.put(bytes);
2225         buffer.position(original);
2226     }
2227 
2228     @Test
testRaParsing()2229     public void testRaParsing() throws Exception {
2230         final int maxRandomPacketSize = 512;
2231         final Random r = new Random();
2232         ApfConfiguration config = getDefaultConfig();
2233         config.multicastFilter = DROP_MULTICAST;
2234         config.ieee802_3Filter = DROP_802_3_FRAMES;
2235         ApfFilter apfFilter = getApfFilter(config);
2236         for (int i = 0; i < 1000; i++) {
2237             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2238             r.nextBytes(packet);
2239             try {
2240                 apfFilter.new Ra(packet, packet.length);
2241             } catch (ApfFilter.InvalidRaException e) {
2242             } catch (Exception e) {
2243                 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2244             }
2245         }
2246     }
2247 
2248     @Test
testRaProcessing()2249     public void testRaProcessing() throws Exception {
2250         final int maxRandomPacketSize = 512;
2251         final Random r = new Random();
2252         ApfConfiguration config = getDefaultConfig();
2253         config.multicastFilter = DROP_MULTICAST;
2254         config.ieee802_3Filter = DROP_802_3_FRAMES;
2255         ApfFilter apfFilter = getApfFilter(config);
2256         for (int i = 0; i < 1000; i++) {
2257             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2258             r.nextBytes(packet);
2259             try {
2260                 apfFilter.processRa(packet, packet.length);
2261             } catch (Exception e) {
2262                 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2263             }
2264         }
2265     }
2266 
2267     @Test
testMatchedRaUpdatesLifetime()2268     public void testMatchedRaUpdatesLifetime() throws Exception {
2269         final ApfFilter apfFilter = getApfFilter(getDefaultConfig());
2270         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2271 
2272         // Create an RA and build an APF program
2273         byte[] ra = new RaPacketBuilder(1800 /* router lifetime */).build();
2274         pretendPacketReceived(ra);
2275         byte[] program =
2276             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2277 
2278         // lifetime dropped significantly, assert pass
2279         ra = new RaPacketBuilder(200 /* router lifetime */).build();
2280         assertPass(program, ra);
2281 
2282         // update program with the new RA
2283         pretendPacketReceived(ra);
2284         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2285 
2286         // assert program was updated and new lifetimes were taken into account.
2287         assertDrop(program, ra);
2288     }
2289     @Test
testProcessRaWithInfiniteLifeTimeWithoutCrash()2290     public void testProcessRaWithInfiniteLifeTimeWithoutCrash() throws Exception {
2291         // configure accept_ra_min_lft
2292         final ApfConfiguration config = getDefaultConfig();
2293         config.acceptRaMinLft = 180;
2294         ApfFilter apfFilter = getApfFilter(config);
2295         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2296         // Template packet:
2297         // Frame 1: 150 bytes on wire (1200 bits), 150 bytes captured (1200 bits)
2298         // Ethernet II, Src: Netgear_23:67:2c (28:c6:8e:23:67:2c), Dst: IPv6mcast_01 (33:33:00:00:00:01)
2299         // Internet Protocol Version 6, Src: fe80::2ac6:8eff:fe23:672c, Dst: ff02::1
2300         // Internet Control Message Protocol v6
2301         //   Type: Router Advertisement (134)
2302         //   Code: 0
2303         //   Checksum: 0x0acd [correct]
2304         //   Checksum Status: Good
2305         //   Cur hop limit: 64
2306         //   Flags: 0xc0, Managed address configuration, Other configuration, Prf (Default Router Preference): Medium
2307         //   Router lifetime (s): 7000
2308         //   Reachable time (ms): 0
2309         //   Retrans timer (ms): 0
2310         //   ICMPv6 Option (Source link-layer address : 28:c6:8e:23:67:2c)
2311         //     Type: Source link-layer address (1)
2312         //     Length: 1 (8 bytes)
2313         //     Link-layer address: Netgear_23:67:2c (28:c6:8e:23:67:2c)
2314         //     Source Link-layer address: Netgear_23:67:2c (28:c6:8e:23:67:2c)
2315         //   ICMPv6 Option (MTU : 1500)
2316         //     Type: MTU (5)
2317         //     Length: 1 (8 bytes)
2318         //     Reserved
2319         //     MTU: 1500
2320         //   ICMPv6 Option (Prefix information : 2401:fa00:480:f000::/64)
2321         //     Type: Prefix information (3)
2322         //     Length: 4 (32 bytes)
2323         //     Prefix Length: 64
2324         //     Flag: 0xc0, On-link flag(L), Autonomous address-configuration flag(A)
2325         //     Valid Lifetime: Infinity (4294967295)
2326         //     Preferred Lifetime: Infinity (4294967295)
2327         //     Reserved
2328         //     Prefix: 2401:fa00:480:f000::
2329         //   ICMPv6 Option (Recursive DNS Server 2401:fa00:480:f000::1)
2330         //     Type: Recursive DNS Server (25)
2331         //     Length: 3 (24 bytes)
2332         //     Reserved
2333         //     Lifetime: 7000
2334         //     Recursive DNS Servers: 2401:fa00:480:f000::1
2335         //   ICMPv6 Option (Advertisement Interval : 600000)
2336         //     Type: Advertisement Interval (7)
2337         //     Length: 1 (8 bytes)
2338         //     Reserved
2339         //     Advertisement Interval: 600000
2340         final String packetStringFmt = "33330000000128C68E23672C86DD60054C6B00603AFFFE800000000000002AC68EFFFE23672CFF02000000000000000000000000000186000ACD40C01B580000000000000000010128C68E23672C05010000000005DC030440C0%s000000002401FA000480F00000000000000000001903000000001B582401FA000480F000000000000000000107010000000927C0";
2341         final List<String> lifetimes = List.of("FFFFFFFF", "00000000", "00000001", "00001B58");
2342         for (String lifetime : lifetimes) {
2343             final byte[] ra = hexStringToByteArray(
2344                     String.format(packetStringFmt, lifetime + lifetime));
2345             // feed the RA into APF and generate the filter, the filter shouldn't crash.
2346             pretendPacketReceived(ra);
2347             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2348         }
2349     }
2350 
2351     // Test for go/apf-ra-filter Case 1a.
2352     // Old lifetime is 0
2353     @Test
testAcceptRaMinLftCase1a()2354     public void testAcceptRaMinLftCase1a() throws Exception {
2355         // configure accept_ra_min_lft
2356         final ApfConfiguration config = getDefaultConfig();
2357         config.acceptRaMinLft = 180;
2358         final ApfFilter apfFilter = getApfFilter(config);
2359         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2360 
2361         // Create an initial RA and build an APF program
2362         byte[] ra = new RaPacketBuilder(1800 /* router lifetime */)
2363                 .addPioOption(1800 /*valid*/, 0 /*preferred*/, "2001:db8::/64")
2364                 .build();
2365 
2366         pretendPacketReceived(ra);
2367         byte[] program =
2368             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2369 
2370         // repeated RA is dropped
2371         assertDrop(program, ra);
2372 
2373         // PIO preferred lifetime increases
2374         ra = new RaPacketBuilder(1800 /* router lifetime */)
2375                 .addPioOption(1800 /*valid*/, 1 /*preferred*/, "2001:db8::/64")
2376                 .build();
2377         assertPass(program, ra);
2378     }
2379 
2380     // Test for go/apf-ra-filter Case 2a.
2381     // Old lifetime is > 0
2382     @Test
testAcceptRaMinLftCase2a()2383     public void testAcceptRaMinLftCase2a() throws Exception {
2384         // configure accept_ra_min_lft
2385         final ApfConfiguration config = getDefaultConfig();
2386         config.acceptRaMinLft = 180;
2387         final ApfFilter apfFilter = getApfFilter(config);
2388         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2389 
2390         // Create an initial RA and build an APF program
2391         byte[] ra = new RaPacketBuilder(1800 /* router lifetime */)
2392                 .addPioOption(1800 /*valid*/, 100 /*preferred*/, "2001:db8::/64")
2393                 .build();
2394 
2395         pretendPacketReceived(ra);
2396         byte[] program =
2397             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2398 
2399         // repeated RA is dropped
2400         assertDrop(program, ra);
2401 
2402         // PIO preferred lifetime increases
2403         ra = new RaPacketBuilder(1800 /* router lifetime */)
2404                 .addPioOption(1800 /*valid*/, 101 /*preferred*/, "2001:db8::/64")
2405                 .build();
2406         assertPass(program, ra);
2407 
2408         // PIO preferred lifetime decreases significantly
2409         ra = new RaPacketBuilder(1800 /* router lifetime */)
2410                 .addPioOption(1800 /*valid*/, 33 /*preferred*/, "2001:db8::/64")
2411                 .build();
2412         assertPass(program, ra);
2413     }
2414 
2415 
2416     // Test for go/apf-ra-filter Case 1b.
2417     // Old lifetime is 0
2418     @Test
testAcceptRaMinLftCase1b()2419     public void testAcceptRaMinLftCase1b() throws Exception {
2420         // configure accept_ra_min_lft
2421         final ApfConfiguration config = getDefaultConfig();
2422         config.acceptRaMinLft = 180;
2423         final ApfFilter apfFilter = getApfFilter(config);
2424         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2425 
2426         // Create an initial RA and build an APF program
2427         byte[] ra = new RaPacketBuilder(0 /* router lifetime */).build();
2428 
2429         pretendPacketReceived(ra);
2430         byte[] program =
2431             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2432 
2433         // repeated RA is dropped
2434         assertDrop(program, ra);
2435 
2436         // lifetime increases below accept_ra_min_lft
2437         ra = new RaPacketBuilder(179 /* router lifetime */).build();
2438         assertDrop(program, ra);
2439 
2440         // lifetime increases to accept_ra_min_lft
2441         ra = new RaPacketBuilder(180 /* router lifetime */).build();
2442         assertPass(program, ra);
2443     }
2444 
2445     // Test for go/apf-ra-filter Case 2b.
2446     // Old lifetime is < accept_ra_min_lft (but not 0).
2447     @Test
testAcceptRaMinLftCase2b()2448     public void testAcceptRaMinLftCase2b() throws Exception {
2449         // configure accept_ra_min_lft
2450         final ApfConfiguration config = getDefaultConfig();
2451         config.acceptRaMinLft = 180;
2452         final ApfFilter apfFilter = getApfFilter(config);
2453         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2454 
2455         // Create an initial RA and build an APF program
2456         byte[] ra = new RaPacketBuilder(100 /* router lifetime */).build();
2457 
2458         pretendPacketReceived(ra);
2459         byte[] program =
2460             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2461 
2462         // repeated RA is dropped
2463         assertDrop(program, ra);
2464 
2465         // lifetime increases
2466         ra = new RaPacketBuilder(101 /* router lifetime */).build();
2467         assertDrop(program, ra);
2468 
2469         // lifetime decreases significantly
2470         ra = new RaPacketBuilder(1 /* router lifetime */).build();
2471         assertDrop(program, ra);
2472 
2473         // equals accept_ra_min_lft
2474         ra = new RaPacketBuilder(180 /* router lifetime */).build();
2475         assertPass(program, ra);
2476 
2477         // lifetime is 0
2478         ra = new RaPacketBuilder(0 /* router lifetime */).build();
2479         assertPass(program, ra);
2480     }
2481 
2482     // Test for go/apf-ra-filter Case 3b.
2483     // Old lifetime is >= accept_ra_min_lft and <= 3 * accept_ra_min_lft
2484     @Test
testAcceptRaMinLftCase3b()2485     public void testAcceptRaMinLftCase3b() throws Exception {
2486         // configure accept_ra_min_lft
2487         final ApfConfiguration config = getDefaultConfig();
2488         config.acceptRaMinLft = 180;
2489         final ApfFilter apfFilter = getApfFilter(config);
2490         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2491 
2492         // Create an initial RA and build an APF program
2493         byte[] ra = new RaPacketBuilder(200 /* router lifetime */).build();
2494 
2495         pretendPacketReceived(ra);
2496         byte[] program =
2497             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2498 
2499         // repeated RA is dropped
2500         assertDrop(program, ra);
2501 
2502         // lifetime increases
2503         ra = new RaPacketBuilder(201 /* router lifetime */).build();
2504         assertPass(program, ra);
2505 
2506         // lifetime is below accept_ra_min_lft (but not 0)
2507         ra = new RaPacketBuilder(1 /* router lifetime */).build();
2508         assertDrop(program, ra);
2509 
2510         // lifetime is 0
2511         ra = new RaPacketBuilder(0 /* router lifetime */).build();
2512         assertPass(program, ra);
2513     }
2514 
2515     // Test for go/apf-ra-filter Case 4b.
2516     // Old lifetime is > 3 * accept_ra_min_lft
2517     @Test
testAcceptRaMinLftCase4b()2518     public void testAcceptRaMinLftCase4b() throws Exception {
2519         // configure accept_ra_min_lft
2520         final ApfConfiguration config = getDefaultConfig();
2521         config.acceptRaMinLft = 180;
2522         final ApfFilter apfFilter = getApfFilter(config);
2523         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2524 
2525         // Create an initial RA and build an APF program
2526         byte[] ra = new RaPacketBuilder(1800 /* router lifetime */).build();
2527 
2528         pretendPacketReceived(ra);
2529         byte[] program =
2530             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2531 
2532         // repeated RA is dropped
2533         assertDrop(program, ra);
2534 
2535         // lifetime increases
2536         ra = new RaPacketBuilder(1801 /* router lifetime */).build();
2537         assertPass(program, ra);
2538 
2539         // lifetime is 1/3 of old lft
2540         ra = new RaPacketBuilder(600 /* router lifetime */).build();
2541         assertDrop(program, ra);
2542 
2543         // lifetime is below 1/3 of old lft
2544         ra = new RaPacketBuilder(599 /* router lifetime */).build();
2545         assertPass(program, ra);
2546 
2547         // lifetime is below accept_ra_min_lft (but not 0)
2548         ra = new RaPacketBuilder(1 /* router lifetime */).build();
2549         assertDrop(program, ra);
2550 
2551         // lifetime is 0
2552         ra = new RaPacketBuilder(0 /* router lifetime */).build();
2553         assertPass(program, ra);
2554     }
2555 
2556     @Test
testRaFilterIsUpdated()2557     public void testRaFilterIsUpdated() throws Exception {
2558         // configure accept_ra_min_lft
2559         final ApfConfiguration config = getDefaultConfig();
2560         config.acceptRaMinLft = 180;
2561         final ApfFilter apfFilter = getApfFilter(config);
2562         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2563 
2564         // Create an initial RA and build an APF program
2565         byte[] ra = new RaPacketBuilder(1800 /* router lifetime */).build();
2566         pretendPacketReceived(ra);
2567         byte[] program =
2568             mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2569 
2570         // repeated RA is dropped.
2571         assertDrop(program, ra);
2572 
2573         // updated RA is passed, repeated RA is dropped after program update.
2574         ra = new RaPacketBuilder(599 /* router lifetime */).build();
2575         assertPass(program, ra);
2576         pretendPacketReceived(ra);
2577         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2578         assertDrop(program, ra);
2579 
2580         ra = new RaPacketBuilder(180 /* router lifetime */).build();
2581         assertPass(program, ra);
2582         pretendPacketReceived(ra);
2583         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2584         assertDrop(program, ra);
2585 
2586         ra = new RaPacketBuilder(0 /* router lifetime */).build();
2587         assertPass(program, ra);
2588         pretendPacketReceived(ra);
2589         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2590         assertDrop(program, ra);
2591 
2592         ra = new RaPacketBuilder(180 /* router lifetime */).build();
2593         assertPass(program, ra);
2594         pretendPacketReceived(ra);
2595         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2596         assertDrop(program, ra);
2597 
2598         ra = new RaPacketBuilder(599 /* router lifetime */).build();
2599         assertPass(program, ra);
2600         pretendPacketReceived(ra);
2601         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2602         assertDrop(program, ra);
2603 
2604         ra = new RaPacketBuilder(1800 /* router lifetime */).build();
2605         assertPass(program, ra);
2606         pretendPacketReceived(ra);
2607         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2608         assertDrop(program, ra);
2609     }
2610 
2611     @Test
testBroadcastAddress()2612     public void testBroadcastAddress() throws Exception {
2613         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
2614         assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
2615         assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
2616         assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
2617 
2618         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
2619         assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
2620         assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
2621         assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
2622     }
2623 
assertEqualsIp(String expected, int got)2624     public void assertEqualsIp(String expected, int got) throws Exception {
2625         int want = Inet4AddressUtils.inet4AddressToIntHTH(
2626                 (Inet4Address) InetAddresses.parseNumericAddress(expected));
2627         assertEquals(want, got);
2628     }
2629 
2630     @Test
testInstallPacketFilterFailure()2631     public void testInstallPacketFilterFailure() throws Exception {
2632         doReturn(false).when(mApfController).installPacketFilter(any(), any());
2633         final ApfConfiguration config = getDefaultConfig();
2634         final ApfFilter apfFilter = getApfFilter(config);
2635 
2636         verify(mNetworkQuirkMetrics).setEvent(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE);
2637         verify(mNetworkQuirkMetrics).statsWrite();
2638         reset(mNetworkQuirkMetrics);
2639         synchronized (apfFilter) {
2640             apfFilter.installNewProgram();
2641         }
2642         verify(mNetworkQuirkMetrics).setEvent(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE);
2643         verify(mNetworkQuirkMetrics).statsWrite();
2644     }
2645 
2646 
2647     @Test
testApfProgramOverSize()2648     public void testApfProgramOverSize() throws Exception {
2649         final ApfConfiguration config = getDefaultConfig();
2650         config.apfVersionSupported = 2;
2651         config.apfRamSize = 256;
2652         final ApfFilter apfFilter = getApfFilter(config);
2653         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2654         verify(mNetworkQuirkMetrics).setEvent(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
2655         verify(mNetworkQuirkMetrics).statsWrite();
2656     }
2657 
2658     @Test
testApfSessionInfoMetrics()2659     public void testApfSessionInfoMetrics() throws Exception {
2660         final ApfConfiguration config = getDefaultConfig();
2661         config.apfVersionSupported = 4;
2662         config.apfRamSize = 4096;
2663         final long startTimeMs = 12345;
2664         final long durationTimeMs = config.minMetricsSessionDurationMs;
2665         doReturn(startTimeMs).when(mDependencies).elapsedRealtime();
2666         final ApfFilter apfFilter = getApfFilter(config);
2667         byte[] program =
2668             mApfTestHelpers.consumeInstalledProgram(mApfController, 2 /* installCnt */);
2669         int maxProgramSize = 0;
2670         int numProgramUpdated = 0;
2671         maxProgramSize = Math.max(maxProgramSize, program.length);
2672         numProgramUpdated++;
2673 
2674         final byte[] data = new byte[Counter.totalSize()];
2675         final byte[] expectedData = data.clone();
2676         final int totalPacketsCounterIdx = Counter.totalSize() + Counter.TOTAL_PACKETS.offset();
2677         final int passedIpv6IcmpCounterIdx =
2678                 Counter.totalSize() + Counter.PASSED_IPV6_ICMP.offset();
2679         final int droppedIpv4MulticastIdx =
2680                 Counter.totalSize() + Counter.DROPPED_IPV4_MULTICAST.offset();
2681 
2682         // Receive an RA packet (passed).
2683         final byte[] ra = buildLargeRa();
2684         expectedData[totalPacketsCounterIdx + 3] += 1;
2685         expectedData[passedIpv6IcmpCounterIdx + 3] += 1;
2686         assertDataMemoryContentsIgnoreVersion(PASS, program, ra, data, expectedData);
2687         pretendPacketReceived(ra);
2688         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2689         maxProgramSize = Math.max(maxProgramSize, program.length);
2690         numProgramUpdated++;
2691 
2692         apfFilter.setMulticastFilter(true);
2693         // setMulticastFilter will trigger program installation.
2694         program = mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2695         maxProgramSize = Math.max(maxProgramSize, program.length);
2696         numProgramUpdated++;
2697 
2698         // Receive IPv4 multicast packet (dropped).
2699         final byte[] multicastIpv4Addr = {(byte) 224, 0, 0, 1};
2700         ByteBuffer mcastv4packet = makeIpv4Packet(IPPROTO_UDP);
2701         put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
2702         expectedData[totalPacketsCounterIdx + 3] += 1;
2703         expectedData[droppedIpv4MulticastIdx + 3] += 1;
2704         assertDataMemoryContentsIgnoreVersion(DROP, program, mcastv4packet.array(), data,
2705                 expectedData);
2706 
2707         // Set data snapshot and update counters.
2708         apfFilter.setDataSnapshot(data);
2709 
2710         // Write metrics data to statsd pipeline when shutdown.
2711         doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime();
2712         mHandler.post(apfFilter::shutdown);
2713         IoUtils.closeQuietly(mWriteSocket);
2714         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
2715         verify(mApfSessionInfoMetrics).setVersion(4);
2716         verify(mApfSessionInfoMetrics).setMemorySize(4096);
2717 
2718         // Verify Counters
2719         final Map<Counter, Long> expectedCounters = Map.of(Counter.TOTAL_PACKETS, 2L,
2720                 Counter.PASSED_IPV6_ICMP, 1L, Counter.DROPPED_IPV4_MULTICAST, 1L);
2721         final ArgumentCaptor<Counter> counterCaptor = ArgumentCaptor.forClass(Counter.class);
2722         final ArgumentCaptor<Long> valueCaptor = ArgumentCaptor.forClass(Long.class);
2723         verify(mApfSessionInfoMetrics, times(expectedCounters.size())).addApfCounter(
2724                 counterCaptor.capture(), valueCaptor.capture());
2725         final List<Counter> counters = counterCaptor.getAllValues();
2726         final List<Long> values = valueCaptor.getAllValues();
2727         final ArrayMap<Counter, Long> capturedCounters = new ArrayMap<>();
2728         for (int i = 0; i < counters.size(); i++) {
2729             capturedCounters.put(counters.get(i), values.get(i));
2730         }
2731         assertEquals(expectedCounters, capturedCounters);
2732 
2733         verify(mApfSessionInfoMetrics).setApfSessionDurationSeconds(
2734                 (int) (durationTimeMs / DateUtils.SECOND_IN_MILLIS));
2735         verify(mApfSessionInfoMetrics).setNumOfTimesApfProgramUpdated(numProgramUpdated);
2736         verify(mApfSessionInfoMetrics).setMaxProgramSize(maxProgramSize);
2737         verify(mApfSessionInfoMetrics).statsWrite();
2738     }
2739 
2740     @Test
testIpClientRaInfoMetrics()2741     public void testIpClientRaInfoMetrics() throws Exception {
2742         final ApfConfiguration config = getDefaultConfig();
2743         final long startTimeMs = 12345;
2744         final long durationTimeMs = config.minMetricsSessionDurationMs;
2745         doReturn(startTimeMs).when(mDependencies).elapsedRealtime();
2746         final ApfFilter apfFilter = getApfFilter(config);
2747         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2748 
2749         final int routerLifetime = 1000;
2750         final int prefixValidLifetime = 200;
2751         final int prefixPreferredLifetime = 100;
2752         final int rdnssLifetime  = 300;
2753         final int routeLifetime  = 400;
2754 
2755         // Construct 2 RAs with partial lifetimes larger than predefined constants
2756         final RaPacketBuilder ra1 = new RaPacketBuilder(routerLifetime);
2757         ra1.addPioOption(prefixValidLifetime + 123, prefixPreferredLifetime, "2001:db8::/64");
2758         ra1.addRdnssOption(rdnssLifetime, "2001:4860:4860::8888", "2001:4860:4860::8844");
2759         ra1.addRioOption(routeLifetime + 456, "64:ff9b::/96");
2760         final RaPacketBuilder ra2 = new RaPacketBuilder(routerLifetime + 123);
2761         ra2.addPioOption(prefixValidLifetime, prefixPreferredLifetime, "2001:db9::/64");
2762         ra2.addRdnssOption(rdnssLifetime + 456, "2001:4860:4860::8888", "2001:4860:4860::8844");
2763         ra2.addRioOption(routeLifetime, "64:ff9b::/96");
2764 
2765         // Construct an invalid RA packet
2766         final RaPacketBuilder raInvalid = new RaPacketBuilder(routerLifetime);
2767         raInvalid.addZeroLengthOption();
2768 
2769         // Construct 4 different kinds of zero lifetime RAs
2770         final RaPacketBuilder raZeroRouterLifetime = new RaPacketBuilder(0 /* routerLft */);
2771         final RaPacketBuilder raZeroPioValidLifetime = new RaPacketBuilder(routerLifetime);
2772         raZeroPioValidLifetime.addPioOption(0, prefixPreferredLifetime, "2001:db10::/64");
2773         final RaPacketBuilder raZeroRdnssLifetime = new RaPacketBuilder(routerLifetime);
2774         raZeroRdnssLifetime.addPioOption(
2775                 prefixValidLifetime, prefixPreferredLifetime, "2001:db11::/64");
2776         raZeroRdnssLifetime.addRdnssOption(0, "2001:4860:4860::8888", "2001:4860:4860::8844");
2777         final RaPacketBuilder raZeroRioRouteLifetime = new RaPacketBuilder(routerLifetime);
2778         raZeroRioRouteLifetime.addPioOption(
2779                 prefixValidLifetime, prefixPreferredLifetime, "2001:db12::/64");
2780         raZeroRioRouteLifetime.addRioOption(0, "64:ff9b::/96");
2781 
2782         // Inject RA packets. Calling assertProgramUpdateAndGet()/assertNoProgramUpdate() is to make
2783         // sure that the RA packet has been processed.
2784         pretendPacketReceived(ra1.build());
2785         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2786         pretendPacketReceived(ra2.build());
2787         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2788         pretendPacketReceived(raInvalid.build());
2789         Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
2790         verify(mApfController, never()).installPacketFilter(any(), any());
2791         pretendPacketReceived(raZeroRouterLifetime.build());
2792         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2793         pretendPacketReceived(raZeroPioValidLifetime.build());
2794         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2795         pretendPacketReceived(raZeroRdnssLifetime.build());
2796         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2797         pretendPacketReceived(raZeroRioRouteLifetime.build());
2798         mApfTestHelpers.consumeInstalledProgram(mApfController, 1 /* installCnt */);
2799 
2800         // Write metrics data to statsd pipeline when shutdown.
2801         doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime();
2802         mHandler.post(apfFilter::shutdown);
2803         IoUtils.closeQuietly(mWriteSocket);
2804         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
2805 
2806         // Verify each metric fields in IpClientRaInfoMetrics.
2807         verify(mIpClientRaInfoMetrics).setMaxNumberOfDistinctRas(6);
2808         verify(mIpClientRaInfoMetrics).setNumberOfZeroLifetimeRas(4);
2809         verify(mIpClientRaInfoMetrics).setNumberOfParsingErrorRas(1);
2810         verify(mIpClientRaInfoMetrics).setLowestRouterLifetimeSeconds(routerLifetime);
2811         verify(mIpClientRaInfoMetrics).setLowestPioValidLifetimeSeconds(prefixValidLifetime);
2812         verify(mIpClientRaInfoMetrics).setLowestRioRouteLifetimeSeconds(routeLifetime);
2813         verify(mIpClientRaInfoMetrics).setLowestRdnssLifetimeSeconds(rdnssLifetime);
2814         verify(mIpClientRaInfoMetrics).statsWrite();
2815     }
2816 
2817     @Test
testNoMetricsWrittenForShortDuration()2818     public void testNoMetricsWrittenForShortDuration() throws Exception {
2819         final ApfConfiguration config = getDefaultConfig();
2820         final long startTimeMs = 12345;
2821         final long durationTimeMs = config.minMetricsSessionDurationMs;
2822 
2823         // Verify no metrics data written to statsd for duration less than durationTimeMs.
2824         doReturn(startTimeMs).when(mDependencies).elapsedRealtime();
2825         final ApfFilter apfFilter = getApfFilter(config);
2826         doReturn(startTimeMs + durationTimeMs - 1).when(mDependencies).elapsedRealtime();
2827         mHandler.post(apfFilter::shutdown);
2828         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
2829         verify(mApfSessionInfoMetrics, never()).statsWrite();
2830         verify(mIpClientRaInfoMetrics, never()).statsWrite();
2831 
2832         // Verify metrics data written to statsd for duration greater than or equal to
2833         // durationTimeMs.
2834         doReturn(startTimeMs).when(mDependencies).elapsedRealtime();
2835         final ApfFilter apfFilter2 = getApfFilter(config);
2836         doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime();
2837         mHandler.post(apfFilter2::shutdown);
2838         HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
2839         verify(mApfSessionInfoMetrics).statsWrite();
2840         verify(mIpClientRaInfoMetrics).statsWrite();
2841     }
2842 
deriveApfGeneratorVersion(ApfV4GeneratorBase<?> gen)2843     private int deriveApfGeneratorVersion(ApfV4GeneratorBase<?> gen) {
2844         if (gen instanceof ApfV4Generator) {
2845             return 4;
2846         } else if (gen instanceof ApfV6Generator) {
2847             return 6;
2848         }
2849         return -1;
2850     }
2851 
2852     @Test
testApfGeneratorPropagation()2853     public void testApfGeneratorPropagation() throws IllegalInstructionException {
2854         ApfV4Generator v4Gen = new ApfV4Generator(APF_VERSION_3, 1024 /* ramSize */,
2855                 1024 /* clampSize */);
2856         ApfV6Generator v6Gen = new ApfV6Generator(APF_VERSION_6, 1024 /* ramSize */,
2857                 1024 /* clampSize */);
2858         assertEquals(4, deriveApfGeneratorVersion(v4Gen));
2859         assertEquals(6, deriveApfGeneratorVersion(v6Gen));
2860     }
2861 
2862     @Test
testFullApfV4ProgramGenerationIPV6()2863     public void testFullApfV4ProgramGenerationIPV6() throws IllegalInstructionException {
2864         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, 1024 /* ramSize */,
2865                 1024 /* clampSize */);
2866         gen.addLoadImmediate(R1, -4);
2867         gen.addLoadData(R0, 0);
2868         gen.addAdd(1);
2869         gen.addStoreData(R0, 0);
2870         gen.addLoad16intoR0(12);
2871         gen.addLoadImmediate(R1, -108);
2872         gen.addJumpIfR0LessThan(0x600, (short) -504);
2873         gen.addLoadImmediate(R1, -112);
2874         gen.addJumpIfR0Equals(0x88a2, (short) -504);
2875         gen.addJumpIfR0Equals(0x88a4, (short) -504);
2876         gen.addJumpIfR0Equals(0x88b8, (short) -504);
2877         gen.addJumpIfR0Equals(0x88cd, (short) -504);
2878         gen.addJumpIfR0Equals(0x88e1, (short) -504);
2879         gen.addJumpIfR0Equals(0x88e3, (short) -504);
2880         gen.addJumpIfR0NotEquals(0x806, (short) -116);
2881         gen.addLoadImmediate(R0, 14);
2882         gen.addLoadImmediate(R1, -36);
2883         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("000108000604"), (short) -498);
2884         gen.addLoad16intoR0(20);
2885         gen.addJumpIfR0Equals(0x1, (short) -102);
2886         gen.addLoadImmediate(R1, -40);
2887         gen.addJumpIfR0NotEquals(0x2, (short) -498);
2888         gen.addLoad32intoR0(28);
2889         gen.addLoadImmediate(R1, -116);
2890         gen.addJumpIfR0Equals(0x0, (short) -504);
2891         gen.addLoadImmediate(R0, 0);
2892         gen.addLoadImmediate(R1, -44);
2893         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -498);
2894 
2895         gen.defineLabel((short) -102);
2896         gen.addLoad32intoR0(38);
2897         gen.addLoadImmediate(R1, -64);
2898         gen.addJumpIfR0Equals(0x0, (short) -504);
2899         gen.addLoadImmediate(R1, -8);
2900         gen.addJump((short) -498);
2901 
2902         gen.defineLabel((short) -116);
2903         gen.addLoad16intoR0(12);
2904         gen.addJumpIfR0NotEquals(0x800, (short) -207);
2905         gen.addLoad8intoR0(23);
2906         gen.addJumpIfR0NotEquals(0x11, (short) -159);
2907         gen.addLoad16intoR0(20);
2908         gen.addJumpIfR0AnyBitsSet(0x1fff, (short) -159);
2909         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
2910         gen.addLoad16R1IndexedIntoR0(16);
2911         gen.addJumpIfR0NotEquals(0x44, (short) -159);
2912         gen.addLoadImmediate(R0, 50);
2913         gen.addAddR1ToR0();
2914         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("e212507c6345"), (short) -159);
2915         gen.addLoadImmediate(R1, -12);
2916         gen.addJump((short) -498);
2917 
2918         gen.defineLabel((short) -159);
2919         gen.addLoad8intoR0(30);
2920         gen.addAnd(240);
2921         gen.addLoadImmediate(R1, -84);
2922         gen.addJumpIfR0Equals(0xe0, (short) -504);
2923         gen.addLoadImmediate(R1, -76);
2924         gen.addLoad32intoR0(30);
2925         gen.addJumpIfR0Equals(0xffffffff, (short) -504);
2926         gen.addLoadImmediate(R1, -24);
2927         gen.addLoadImmediate(R0, 0);
2928         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -498);
2929         gen.addLoadImmediate(R1, -72);
2930         gen.addJump((short) -504);
2931         gen.addLoadImmediate(R1, -16);
2932         gen.addJump((short) -498);
2933 
2934         gen.defineLabel((short) -207);
2935         gen.addJumpIfR0Equals(0x86dd, (short) -231);
2936         gen.addLoadImmediate(R0, 0);
2937         gen.addLoadImmediate(R1, -48);
2938         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -498);
2939         gen.addLoadImmediate(R1, -56);
2940         gen.addJump((short) -504);
2941 
2942         gen.defineLabel((short) -231);
2943         gen.addLoad8intoR0(20);
2944         gen.addJumpIfR0Equals(0x3a, (short) -249);
2945         gen.addLoadImmediate(R1, -104);
2946         gen.addLoad8intoR0(38);
2947         gen.addJumpIfR0Equals(0xff, (short) -504);
2948         gen.addLoadImmediate(R1, -32);
2949         gen.addJump((short) -498);
2950 
2951         gen.defineLabel((short) -249);
2952         gen.addLoad8intoR0(54);
2953         gen.addLoadImmediate(R1, -88);
2954         gen.addJumpIfR0Equals(0x85, (short) -504);
2955         gen.addJumpIfR0NotEquals(0x88, (short) -283);
2956         gen.addLoadImmediate(R0, 38);
2957         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ff0200000000000000000000000000"), (short) -283);
2958         gen.addLoadImmediate(R1, -92);
2959         gen.addJump((short) -504);
2960 
2961         gen.defineLabel((short) -283);
2962         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE);
2963         gen.addJumpIfR0NotEquals(0xa6, (short) -496);
2964         gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
2965         gen.addJumpIfR0GreaterThan(0x254, (short) -496);
2966         gen.addLoadImmediate(R0, 0);
2967         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("e212507c6345648788fd6df086dd68"), (short) -496);
2968         gen.addLoadImmediate(R0, 18);
2969         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("00703afffe800000000000002a0079e10abc1539fe80000000000000e01250fffe7c63458600"), (short) -496);
2970         gen.addLoadImmediate(R0, 58);
2971         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("4000"), (short) -496);
2972         gen.addLoad16intoR0(60);
2973         gen.addJumpIfR0LessThan(0x254, (short) -496);
2974         gen.addLoadImmediate(R0, 62);
2975         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("0000000000000000"), (short) -496);
2976         gen.addLoadImmediate(R0, 78);
2977         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("19050000"), (short) -496);
2978         gen.addLoad32intoR0(82);
2979         gen.addJumpIfR0LessThan(0x254, (short) -496);
2980         gen.addLoadImmediate(R0, 86);
2981         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("2001486048600000000000000000646420014860486000000000000000000064"), (short) -496);
2982         gen.addLoadImmediate(R0, 118);
2983         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("030440c0"), (short) -496);
2984         gen.addLoad32intoR0(122);
2985         gen.addJumpIfR0LessThan(0x254, (short) -496);
2986         gen.addLoad32intoR0(126);
2987         gen.addJumpIfR0LessThan(0x254, (short) -496);
2988         gen.addLoadImmediate(R0, 130);
2989         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("00000000"), (short) -496);
2990         gen.addLoadImmediate(R0, 134);
2991         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("2a0079e10abc15390000000000000000"), (short) -496);
2992         gen.addLoadImmediate(R1, -60);
2993         gen.addJump((short) -504);
2994 
2995         gen.defineLabel((short) -496);
2996         gen.addLoadImmediate(R1, -28);
2997 
2998         gen.defineLabel((short) -498);
2999         gen.addLoadData(R0, 0);
3000         gen.addAdd(1);
3001         gen.addStoreData(R0, 0);
3002         gen.addJump(PASS_LABEL);
3003 
3004         gen.defineLabel((short) -504);
3005         gen.addLoadData(R0, 0);
3006         gen.addAdd(1);
3007         gen.addStoreData(R0, 0);
3008         gen.addJump(DROP_LABEL);
3009 
3010         byte[] program = gen.generate();
3011         final String programString = toHexString(program).toLowerCase();
3012         final String referenceProgramHexString = "6bfcb03a01b8120c6b949401e906006b907c01e288a27c01dd88a47c01d888b87c01d388cd7c01ce88e17c01c988e384004008066a0e6bdca401af000600010800060412147a1e016bd88401a300021a1c6b8c7c01a00000686bd4a4018c0006ffffffffffff1a266bc07c018900006bf874017e120c84005408000a17821f1112149c00181fffab0d2a108211446a3239a20506e212507c63456bf47401530a1e52f06bac7c014e00e06bb41a1e7e00000141ffffffff6be868a4012d0006ffffffffffff6bb874012e6bf07401237c001386dd686bd0a401100006ffffffffffff6bc87401110a147a0d3a6b980a267c010300ff6be072f90a366ba87af8858218886a26a2040fff02000000000000000000000000006ba472ddaa0e82d0a6aa0f8c00c9025468a2b60fe212507c6345648788fd6df086dd686a12a28b2600703afffe800000000000002a0079e10abc1539fe80000000000000e01250fffe7c634586006a3aa284024000123c94007d02546a3ea2700800000000000000006a4ea26704190500001a5294006002546a56a23b2020014860486000000000000000006464200148604860000000000000000000646a76a23204030440c01a7a94002b02541a7e94002402546c0082a21a04000000006c0086a204102a0079e10abc153900000000000000006bc472086be4b03a01b87206b03a01b87201";
3013         assertEquals(referenceProgramHexString, programString);
3014     }
3015 
3016     @Test
testFullApfV4ProgramGenerationIPV4()3017     public void testFullApfV4ProgramGenerationIPV4() throws IllegalInstructionException {
3018         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, 1024 /* ramSize */,
3019                 1024 /* clampSize */);
3020         gen.addLoadImmediate(R1, -4);
3021         gen.addLoadData(R0, 0);
3022         gen.addAdd(1);
3023         gen.addStoreData(R0, 0);
3024         gen.addLoad16intoR0(12);
3025         gen.addLoadImmediate(R1, -108);
3026         gen.addJumpIfR0LessThan(0x600, (short) -283);
3027         gen.addLoadImmediate(R1, -112);
3028         gen.addJumpIfR0Equals(0x88a2, (short) -283);
3029         gen.addJumpIfR0Equals(0x88a4, (short) -283);
3030         gen.addJumpIfR0Equals(0x88b8, (short) -283);
3031         gen.addJumpIfR0Equals(0x88cd, (short) -283);
3032         gen.addJumpIfR0Equals(0x88e1, (short) -283);
3033         gen.addJumpIfR0Equals(0x88e3, (short) -283);
3034         gen.addJumpIfR0NotEquals(0x806, (short) -109);
3035         gen.addLoadImmediate(R0, 14);
3036         gen.addLoadImmediate(R1, -36);
3037         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("000108000604"), (short) -277);
3038         gen.addLoad16intoR0(20);
3039         gen.addJumpIfR0Equals(0x1, (short) -94);
3040         gen.addLoadImmediate(R1, -40);
3041         gen.addJumpIfR0NotEquals(0x2, (short) -277);
3042         gen.addLoad32intoR0(28);
3043         gen.addLoadImmediate(R1, -116);
3044         gen.addJumpIfR0Equals(0x0, (short) -283);
3045         gen.addLoadImmediate(R0, 0);
3046         gen.addLoadImmediate(R1, -44);
3047         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -277);
3048 
3049         gen.defineLabel((short) -94);
3050         gen.addLoadImmediate(R0, 38);
3051         gen.addLoadImmediate(R1, -68);
3052         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("c0a801b3"), (short) -283);
3053         gen.addLoadImmediate(R1, -8);
3054         gen.addJump((short) -277);
3055 
3056         gen.defineLabel((short) -109);
3057         gen.addLoad16intoR0(12);
3058         gen.addJumpIfR0NotEquals(0x800, (short) -204);
3059         gen.addLoad8intoR0(23);
3060         gen.addJumpIfR0NotEquals(0x11, (short) -151);
3061         gen.addLoad16intoR0(20);
3062         gen.addJumpIfR0AnyBitsSet(0x1fff, (short) -151);
3063         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
3064         gen.addLoad16R1IndexedIntoR0(16);
3065         gen.addJumpIfR0NotEquals(0x44, (short) -151);
3066         gen.addLoadImmediate(R0, 50);
3067         gen.addAddR1ToR0();
3068         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("f683d58f832b"), (short) -151);
3069         gen.addLoadImmediate(R1, -12);
3070         gen.addJump((short) -277);
3071 
3072         gen.defineLabel((short) -151);
3073         gen.addLoad8intoR0(30);
3074         gen.addAnd(240);
3075         gen.addLoadImmediate(R1, -84);
3076         gen.addJumpIfR0Equals(0xe0, (short) -283);
3077         gen.addLoadImmediate(R1, -76);
3078         gen.addLoad32intoR0(30);
3079         gen.addJumpIfR0Equals(0xffffffff, (short) -283);
3080         gen.addLoadImmediate(R1, -80);
3081         gen.addJumpIfR0Equals(0xc0a801ff, (short) -283);
3082         gen.addLoadImmediate(R1, -24);
3083         gen.addLoadImmediate(R0, 0);
3084         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -277);
3085         gen.addLoadImmediate(R1, -72);
3086         gen.addJump((short) -283);
3087         gen.addLoadImmediate(R1, -16);
3088         gen.addJump((short) -277);
3089 
3090         gen.defineLabel((short) -204);
3091         gen.addJumpIfR0Equals(0x86dd, (short) -225);
3092         gen.addLoadImmediate(R0, 0);
3093         gen.addLoadImmediate(R1, -48);
3094         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), (short) -277);
3095         gen.addLoadImmediate(R1, -56);
3096         gen.addJump((short) -283);
3097 
3098         gen.defineLabel((short) -225);
3099         gen.addLoad8intoR0(20);
3100         gen.addJumpIfR0Equals(0x3a, (short) -241);
3101         gen.addLoadImmediate(R1, -104);
3102         gen.addLoad8intoR0(38);
3103         gen.addJumpIfR0Equals(0xff, (short) -283);
3104         gen.addLoadImmediate(R1, -32);
3105         gen.addJump((short) -277);
3106 
3107         gen.defineLabel((short) -241);
3108         gen.addLoad8intoR0(54);
3109         gen.addLoadImmediate(R1, -88);
3110         gen.addJumpIfR0Equals(0x85, (short) -283);
3111         gen.addJumpIfR0NotEquals(0x88, (short) -275);
3112         gen.addLoadImmediate(R0, 38);
3113         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ff0200000000000000000000000000"), (short) -275);
3114         gen.addLoadImmediate(R1, -92);
3115         gen.addJump((short) -283);
3116 
3117         gen.defineLabel((short) -275);
3118         gen.addLoadImmediate(R1, -28);
3119 
3120         gen.defineLabel((short) -277);
3121         gen.addLoadData(R0, 0);
3122         gen.addAdd(1);
3123         gen.addStoreData(R0, 0);
3124         gen.addJump(PASS_LABEL);
3125 
3126         gen.defineLabel((short) -283);
3127         gen.addLoadData(R0, 0);
3128         gen.addAdd(1);
3129         gen.addStoreData(R0, 0);
3130         gen.addJump(DROP_LABEL);
3131 
3132         byte[] program = gen.generate();
3133         final String programString = toHexString(program).toLowerCase();
3134         final String referenceProgramHexString = "6bfcb03a01b8120c6b9494010c06006b907c010588a27c010088a47c00fb88b87c00f688cd7c00f188e17c00ec88e384003908066a0e6bdca2d40600010800060412147a18016bd882ca021a1c6b8c7ac900686bd4a2b706ffffffffffff6a266bbca2b204c0a801b36bf872a8120c84005808000a17821e1112149c00171fffab0d2a108210446a3239a20406f683d58f832b6bf4727e0a1e52f06bac7a7be06bb41a1e7e0000006effffffff6bb07e00000063c0a801ff6be868a25106ffffffffffff6bb872536bf072497c001086dd686bd0a23806ffffffffffff6bc8723a0a147a0b3a6b980a267a2eff6be072240a366ba87a23858218886a26a2040fff02000000000000000000000000006ba472086be4b03a01b87206b03a01b87201";
3135         assertEquals(referenceProgramHexString, programString);
3136     }
3137 
3138     @Test
testFullApfV4ProgramGenerationNatTKeepAliveV4()3139     public void testFullApfV4ProgramGenerationNatTKeepAliveV4() throws IllegalInstructionException {
3140         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, mRamSize, mClampSize, true);
3141         gen.addLoadImmediate(R1, -4);
3142         gen.addLoadData(R0, 0);
3143         gen.addAdd(1);
3144         gen.addStoreData(R0, 0);
3145         gen.addLoad16intoR0(12);
3146         gen.addCountAndDropIfR0LessThan(0x600, getCounterEnumFromOffset(-108));
3147         gen.addLoadImmediate(R1, -112);
3148         gen.addJumpIfR0Equals(0x88a2, gen.mCountAndDropLabel);
3149         gen.addJumpIfR0Equals(0x88a4, gen.mCountAndDropLabel);
3150         gen.addJumpIfR0Equals(0x88b8, gen.mCountAndDropLabel);
3151         gen.addJumpIfR0Equals(0x88cd, gen.mCountAndDropLabel);
3152         gen.addJumpIfR0Equals(0x88e1, gen.mCountAndDropLabel);
3153         gen.addJumpIfR0Equals(0x88e3, gen.mCountAndDropLabel);
3154         gen.addJumpIfR0NotEquals(0x806, (short) -115);
3155         gen.addLoadImmediate(R0, 14);
3156         gen.addCountAndPassIfBytesAtR0NotEqual(hexStringToByteArray("000108000604"), getCounterEnumFromOffset(-36));
3157         gen.addLoad16intoR0(20);
3158         gen.addJumpIfR0Equals(0x1, (short) -100);
3159         gen.addCountAndPassIfR0NotEquals(0x2, getCounterEnumFromOffset(-40));
3160         gen.addLoad32intoR0(28);
3161         gen.addCountAndDropIfR0Equals(0x0, getCounterEnumFromOffset(-116));
3162         gen.addLoadImmediate(R0, 0);
3163         gen.addCountAndPassIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), getCounterEnumFromOffset(-44));
3164 
3165         gen.defineLabel((short) -100);
3166         gen.addLoadImmediate(R0, 38);
3167         gen.addCountAndDropIfBytesAtR0NotEqual(hexStringToByteArray("c0a801be"), getCounterEnumFromOffset(-68));
3168         gen.addCountAndPass(getCounterEnumFromOffset(-8));
3169 
3170         gen.defineLabel((short) -115);
3171         gen.addLoad16intoR0(12);
3172         gen.addJumpIfR0NotEquals(0x800, (short) -263);
3173         gen.addLoad8intoR0(23);
3174         gen.addJumpIfR0NotEquals(0x11, (short) -157);
3175         gen.addLoad16intoR0(20);
3176         gen.addJumpIfR0AnyBitsSet(0x1fff, (short) -157);
3177         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
3178         gen.addLoad16R1IndexedIntoR0(16);
3179         gen.addJumpIfR0NotEquals(0x44, (short) -157);
3180         gen.addLoadImmediate(R0, 50);
3181         gen.addAddR1ToR0();
3182         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ea42226789c0"), (short) -157);
3183         gen.addCountAndPass(getCounterEnumFromOffset(-12));
3184 
3185         gen.defineLabel((short) -157);
3186         gen.addLoad8intoR0(30);
3187         gen.addAnd(240);
3188         gen.addCountAndDropIfR0Equals(0xe0, getCounterEnumFromOffset(-84));
3189         gen.addLoadImmediate(R1, -76);
3190         gen.addLoad32intoR0(30);
3191         gen.addJumpIfR0Equals(0xffffffff, gen.mCountAndDropLabel);
3192         gen.addCountAndDropIfR0Equals(0xc0a801ff, getCounterEnumFromOffset(-80));
3193         gen.addLoad8intoR0(23);
3194         gen.addJumpIfR0NotEquals(0x11, (short) -243);
3195         gen.addLoadImmediate(R0, 26);
3196         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("6b7a1f1fc0a801be"), (short) -243);
3197         gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
3198         gen.addAdd(8);
3199         gen.addSwap();
3200         gen.addLoad16intoR0(16);
3201         gen.addNeg(R1);
3202         gen.addAddR1ToR0();
3203         gen.addJumpIfR0NotEquals(0x1, (short) -243);
3204         gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
3205         gen.addAdd(14);
3206         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("1194ceca"), (short) -243);
3207         gen.addAdd(8);
3208         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ff"), (short) -243);
3209         gen.addCountAndDrop(getCounterEnumFromOffset(-128));
3210 
3211         gen.defineLabel((short) -243);
3212         gen.addLoadImmediate(R1, -24);
3213         gen.addLoadImmediate(R0, 0);
3214         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), gen.mCountAndPassLabel);
3215         gen.addCountAndDrop(getCounterEnumFromOffset(-72));
3216         gen.addCountAndPass(getCounterEnumFromOffset(-16));
3217 
3218         gen.defineLabel((short) -263);
3219         gen.addJumpIfR0Equals(0x86dd, (short) -284);
3220         gen.addLoadImmediate(R0, 0);
3221         gen.addCountAndPassIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), getCounterEnumFromOffset(-48));
3222         gen.addCountAndDrop(getCounterEnumFromOffset(-56));
3223 
3224         gen.defineLabel((short) -284);
3225         gen.addLoad8intoR0(20);
3226         gen.addJumpIfR0Equals(0x0, gen.mCountAndPassLabel);
3227         gen.addJumpIfR0Equals(0x3a, (short) -303);
3228         gen.addLoadImmediate(R1, -104);
3229         gen.addLoad8intoR0(38);
3230         gen.addJumpIfR0Equals(0xff, gen.mCountAndDropLabel);
3231         gen.addCountAndPass(getCounterEnumFromOffset(-32));
3232 
3233         gen.defineLabel((short) -303);
3234         gen.addLoad8intoR0(54);
3235         gen.addLoadImmediate(R1, -88);
3236         gen.addJumpIfR0Equals(0x85, gen.mCountAndDropLabel);
3237         gen.addJumpIfR0NotEquals(0x88, (short) -337);
3238         gen.addLoadImmediate(R0, 38);
3239         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ff0200000000000000000000000000"), (short) -337);
3240         gen.addCountAndDrop(getCounterEnumFromOffset(-92));
3241 
3242         gen.defineLabel((short) -337);
3243         gen.addLoadImmediate(R1, -28);
3244 
3245         gen.addCountTrampoline();
3246 
3247         byte[] program = gen.generate();
3248         final String programString = toHexString(program).toLowerCase();
3249         final String referenceProgramHexString = "6bfcb03a01b8120c6b9494014a06006b907c014388a27c013e88a47c013988b87c013488cd7c012f88e17c012a88e384003f08066a0e6bdca40110000600010800060412147a1c016bd884010400021a1c6b8c7c01010000686bd4a2ef06ffffffffffff6a266bbca2ea04c0a801be6bf872e0120c84008d08000a17821e1112149c00171fffab0d2a108210446a3239a20406ea42226789c06bf472b60a1e52f06bac7ab3e06bb41a1e7e000000a6ffffffff6bb07e0000009bc0a801ff0a178230116a1aa223086b7a1f1fc0a801beaa0d3a08aa221210ab2139821501aa0d3a0ea20a041194ceca3a08a20401ff6b8072666be868a25406ffffffffffff6bb872566bf0724c7c001086dd686bd0a23b06ffffffffffff6bc8723d0a147a32007a0b3a6b980a267a2eff6be072240a366ba87a23858218886a26a2040fff02000000000000000000000000006ba472086be4b03a01b87206b03a01b87201";
3250         assertEquals(referenceProgramHexString, programString);
3251     }
3252 
3253     @Test
testInfiniteLifetimeFullApfV4ProgramGeneration()3254     public void testInfiniteLifetimeFullApfV4ProgramGeneration() throws IllegalInstructionException {
3255         ApfV4Generator gen = new ApfV4Generator(APF_VERSION_3, 1024 /* ramSize */,
3256                 1024 /* clampSize */, true);
3257         gen.addLoadCounter(R0, getCounterEnumFromOffset(-8));
3258         gen.addAdd(1);
3259         gen.addStoreData(R0, 0);
3260         gen.addLoad16intoR0(12);
3261         gen.addCountAndDropIfR0LessThan(0x600, getCounterEnumFromOffset(-120));
3262         gen.addLoadImmediate(R1, -124);
3263         gen.addJumpIfR0Equals(0x88a2, gen.mCountAndDropLabel);
3264         gen.addJumpIfR0Equals(0x88a4, gen.mCountAndDropLabel);
3265         gen.addJumpIfR0Equals(0x88b8, gen.mCountAndDropLabel);
3266         gen.addJumpIfR0Equals(0x88cd, gen.mCountAndDropLabel);
3267         gen.addJumpIfR0Equals(0x88e1, gen.mCountAndDropLabel);
3268         gen.addJumpIfR0Equals(0x88e3, gen.mCountAndDropLabel);
3269         gen.addJumpIfR0NotEquals(0x806, (short) -122);
3270         gen.addLoadImmediate(R0, 14);
3271         gen.addCountAndDropIfBytesAtR0NotEqual(hexStringToByteArray("000108000604"), getCounterEnumFromOffset(-152));
3272         gen.addLoad16intoR0(20);
3273         gen.addJumpIfR0Equals(0x1, (short) -104);
3274         gen.addCountAndDropIfR0NotEquals(0x2, getCounterEnumFromOffset(-156));
3275         gen.addLoad32intoR0(28);
3276         gen.addCountAndDropIfR0Equals(0x0, getCounterEnumFromOffset(-128));
3277         gen.addLoadImmediate(R0, 0);
3278         gen.addCountAndPassIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), getCounterEnumFromOffset(-56));
3279 
3280         gen.defineLabel((short) -104);
3281         gen.addLoadImmediate(R0, 38);
3282         gen.addCountAndDropIfBytesAtR0NotEqual(hexStringToByteArray("c0a801ec"), getCounterEnumFromOffset(-80));
3283         gen.addCountAndPass(getCounterEnumFromOffset(-20));
3284 
3285         gen.defineLabel((short) -122);
3286         gen.addLoad16intoR0(12);
3287         gen.addJumpIfR0NotEquals(0x800, (short) -249);
3288         gen.addLoad8intoR0(23);
3289         gen.addJumpIfR0NotEquals(0x11, (short) -165);
3290         gen.addLoad16intoR0(20);
3291         gen.addJumpIfR0AnyBitsSet(0x1fff, (short) -165);
3292         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
3293         gen.addLoad16R1IndexedIntoR0(16);
3294         gen.addJumpIfR0NotEquals(0x44, (short) -165);
3295         gen.addLoadImmediate(R0, 50);
3296         gen.addAddR1ToR0();
3297         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("7e9046bc7008"), (short) -165);
3298         gen.addCountAndPass(getCounterEnumFromOffset(-24));
3299 
3300         gen.defineLabel((short) -165);
3301         gen.addLoad8intoR0(30);
3302         gen.addAnd(240);
3303         gen.addCountAndDropIfR0Equals(0xe0, getCounterEnumFromOffset(-96));
3304         gen.addLoadImmediate(R1, -88);
3305         gen.addLoad32intoR0(30);
3306         gen.addJumpIfR0Equals(0xffffffff, gen.mCountAndDropLabel);
3307         gen.addCountAndDropIfR0Equals(0xc0a801ff, getCounterEnumFromOffset(-92));
3308         gen.addLoad8intoR0(23);
3309         gen.addJumpIfR0NotEquals(0x6, (short) -225);
3310         gen.addLoad16intoR0(20);
3311         gen.addJumpIfR0AnyBitsSet(0x1fff, (short) -225);
3312         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
3313         gen.addLoad16R1IndexedIntoR0(16);
3314         gen.addJumpIfR0NotEquals(0x7, (short) -225);
3315         gen.addCountAndDrop(getCounterEnumFromOffset(-148));
3316 
3317         gen.defineLabel((short) -225);
3318         gen.addLoadImmediate(R1, -36);
3319         gen.addLoadImmediate(R0, 0);
3320         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), gen.mCountAndPassLabel);
3321         gen.addCountAndDrop(getCounterEnumFromOffset(-84));
3322         gen.addCountAndPass(getCounterEnumFromOffset(-28));
3323 
3324         gen.defineLabel((short) -249);
3325         gen.addJumpIfR0Equals(0x86dd, (short) -273);
3326         gen.addLoadImmediate(R0, 0);
3327         gen.addCountAndPassIfBytesAtR0NotEqual(hexStringToByteArray("ffffffffffff"), getCounterEnumFromOffset(-60));
3328         gen.addCountAndDrop(getCounterEnumFromOffset(-68));
3329 
3330         gen.defineLabel((short) -273);
3331         gen.addLoad8intoR0(20);
3332         gen.addJumpIfR0Equals(0x0, gen.mCountAndPassLabel);
3333         gen.addJumpIfR0Equals(0x3a, (short) -297);
3334         gen.addLoadImmediate(R1, -116);
3335         gen.addLoad8intoR0(38);
3336         gen.addJumpIfR0Equals(0xff, gen.mCountAndDropLabel);
3337         gen.addCountAndPass(getCounterEnumFromOffset(-44));
3338 
3339         gen.defineLabel((short) -297);
3340         gen.addLoad8intoR0(54);
3341         gen.addCountAndDropIfR0Equals(0x85, getCounterEnumFromOffset(-100));
3342         gen.addJumpIfR0NotEquals(0x88, (short) -333);
3343         gen.addLoadImmediate(R0, 38);
3344         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("ff0200000000000000000000000000"), (short) -333);
3345         gen.addCountAndDrop(getCounterEnumFromOffset(-104));
3346 
3347         gen.defineLabel((short) -333);
3348         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE);
3349         gen.addJumpIfR0NotEquals(0x96, (short) -574);
3350         gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
3351         gen.addJumpIfR0GreaterThan(0x48e, (short) -574);
3352         gen.addLoadImmediate(R0, 0);
3353         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("7e9046bc700828c68e23672c86dd60"), (short) -574);
3354         gen.addLoadImmediate(R0, 18);
3355         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("00603afffe800000000000002ac68efffe23672c"), (short) -574);
3356         gen.addLoadImmediate(R0, 54);
3357         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("8600"), (short) -574);
3358         gen.addLoadImmediate(R0, 58);
3359         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("40c0"), (short) -574);
3360         gen.addLoad16intoR0(60);
3361         gen.addJumpIfR0Equals(0x0, (short) -574);
3362         gen.addJumpIfR0LessThan(0xb4, (short) -421);
3363         gen.addJumpIfR0LessThan(0x91e, (short) -574);
3364         gen.addJumpIfR0GreaterThan(0x1b58, (short) -574);
3365 
3366         gen.defineLabel((short) -421);
3367         gen.addLoadImmediate(R0, 62);
3368         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("0000000000000000010128c68e23672c05010000000005dc030440c0"), (short) -574);
3369         gen.addLoad32intoR0(90);
3370         gen.addJumpIfR0Equals(0x0, (short) -574);
3371         gen.addJumpIfR0LessThan(0xb4, (short) -480);
3372         gen.addJumpIfR0LessThan(0x55555555, (short) -574);
3373         gen.addJumpIfR0GreaterThan(0xffffffffL, (short) -574);
3374 
3375         gen.defineLabel((short) -480);
3376         gen.addLoad32intoR0(94);
3377         gen.addJumpIfR0LessThan(0x55555555, (short) -574);
3378         gen.addJumpIfR0GreaterThan(0xffffffffL, (short) -574);
3379         gen.addLoadImmediate(R0, 98);
3380         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("000000002401fa000480f000000000000000000019030000"), (short) -574);
3381         gen.addLoad32intoR0(122);
3382         gen.addJumpIfR0Equals(0x0, (short) -574);
3383         gen.addJumpIfR0LessThan(0x78, (short) -547);
3384         gen.addJumpIfR0LessThan(0x91e, (short) -574);
3385         gen.addJumpIfR0GreaterThan(0x1b58, (short) -574);
3386 
3387         gen.defineLabel((short) -547);
3388         gen.addLoadImmediate(R0, 126);
3389         gen.addJumpIfBytesAtR0NotEqual(hexStringToByteArray("2401fa000480f00000000000000000010701"), (short) -574);
3390         gen.addCountAndDrop(getCounterEnumFromOffset(-72));
3391 
3392         gen.defineLabel((short) -574);
3393         gen.addLoadImmediate(R1, -40);
3394 
3395         gen.addCountTrampoline();
3396 
3397         byte[] program = gen.generate();
3398         final String programString = toHexString(program).toLowerCase();
3399         final String referenceProgramHexString = "6bf8b03a01b8120c6b8894023706006b847c023088a27c022b88a47c022688b87c022188cd7c021c88e17c021788e384004608066a0e6dff68a40202000600010800060412147a1f016dff648401f500021a1c6b807c01ec0000686bc8a401d80006ffffffffffff6a266bb0a401d10004c0a801ec6bec7401c6120c84007808000a17821f1112149c00181fffab0d2a108211446a3239a205067e9046bc70086be874019b0a1e52f06ba07c019600e06ba81a1e7e00000189ffffffff6ba47e0000017ec0a801ff0a1782140612149c000d1fffab0d2a108206076dff6c7401656bdc68a401510006ffffffffffff6bac7401526be47401477c001386dd686bc4a401340006ffffffffffff6bbc7401350a147c012800007a0e3a6b8c0a267c012200ff6bd47401170a366b9c7c011400858218886a26a2040fff02000000000000000000000000006b9872f9aa0e82ec96aa0f8c00e5048e68a2d20f7e9046bc700828c68e23672c86dd606a12a2b91400603afffe800000000000002ac68efffe23672c6a36a2b20286006a3aa2ab0240c0123c7aa600920ab494009e091e8c00991b586a3ea2781c0000000000000000010128c68e23672c05010000000005dc030440c01a5a7a73009212b49600000067555555558e0000005effffffff1a5e9600000053555555558e0000004affffffff6a62a22d18000000002401fa000480f0000000000000000000190300001a7a7a2800920a78940020091e8c001b1b586a7ea204122401fa000480f000000000000000000107016bb872086bd8b03a01b87206b03a01b87201";
3400         assertEquals(referenceProgramHexString, programString);
3401     }
3402 }
3403