ApfTest.java revision 38db976514ff2ad12d207a927219762eab179882
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
17package android.net.apf;
18
19import static android.system.OsConstants.*;
20
21import com.android.frameworks.servicestests.R;
22
23import android.net.apf.ApfCapabilities;
24import android.net.apf.ApfFilter;
25import android.net.apf.ApfGenerator;
26import android.net.apf.ApfGenerator.IllegalInstructionException;
27import android.net.apf.ApfGenerator.Register;
28import android.net.ip.IpManager;
29import android.net.metrics.IpConnectivityLog;
30import android.net.metrics.RaEvent;
31import android.net.LinkAddress;
32import android.net.LinkProperties;
33import android.os.ConditionVariable;
34import android.os.Parcelable;
35import android.system.ErrnoException;
36import android.system.Os;
37import android.test.AndroidTestCase;
38import android.test.suitebuilder.annotation.LargeTest;
39
40import org.mockito.ArgumentCaptor;
41import org.mockito.Mock;
42import org.mockito.MockitoAnnotations;
43import static org.mockito.Mockito.atLeastOnce;
44import static org.mockito.Mockito.verify;
45
46import java.io.File;
47import java.io.FileDescriptor;
48import java.io.FileOutputStream;
49import java.io.IOException;
50import java.io.InputStream;
51import java.io.OutputStream;
52import java.net.InetAddress;
53import java.net.NetworkInterface;
54import java.nio.ByteBuffer;
55import java.util.List;
56
57import libcore.io.IoUtils;
58import libcore.io.Streams;
59
60/**
61 * Tests for APF program generator and interpreter.
62 *
63 * Build, install and run with:
64 *  runtest frameworks-services -c com.android.server.ApfTest
65 */
66public class ApfTest extends AndroidTestCase {
67    private static final int TIMEOUT_MS = 500;
68
69    @Mock IpConnectivityLog mLog;
70
71    @Override
72    public void setUp() throws Exception {
73        super.setUp();
74        MockitoAnnotations.initMocks(this);
75        // Load up native shared library containing APF interpreter exposed via JNI.
76        System.loadLibrary("servicestestsjni");
77    }
78
79    // Expected return codes from APF interpreter.
80    private final static int PASS = 1;
81    private final static int DROP = 0;
82    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
83    // least the minimum packet size.
84    private final static int MIN_PKT_SIZE = 15;
85
86    private final static boolean DROP_MULTICAST = true;
87    private final static boolean ALLOW_MULTICAST = false;
88
89    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
90        assertEquals(expected, apfSimulate(program, packet, filterAge));
91    }
92
93    private void assertPass(byte[] program, byte[] packet, int filterAge) {
94        assertVerdict(PASS, program, packet, filterAge);
95    }
96
97    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
98        assertVerdict(DROP, program, packet, filterAge);
99    }
100
101    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
102            throws IllegalInstructionException {
103        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
104    }
105
106    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
107            throws IllegalInstructionException {
108        assertVerdict(PASS, gen, packet, filterAge);
109    }
110
111    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
112            throws IllegalInstructionException {
113        assertVerdict(DROP, gen, packet, filterAge);
114    }
115
116    private void assertPass(ApfGenerator gen)
117            throws IllegalInstructionException {
118        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
119    }
120
121    private void assertDrop(ApfGenerator gen)
122            throws IllegalInstructionException {
123        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
124    }
125
126    /**
127     * Test each instruction by generating a program containing the instruction,
128     * generating bytecode for that program and running it through the
129     * interpreter to verify it functions correctly.
130     */
131    @LargeTest
132    public void testApfInstructions() throws IllegalInstructionException {
133        // Empty program should pass because having the program counter reach the
134        // location immediately after the program indicates the packet should be
135        // passed to the AP.
136        ApfGenerator gen = new ApfGenerator();
137        assertPass(gen);
138
139        // Test jumping to pass label.
140        gen = new ApfGenerator();
141        gen.addJump(gen.PASS_LABEL);
142        byte[] program = gen.generate();
143        assertEquals(1, program.length);
144        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
145        assertPass(program, new byte[MIN_PKT_SIZE], 0);
146
147        // Test jumping to drop label.
148        gen = new ApfGenerator();
149        gen.addJump(gen.DROP_LABEL);
150        program = gen.generate();
151        assertEquals(2, program.length);
152        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
153        assertEquals(1, program[1]);
154        assertDrop(program, new byte[15], 15);
155
156        // Test jumping if equal to 0.
157        gen = new ApfGenerator();
158        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
159        assertDrop(gen);
160
161        // Test jumping if not equal to 0.
162        gen = new ApfGenerator();
163        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
164        assertPass(gen);
165        gen = new ApfGenerator();
166        gen.addLoadImmediate(Register.R0, 1);
167        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
168        assertDrop(gen);
169
170        // Test jumping if registers equal.
171        gen = new ApfGenerator();
172        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
173        assertDrop(gen);
174
175        // Test jumping if registers not equal.
176        gen = new ApfGenerator();
177        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
178        assertPass(gen);
179        gen = new ApfGenerator();
180        gen.addLoadImmediate(Register.R0, 1);
181        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
182        assertDrop(gen);
183
184        // Test load immediate.
185        gen = new ApfGenerator();
186        gen.addLoadImmediate(Register.R0, 1234567890);
187        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
188        assertDrop(gen);
189
190        // Test add.
191        gen = new ApfGenerator();
192        gen.addAdd(1234567890);
193        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
194        assertDrop(gen);
195
196        // Test subtract.
197        gen = new ApfGenerator();
198        gen.addAdd(-1234567890);
199        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
200        assertDrop(gen);
201
202        // Test or.
203        gen = new ApfGenerator();
204        gen.addOr(1234567890);
205        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
206        assertDrop(gen);
207
208        // Test and.
209        gen = new ApfGenerator();
210        gen.addLoadImmediate(Register.R0, 1234567890);
211        gen.addAnd(123456789);
212        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
213        assertDrop(gen);
214
215        // Test left shift.
216        gen = new ApfGenerator();
217        gen.addLoadImmediate(Register.R0, 1234567890);
218        gen.addLeftShift(1);
219        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
220        assertDrop(gen);
221
222        // Test right shift.
223        gen = new ApfGenerator();
224        gen.addLoadImmediate(Register.R0, 1234567890);
225        gen.addRightShift(1);
226        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
227        assertDrop(gen);
228
229        // Test multiply.
230        gen = new ApfGenerator();
231        gen.addLoadImmediate(Register.R0, 1234567890);
232        gen.addMul(2);
233        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
234        assertDrop(gen);
235
236        // Test divide.
237        gen = new ApfGenerator();
238        gen.addLoadImmediate(Register.R0, 1234567890);
239        gen.addDiv(2);
240        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
241        assertDrop(gen);
242
243        // Test divide by zero.
244        gen = new ApfGenerator();
245        gen.addDiv(0);
246        gen.addJump(gen.DROP_LABEL);
247        assertPass(gen);
248
249        // Test add.
250        gen = new ApfGenerator();
251        gen.addLoadImmediate(Register.R1, 1234567890);
252        gen.addAddR1();
253        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
254        assertDrop(gen);
255
256        // Test subtract.
257        gen = new ApfGenerator();
258        gen.addLoadImmediate(Register.R1, -1234567890);
259        gen.addAddR1();
260        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
261        assertDrop(gen);
262
263        // Test or.
264        gen = new ApfGenerator();
265        gen.addLoadImmediate(Register.R1, 1234567890);
266        gen.addOrR1();
267        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
268        assertDrop(gen);
269
270        // Test and.
271        gen = new ApfGenerator();
272        gen.addLoadImmediate(Register.R0, 1234567890);
273        gen.addLoadImmediate(Register.R1, 123456789);
274        gen.addAndR1();
275        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
276        assertDrop(gen);
277
278        // Test left shift.
279        gen = new ApfGenerator();
280        gen.addLoadImmediate(Register.R0, 1234567890);
281        gen.addLoadImmediate(Register.R1, 1);
282        gen.addLeftShiftR1();
283        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
284        assertDrop(gen);
285
286        // Test right shift.
287        gen = new ApfGenerator();
288        gen.addLoadImmediate(Register.R0, 1234567890);
289        gen.addLoadImmediate(Register.R1, -1);
290        gen.addLeftShiftR1();
291        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
292        assertDrop(gen);
293
294        // Test multiply.
295        gen = new ApfGenerator();
296        gen.addLoadImmediate(Register.R0, 1234567890);
297        gen.addLoadImmediate(Register.R1, 2);
298        gen.addMulR1();
299        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
300        assertDrop(gen);
301
302        // Test divide.
303        gen = new ApfGenerator();
304        gen.addLoadImmediate(Register.R0, 1234567890);
305        gen.addLoadImmediate(Register.R1, 2);
306        gen.addDivR1();
307        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
308        assertDrop(gen);
309
310        // Test divide by zero.
311        gen = new ApfGenerator();
312        gen.addDivR1();
313        gen.addJump(gen.DROP_LABEL);
314        assertPass(gen);
315
316        // Test byte load.
317        gen = new ApfGenerator();
318        gen.addLoad8(Register.R0, 1);
319        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
320        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
321
322        // Test out of bounds load.
323        gen = new ApfGenerator();
324        gen.addLoad8(Register.R0, 16);
325        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
326        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
327
328        // Test half-word load.
329        gen = new ApfGenerator();
330        gen.addLoad16(Register.R0, 1);
331        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
332        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
333
334        // Test word load.
335        gen = new ApfGenerator();
336        gen.addLoad32(Register.R0, 1);
337        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
338        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
339
340        // Test byte indexed load.
341        gen = new ApfGenerator();
342        gen.addLoadImmediate(Register.R1, 1);
343        gen.addLoad8Indexed(Register.R0, 0);
344        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
345        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
346
347        // Test out of bounds indexed load.
348        gen = new ApfGenerator();
349        gen.addLoadImmediate(Register.R1, 8);
350        gen.addLoad8Indexed(Register.R0, 8);
351        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
352        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
353
354        // Test half-word indexed load.
355        gen = new ApfGenerator();
356        gen.addLoadImmediate(Register.R1, 1);
357        gen.addLoad16Indexed(Register.R0, 0);
358        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
359        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
360
361        // Test word indexed load.
362        gen = new ApfGenerator();
363        gen.addLoadImmediate(Register.R1, 1);
364        gen.addLoad32Indexed(Register.R0, 0);
365        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
366        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
367
368        // Test jumping if greater than.
369        gen = new ApfGenerator();
370        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
371        assertPass(gen);
372        gen = new ApfGenerator();
373        gen.addLoadImmediate(Register.R0, 1);
374        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
375        assertDrop(gen);
376
377        // Test jumping if less than.
378        gen = new ApfGenerator();
379        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
380        assertPass(gen);
381        gen = new ApfGenerator();
382        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
383        assertDrop(gen);
384
385        // Test jumping if any bits set.
386        gen = new ApfGenerator();
387        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
388        assertPass(gen);
389        gen = new ApfGenerator();
390        gen.addLoadImmediate(Register.R0, 1);
391        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
392        assertDrop(gen);
393        gen = new ApfGenerator();
394        gen.addLoadImmediate(Register.R0, 3);
395        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
396        assertDrop(gen);
397
398        // Test jumping if register greater than.
399        gen = new ApfGenerator();
400        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
401        assertPass(gen);
402        gen = new ApfGenerator();
403        gen.addLoadImmediate(Register.R0, 2);
404        gen.addLoadImmediate(Register.R1, 1);
405        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
406        assertDrop(gen);
407
408        // Test jumping if register less than.
409        gen = new ApfGenerator();
410        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
411        assertPass(gen);
412        gen = new ApfGenerator();
413        gen.addLoadImmediate(Register.R1, 1);
414        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
415        assertDrop(gen);
416
417        // Test jumping if any bits set in register.
418        gen = new ApfGenerator();
419        gen.addLoadImmediate(Register.R1, 3);
420        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
421        assertPass(gen);
422        gen = new ApfGenerator();
423        gen.addLoadImmediate(Register.R1, 3);
424        gen.addLoadImmediate(Register.R0, 1);
425        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
426        assertDrop(gen);
427        gen = new ApfGenerator();
428        gen.addLoadImmediate(Register.R1, 3);
429        gen.addLoadImmediate(Register.R0, 3);
430        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
431        assertDrop(gen);
432
433        // Test load from memory.
434        gen = new ApfGenerator();
435        gen.addLoadFromMemory(Register.R0, 0);
436        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
437        assertDrop(gen);
438
439        // Test store to memory.
440        gen = new ApfGenerator();
441        gen.addLoadImmediate(Register.R1, 1234567890);
442        gen.addStoreToMemory(Register.R1, 12);
443        gen.addLoadFromMemory(Register.R0, 12);
444        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
445        assertDrop(gen);
446
447        // Test filter age pre-filled memory.
448        gen = new ApfGenerator();
449        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
450        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
451        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
452
453        // Test packet size pre-filled memory.
454        gen = new ApfGenerator();
455        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
456        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
457        assertDrop(gen);
458
459        // Test IPv4 header size pre-filled memory.
460        gen = new ApfGenerator();
461        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
462        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
463        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
464
465        // Test not.
466        gen = new ApfGenerator();
467        gen.addLoadImmediate(Register.R0, 1234567890);
468        gen.addNot(Register.R0);
469        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
470        assertDrop(gen);
471
472        // Test negate.
473        gen = new ApfGenerator();
474        gen.addLoadImmediate(Register.R0, 1234567890);
475        gen.addNeg(Register.R0);
476        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
477        assertDrop(gen);
478
479        // Test move.
480        gen = new ApfGenerator();
481        gen.addLoadImmediate(Register.R1, 1234567890);
482        gen.addMove(Register.R0);
483        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
484        assertDrop(gen);
485        gen = new ApfGenerator();
486        gen.addLoadImmediate(Register.R0, 1234567890);
487        gen.addMove(Register.R1);
488        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
489        assertDrop(gen);
490
491        // Test swap.
492        gen = new ApfGenerator();
493        gen.addLoadImmediate(Register.R1, 1234567890);
494        gen.addSwap();
495        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
496        assertDrop(gen);
497        gen = new ApfGenerator();
498        gen.addLoadImmediate(Register.R0, 1234567890);
499        gen.addSwap();
500        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
501        assertDrop(gen);
502
503        // Test jump if bytes not equal.
504        gen = new ApfGenerator();
505        gen.addLoadImmediate(Register.R0, 1);
506        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
507        program = gen.generate();
508        assertEquals(6, program.length);
509        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
510        assertEquals(1, program[1]);
511        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
512        assertEquals(1, program[3]);
513        assertEquals(1, program[4]);
514        assertEquals(123, program[5]);
515        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
516        gen = new ApfGenerator();
517        gen.addLoadImmediate(Register.R0, 1);
518        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
519        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
520        assertPass(gen, packet123, 0);
521        gen = new ApfGenerator();
522        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
523        assertDrop(gen, packet123, 0);
524        gen = new ApfGenerator();
525        gen.addLoadImmediate(Register.R0, 1);
526        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
527        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
528        assertDrop(gen, packet12345, 0);
529        gen = new ApfGenerator();
530        gen.addLoadImmediate(Register.R0, 1);
531        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
532        assertPass(gen, packet12345, 0);
533    }
534
535    /**
536     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
537     * over packet traces and verify both programs filter out the same packets.
538     */
539    @LargeTest
540    public void testApfAgainstBpf() throws Exception {
541        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
542                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
543                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
544                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
545        String pcap_filename = stageFile(R.raw.apf);
546        for (String tcpdump_filter : tcpdump_filters) {
547            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
548            assertTrue("Failed to match for filter: " + tcpdump_filter,
549                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
550        }
551    }
552
553    private class MockIpManagerCallback extends IpManager.Callback {
554        private final ConditionVariable mGotApfProgram = new ConditionVariable();
555        private byte[] mLastApfProgram;
556
557        @Override
558        public void installPacketFilter(byte[] filter) {
559            mLastApfProgram = filter;
560            mGotApfProgram.open();
561        }
562
563        public void resetApfProgramWait() {
564            mGotApfProgram.close();
565        }
566
567        public byte[] getApfProgram() {
568            assertTrue(mGotApfProgram.block(TIMEOUT_MS));
569            return mLastApfProgram;
570        }
571
572        public void assertNoProgramUpdate() {
573            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
574        }
575    }
576
577    private static class TestApfFilter extends ApfFilter {
578        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
579        private FileDescriptor mWriteSocket;
580
581        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
582                IpConnectivityLog log) throws Exception {
583            super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
584                    ipManagerCallback, multicastFilter, log);
585        }
586
587        // Pretend an RA packet has been received and show it to ApfFilter.
588        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
589            // ApfFilter's ReceiveThread will be waiting to read this.
590            Os.write(mWriteSocket, packet, 0, packet.length);
591        }
592
593        @Override
594        void maybeStartFilter() {
595            mHardwareAddress = MOCK_MAC_ADDR;
596            installNewProgramLocked();
597
598            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
599            FileDescriptor readSocket = new FileDescriptor();
600            mWriteSocket = new FileDescriptor();
601            try {
602                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
603            } catch (ErrnoException e) {
604                fail();
605                return;
606            }
607            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
608            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
609            mReceiveThread = new ReceiveThread(readSocket);
610            mReceiveThread.start();
611        }
612
613        @Override
614        public void shutdown() {
615            super.shutdown();
616            IoUtils.closeQuietly(mWriteSocket);
617        }
618    }
619
620    private static final int ETH_HEADER_LEN = 14;
621    private static final int ETH_DEST_ADDR_OFFSET = 0;
622    private static final int ETH_ETHERTYPE_OFFSET = 12;
623    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
624        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
625
626    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
627    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
628    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
629
630    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
631    private static final int IPV6_HEADER_LEN = 40;
632    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
633    // The IPv6 all nodes address ff02::1
634    private static final byte[] IPV6_ALL_NODES_ADDRESS =
635            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
636
637    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
638    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
639    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
640
641    private static final int ICMP6_RA_HEADER_LEN = 16;
642    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
643            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
644    private static final int ICMP6_RA_CHECKSUM_OFFSET =
645            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
646    private static final int ICMP6_RA_OPTION_OFFSET =
647            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
648
649    private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
650    private static final int ICMP6_PREFIX_OPTION_LEN = 32;
651    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
652    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
653
654    // From RFC6106: Recursive DNS Server option
655    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
656    // From RFC6106: DNS Search List option
657    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
658
659    // From RFC4191: Route Information option
660    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
661    // Above three options all have the same format:
662    private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
663    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
664    private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
665
666    private static final int UDP_HEADER_LEN = 8;
667    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
668
669    private static final int DHCP_CLIENT_PORT = 68;
670    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
671
672    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
673    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
674            0, 1, // Hardware type: Ethernet (1)
675            8, 0, // Protocol type: IP (0x0800)
676            6,    // Hardware size: 6
677            4,    // Protocol size: 4
678            0, 1  // Opcode: request (1)
679    };
680    private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
681            0, 1, // Hardware type: Ethernet (1)
682            8, 0, // Protocol type: IP (0x0800)
683            6,    // Hardware size: 6
684            4,    // Protocol size: 4
685            0, 2  // Opcode: reply (2)
686    };
687    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
688
689    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
690    private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
691    private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
692
693    @LargeTest
694    public void testApfFilterIPv4() throws Exception {
695        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
696        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
697        byte[] program = ipManagerCallback.getApfProgram();
698
699        // Verify empty packet of 100 zero bytes is passed
700        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
701        assertPass(program, packet.array(), 0);
702
703        // Verify unicast IPv4 packet is passed
704        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
705        assertPass(program, packet.array(), 0);
706
707        // Verify broadcast IPv4, not DHCP to us, is dropped
708        packet.put(ETH_BROADCAST_MAC_ADDRESS);
709        assertDrop(program, packet.array(), 0);
710        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
711        assertDrop(program, packet.array(), 0);
712        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
713        assertDrop(program, packet.array(), 0);
714        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
715        assertDrop(program, packet.array(), 0);
716
717        // Verify broadcast IPv4 DHCP to us is passed
718        packet.position(DHCP_CLIENT_MAC_OFFSET);
719        packet.put(TestApfFilter.MOCK_MAC_ADDR);
720        assertPass(program, packet.array(), 0);
721
722        apfFilter.shutdown();
723    }
724
725    @LargeTest
726    public void testApfFilterIPv6() throws Exception {
727        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
728        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
729        byte[] program = ipManagerCallback.getApfProgram();
730
731        // Verify empty IPv6 packet is passed
732        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
733        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
734        assertPass(program, packet.array(), 0);
735
736        // Verify empty ICMPv6 packet is passed
737        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
738        assertPass(program, packet.array(), 0);
739
740        // Verify empty ICMPv6 NA packet is passed
741        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
742        assertPass(program, packet.array(), 0);
743
744        // Verify ICMPv6 NA to ff02::1 is dropped
745        packet.position(IPV6_DEST_ADDR_OFFSET);
746        packet.put(IPV6_ALL_NODES_ADDRESS);
747        assertDrop(program, packet.array(), 0);
748
749        apfFilter.shutdown();
750    }
751
752    @LargeTest
753    public void testApfFilterMulticast() throws Exception {
754        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
755        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
756        byte[] program = ipManagerCallback.getApfProgram();
757
758        // Construct IPv4 and IPv6 multicast packets.
759        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
760        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
761        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
762        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
763
764        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
765        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
766        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
767        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
768        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
769
770        // Construct IPv4 broadcast packet.
771        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
772        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
773        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
774        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
775        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
776
777        // Verify initially disabled multicast filter is off
778        assertPass(program, bcastv4packet.array(), 0);
779        assertPass(program, mcastv4packet.array(), 0);
780        assertPass(program, mcastv6packet.array(), 0);
781
782        // Turn on multicast filter and verify it works
783        ipManagerCallback.resetApfProgramWait();
784        apfFilter.setMulticastFilter(true);
785        program = ipManagerCallback.getApfProgram();
786        assertDrop(program, bcastv4packet.array(), 0);
787        assertDrop(program, mcastv4packet.array(), 0);
788        assertDrop(program, mcastv6packet.array(), 0);
789
790        // Turn off multicast filter and verify it's off
791        ipManagerCallback.resetApfProgramWait();
792        apfFilter.setMulticastFilter(false);
793        program = ipManagerCallback.getApfProgram();
794        assertPass(program, bcastv4packet.array(), 0);
795        assertPass(program, mcastv4packet.array(), 0);
796        assertPass(program, mcastv6packet.array(), 0);
797
798        // Verify it can be initialized to on
799        ipManagerCallback.resetApfProgramWait();
800        apfFilter.shutdown();
801        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
802        program = ipManagerCallback.getApfProgram();
803        assertDrop(program, bcastv4packet.array(), 0);
804        assertDrop(program, mcastv4packet.array(), 0);
805        assertDrop(program, mcastv6packet.array(), 0);
806
807        // Verify that ICMPv6 multicast is not dropped.
808        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
809        assertPass(program, mcastv6packet.array(), 0);
810
811        apfFilter.shutdown();
812    }
813
814    private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
815        cb.resetApfProgramWait();
816        filter.setLinkProperties(lp);
817        return cb.getApfProgram();
818    }
819
820    private void verifyArpFilter(byte[] program, int filterResult) {
821        // Verify ARP request packet
822        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
823        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
824        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
825
826        // Verify unicast ARP reply packet is always accepted.
827        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
828        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
829        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
830
831        // Verify GARP reply packets are always filtered
832        assertDrop(program, garpReply(), 0);
833    }
834
835    @LargeTest
836    public void testApfFilterArp() throws Exception {
837        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
838        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
839
840        // Verify initially ARP request filter is off, and GARP filter is on.
841        verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
842
843        // Inform ApfFilter of our address and verify ARP filtering is on
844        LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
845        LinkProperties lp = new LinkProperties();
846        assertTrue(lp.addLinkAddress(linkAddress));
847        verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
848
849        // Inform ApfFilter of loss of IP and verify ARP filtering is off
850        verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
851
852        apfFilter.shutdown();
853    }
854
855    private static byte[] arpRequestBroadcast(byte[] tip) {
856        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
857        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
858        packet.position(ETH_DEST_ADDR_OFFSET);
859        packet.put(ETH_BROADCAST_MAC_ADDRESS);
860        packet.position(ARP_HEADER_OFFSET);
861        packet.put(ARP_IPV4_REQUEST_HEADER);
862        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
863        packet.put(tip);
864        return packet.array();
865    }
866
867    private static byte[] arpReplyUnicast(byte[] tip) {
868        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
869        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
870        packet.position(ARP_HEADER_OFFSET);
871        packet.put(ARP_IPV4_REPLY_HEADER);
872        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
873        packet.put(tip);
874        return packet.array();
875    }
876
877    private static byte[] garpReply() {
878        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
879        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
880        packet.position(ETH_DEST_ADDR_OFFSET);
881        packet.put(ETH_BROADCAST_MAC_ADDRESS);
882        packet.position(ARP_HEADER_OFFSET);
883        packet.put(ARP_IPV4_REPLY_HEADER);
884        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
885        packet.put(IPV4_ANY_HOST_ADDR);
886        return packet.array();
887    }
888
889    // Verify that the last program pushed to the IpManager.Callback properly filters the
890    // given packet for the given lifetime.
891    private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
892            int lifetime) {
893        byte[] program = ipManagerCallback.getApfProgram();
894
895        // Verify new program should drop RA for 1/6th its lifetime
896        assertDrop(program, packet.array(), 0);
897        assertDrop(program, packet.array(), lifetime/6);
898        assertPass(program, packet.array(), lifetime/6 + 1);
899        assertPass(program, packet.array(), lifetime);
900
901        // Verify RA checksum is ignored
902        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
903        assertDrop(program, packet.array(), 0);
904        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
905        assertDrop(program, packet.array(), 0);
906
907        // Verify other changes to RA make it not match filter
908        packet.put(0, (byte)-1);
909        assertPass(program, packet.array(), 0);
910        packet.put(0, (byte)0);
911        assertDrop(program, packet.array(), 0);
912    }
913
914    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
915    // for the given lifetime.
916    private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
917            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
918        // Verify new program generated if ApfFilter witnesses RA
919        ipManagerCallback.resetApfProgramWait();
920        apfFilter.pretendPacketReceived(packet.array());
921        ipManagerCallback.getApfProgram();
922
923        verifyRaLifetime(ipManagerCallback, packet, lifetime);
924    }
925
926    private void verifyRaEvent(RaEvent expected) {
927        ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class);
928        verify(mLog, atLeastOnce()).log(captor.capture());
929        RaEvent got = lastRaEvent(captor.getAllValues());
930        if (!raEventEquals(expected, got)) {
931            assertEquals(expected, got);  // fail for printing an assertion error message.
932        }
933    }
934
935    private RaEvent lastRaEvent(List<Parcelable> events) {
936        RaEvent got = null;
937        for (Parcelable ev : events) {
938            if (ev instanceof RaEvent) {
939                got = (RaEvent) ev;
940            }
941        }
942        return got;
943    }
944
945    private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
946        return (ev1 != null) && (ev2 != null)
947                && (ev1.routerLifetime == ev2.routerLifetime)
948                && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
949                && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
950                && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
951                && (ev1.rdnssLifetime == ev2.rdnssLifetime)
952                && (ev1.dnsslLifetime == ev2.dnsslLifetime);
953    }
954
955    private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
956            ByteBuffer packet) throws IOException, ErrnoException {
957        ipManagerCallback.resetApfProgramWait();
958        apfFilter.pretendPacketReceived(packet.array());
959        ipManagerCallback.assertNoProgramUpdate();
960    }
961
962    @LargeTest
963    public void testApfFilterRa() throws Exception {
964        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
965        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
966        byte[] program = ipManagerCallback.getApfProgram();
967
968        // Verify RA is passed the first time
969        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
970        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
971        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
972        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
973        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
974        basePacket.position(IPV6_DEST_ADDR_OFFSET);
975        basePacket.put(IPV6_ALL_NODES_ADDRESS);
976        assertPass(program, basePacket.array(), 0);
977
978        testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
979        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
980
981        // Ensure zero-length options cause the packet to be silently skipped.
982        // Do this before we test other packets. http://b/29586253
983        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
984                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
985        basePacket.clear();
986        zeroLengthOptionPacket.put(basePacket);
987        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
988        zeroLengthOptionPacket.put((byte)0);
989        assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket);
990
991        // Generate several RAs with different options and lifetimes, and verify when
992        // ApfFilter is shown these packets, it generates programs to filter them for the
993        // appropriate lifetime.
994        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
995                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
996        basePacket.clear();
997        prefixOptionPacket.put(basePacket);
998        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
999        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
1000        prefixOptionPacket.putInt(
1001                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100);
1002        prefixOptionPacket.putInt(
1003                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
1004        testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
1005        verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
1006
1007        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
1008                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1009        basePacket.clear();
1010        rdnssOptionPacket.put(basePacket);
1011        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
1012        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1013        rdnssOptionPacket.putInt(
1014                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
1015        testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
1016        verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
1017
1018        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
1019                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1020        basePacket.clear();
1021        routeInfoOptionPacket.put(basePacket);
1022        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
1023        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1024        routeInfoOptionPacket.putInt(
1025                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
1026        testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
1027        verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
1028
1029        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
1030                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1031        basePacket.clear();
1032        dnsslOptionPacket.put(basePacket);
1033        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
1034        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1035        dnsslOptionPacket.putInt(
1036                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000);
1037        // Note that lifetime of 2000 will be ignored in favor of shorter
1038        // route lifetime of 1000.
1039        testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
1040        verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
1041
1042        // Verify that current program filters all five RAs:
1043        verifyRaLifetime(ipManagerCallback, basePacket, 1000);
1044        verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100);
1045        verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300);
1046        verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400);
1047        verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000);
1048
1049        apfFilter.shutdown();
1050    }
1051
1052    /**
1053     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
1054     * copy that resource into the app's data directory and return the path to it.
1055     */
1056    private String stageFile(int rawId) throws Exception {
1057        File file = new File(getContext().getFilesDir(), "staged_file");
1058        new File(file.getParent()).mkdirs();
1059        InputStream in = null;
1060        OutputStream out = null;
1061        try {
1062            in = getContext().getResources().openRawResource(rawId);
1063            out = new FileOutputStream(file);
1064            Streams.copy(in, out);
1065        } finally {
1066            if (in != null) in.close();
1067            if (out != null) out.close();
1068        }
1069        return file.getAbsolutePath();
1070    }
1071
1072    /**
1073     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
1074     * filter was installed {@code filter_age} seconds ago.
1075     */
1076    private native static int apfSimulate(byte[] program, byte[] packet, int filter_age);
1077
1078    /**
1079     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
1080     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
1081     */
1082    private native static String compileToBpf(String filter);
1083
1084    /**
1085     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
1086     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
1087     * at the same time using APF program {@code apf_program}.  Return {@code true} if
1088     * both APF and BPF programs filter out exactly the same packets.
1089     */
1090    private native static boolean compareBpfApf(String filter, String pcap_filename,
1091            byte[] apf_program);
1092}
1093