1578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen/*
2578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Copyright (C) 2016 The Android Open Source Project
3578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen *
4578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License");
5578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * you may not use this file except in compliance with the License.
6578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * You may obtain a copy of the License at
7578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen *
8578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen *      http://www.apache.org/licenses/LICENSE-2.0
9578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen *
10578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * Unless required by applicable law or agreed to in writing, software
11578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * distributed under the License is distributed on an "AS IS" BASIS,
12578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * See the License for the specific language governing permissions and
14578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * limitations under the License.
15578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */
16578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
17f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensenpackage android.net.apf;
18578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
19578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport static android.system.OsConstants.*;
20578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
21647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichiimport android.os.SystemClock;
227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichiimport android.net.LinkAddress;
23a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensenimport android.net.LinkProperties;
24578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.NetworkUtils;
25578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator;
26578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator.IllegalInstructionException;
27578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.net.apf.ApfGenerator.Register;
28f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensenimport android.net.ip.IpManager;
294fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.net.metrics.ApfProgramEvent;
30647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichiimport android.net.metrics.ApfStats;
314fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.net.metrics.IpConnectivityLog;
32cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichiimport android.net.metrics.RaEvent;
33578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.ErrnoException;
34578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.Os;
35578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.system.PacketSocketAddress;
364fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichiimport android.text.format.DateUtils;
37578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.util.Log;
38578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport android.util.Pair;
39578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
40dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensenimport com.android.internal.annotations.GuardedBy;
419132f34976f16a626c2ec1d3d90624d71e054346Paul Jensenimport com.android.internal.annotations.VisibleForTesting;
42578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport com.android.internal.util.HexDump;
435ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport com.android.internal.util.IndentingPrintWriter;
44578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
45578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.io.FileDescriptor;
46578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.io.IOException;
47578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.lang.Thread;
487d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichiimport java.net.Inet4Address;
495ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.Inet6Address;
505ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.InetAddress;
51578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.net.NetworkInterface;
52578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.net.SocketException;
535ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.net.UnknownHostException;
54578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.nio.ByteBuffer;
555ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colittiimport java.nio.BufferUnderflowException;
56578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.util.ArrayList;
57578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport java.util.Arrays;
58578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
59578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenimport libcore.io.IoBridge;
60578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
61578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen/**
62578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * For networks that support packet filtering via APF programs, {@code ApfFilter}
63578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
64578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * filter out redundant duplicate ones.
65578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen *
66dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * Threading model:
67dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
68dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * know what RAs to filter for, thus generating APF programs is dependent on mRas.
69dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * mRas can be accessed by multiple threads:
70dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
71dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * - callers of:
72dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen *    - setMulticastFilter(), which can cause an APF program to be generated.
73dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen *    - dump(), which dumps mRas among other things.
74dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen *    - shutdown(), which clears mRas.
75dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen * So access to mRas is synchronized.
76dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen *
77578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen * @hide
78578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen */
79578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensenpublic class ApfFilter {
80647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
81647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    // Enums describing the outcome of receiving an RA packet.
82647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    private static enum ProcessRaResult {
83647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        MATCH,          // Received RA matched a known RA
84647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        DROPPED,        // Received RA ignored due to MAX_RAS
85647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        PARSE_ERROR,    // Received RA could not be parsed
86647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        ZERO_LIFETIME,  // Received RA had 0 lifetime
87647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        UPDATE_NEW_RA,  // APF program updated for new RA
88647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        UPDATE_EXPIRY   // APF program updated for expiry
89647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    }
90647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
91578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // Thread to listen for RAs.
929132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
939132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    class ReceiveThread extends Thread {
94578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private final byte[] mPacket = new byte[1514];
95578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private final FileDescriptor mSocket;
96647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        private final long mStart = SystemClock.elapsedRealtime();
9722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        private final ApfStats mStats = new ApfStats();
98647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
9922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        private volatile boolean mStopped;
100647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
101578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        public ReceiveThread(FileDescriptor socket) {
102578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mSocket = socket;
103578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
104578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
105578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        public void halt() {
106578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mStopped = true;
107578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            try {
108578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Interrupts the read() call the thread is blocked in.
109578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                IoBridge.closeAndSignalBlockedThreads(mSocket);
110578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            } catch (IOException ignored) {}
111578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
112578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
113578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        @Override
114578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        public void run() {
115578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            log("begin monitoring");
116578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            while (!mStopped) {
117578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                try {
118578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
119647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    updateStats(processRa(mPacket, length));
120578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                } catch (IOException|ErrnoException e) {
121578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    if (!mStopped) {
122578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        Log.e(TAG, "Read error", e);
123578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    }
124578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                }
125578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
126647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            logStats();
127647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        }
128647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
129647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        private void updateStats(ProcessRaResult result) {
13022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            mStats.receivedRas++;
131647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            switch(result) {
132647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case MATCH:
13322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.matchingRas++;
134647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
135647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case DROPPED:
13622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.droppedRas++;
137647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
138647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case PARSE_ERROR:
13922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.parseErrors++;
140647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
141647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case ZERO_LIFETIME:
14222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.zeroLifetimeRas++;
143647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
144647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case UPDATE_EXPIRY:
14522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.matchingRas++;
14622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.programUpdates++;
147647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
148647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                case UPDATE_NEW_RA:
14922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                    mStats.programUpdates++;
150647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return;
151647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            }
152647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        }
153647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi
154647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        private void logStats() {
15522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            final long nowMs = SystemClock.elapsedRealtime();
15622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            synchronized (this) {
15722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                mStats.durationMs = nowMs - mStart;
15822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize;
15922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                mStats.programUpdatesAll = mNumProgramUpdates;
16022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast;
16122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                mMetricsLog.log(mStats);
16222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi                logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
16322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            }
164578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
165578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
166578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
167578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private static final String TAG = "ApfFilter";
16839c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti    private static final boolean DBG = true;
1697a8797f6c8406bbc335f67b85ef0cf00dc3a2b24Joe Onorato    private static final boolean VDBG = false;
170578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
171dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int ETH_HEADER_LEN = 14;
17291723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen    private static final int ETH_DEST_ADDR_OFFSET = 0;
173dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int ETH_ETHERTYPE_OFFSET = 12;
174961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
175961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
176dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
177dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
178dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // Endianness is not an issue for this constant because the APF interpreter always operates in
179dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // network byte order.
180dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
181dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
182dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
18338db976514ff2ad12d207a927219762eab179882Hugo Benichi    private static final int IPV4_ANY_HOST_ADDRESS = 0;
1840dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
185dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
186dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
187dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
188dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
189dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int IPV6_HEADER_LEN = 40;
190dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // The IPv6 all nodes address ff02::1
191dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final byte[] IPV6_ALL_NODES_ADDRESS =
192961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
193dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
194dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
19502428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi    private static final int ICMP6_ROUTER_SOLICITATION = 133;
1964b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
19702428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
19802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
199dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
200dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
201dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
202dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int UDP_HEADER_LEN = 8;
203dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
204dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int DHCP_CLIENT_PORT = 68;
205dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
206dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
207dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
2084fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
20938db976514ff2ad12d207a927219762eab179882Hugo Benichi    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
21038db976514ff2ad12d207a927219762eab179882Hugo Benichi    private static final short ARP_OPCODE_REQUEST = 1;
21138db976514ff2ad12d207a927219762eab179882Hugo Benichi    private static final short ARP_OPCODE_REPLY = 2;
212961ca49fd67b39d8076ea49d12d2fda73f581399Hugo Benichi    private static final byte[] ARP_IPV4_HEADER = {
213a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen            0, 1, // Hardware type: Ethernet (1)
214a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen            8, 0, // Protocol type: IP (0x0800)
215a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen            6,    // Hardware size: 6
216a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen            4,    // Protocol size: 4
217a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    };
2184fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
21922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    // Do not log ApfProgramEvents whose actual lifetimes was less than this.
22022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
221a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
222f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen    private final ApfCapabilities mApfCapabilities;
223f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen    private final IpManager.Callback mIpManagerCallback;
224f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen    private final NetworkInterface mNetworkInterface;
2256ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi    private final IpConnectivityLog mMetricsLog;
2269132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
2279132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    byte[] mHardwareAddress;
2289132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
2299132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    ReceiveThread mReceiveThread;
230dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
231578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private long mUniqueCounter;
232dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
233dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private boolean mMulticastFilter;
234a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    // Our IPv4 address, if we have just one, otherwise null.
235a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    @GuardedBy("this")
236a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    private byte[] mIPv4Address;
2377d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
2387d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    @GuardedBy("this")
2397d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private int mIPv4PrefixLength;
240578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
2419132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
2429132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
2436ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi            IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) {
244f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        mApfCapabilities = apfCapabilities;
245f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        mIpManagerCallback = ipManagerCallback;
246f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        mNetworkInterface = networkInterface;
2472e074db972355a77f91378b5b1daceb500dde019Paul Jensen        mMulticastFilter = multicastFilter;
2486ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi        mMetricsLog = log;
249f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen
25022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        // TODO: ApfFilter should not generate programs until IpManager sends provisioning success.
251578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        maybeStartFilter();
252578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
253578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
254578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private void log(String s) {
255f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s);
256578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
257578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
258dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
259dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private long getUniqueNumberLocked() {
260578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        return mUniqueCounter++;
261578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
262578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
263578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    /**
264578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen     * Attempt to start listening for RAs and, if RAs are received, generating and installing
265578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen     * filters to ignore useless RAs.
266578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen     */
2679132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
2689132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    void maybeStartFilter() {
269578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        FileDescriptor socket;
270578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        try {
271f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            mHardwareAddress = mNetworkInterface.getHardwareAddress();
272dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            synchronized(this) {
273dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                // Install basic filters
274dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                installNewProgramLocked();
275dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            }
276578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
277578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
278f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen                    mNetworkInterface.getIndex());
279578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            Os.bind(socket, addr);
280f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
281578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        } catch(SocketException|ErrnoException e) {
282dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            Log.e(TAG, "Error starting filter", e);
283578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return;
284578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
285578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        mReceiveThread = new ReceiveThread(socket);
286578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        mReceiveThread.start();
287578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
288578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
289dafc44ea11972b3152e67dc305a98d658f1465baHugo Benichi    // Returns seconds since device boot.
2904456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi    @VisibleForTesting
2914456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi    protected long currentTimeSeconds() {
292dafc44ea11972b3152e67dc305a98d658f1465baHugo Benichi        return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
293578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
294578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
2950668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    public static class InvalidRaException extends Exception {
2960668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi        public InvalidRaException(String m) {
2970668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            super(m);
2980668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi        }
2990668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    }
3000668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi
301578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // A class to hold information about an RA.
3020668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    @VisibleForTesting
3030668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    class Ra {
304578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // From RFC4861:
305578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_RA_HEADER_LEN = 16;
306e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti        private static final int ICMP6_RA_CHECKSUM_OFFSET =
307e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
308e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
309578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_RA_OPTION_OFFSET =
310578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
311578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
312578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
313578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
314578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Prefix information option.
315578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
316578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
317578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
318578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
319578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
320578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
321578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
322578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // From RFC6106: Recursive DNS Server option
323578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
324578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // From RFC6106: DNS Search List option
325578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
326578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
327578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // From RFC4191: Route Information option
328578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
329578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Above three options all have the same format:
330578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
331578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
332578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
3331c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen        // Note: mPacket's position() cannot be assumed to be reset.
334578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private final ByteBuffer mPacket;
335578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // List of binary ranges that include the whole packet except the lifetimes.
336578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Pairs consist of offset and length.
337578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
338578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                new ArrayList<Pair<Integer, Integer>>();
339578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Minimum lifetime in packet
340578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long mMinLifetime;
341578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // When the packet was last captured, in seconds since Unix Epoch
342578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long mLastSeen;
343578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
3445ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        // For debugging only. Offsets into the packet where PIOs are.
345059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
346059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
347059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        // For debugging only. Offsets into the packet where RDNSS options are.
348059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
349059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
3505ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        // For debugging only. How many times this RA was seen.
3515ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        int seenCount = 0;
3525ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
35339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        // For debugging only. Returns the hex representation of the last matching packet.
35439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        String getLastMatchingPacket() {
355059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
356059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                    false /* lowercase */);
35739c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        }
3585ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
359059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        // For debugging only. Returns the string representation of the IPv6 address starting at
360059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        // position pos in the packet.
3615ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        private String IPv6AddresstoString(int pos) {
3625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            try {
3635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                byte[] array = mPacket.array();
3645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                // Can't just call copyOfRange() and see if it throws, because if it reads past the
3655ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                // end it pads with zeros instead of throwing.
3665ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
3675ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                    return "???";
3685ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                }
3695ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
3705ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
3715ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                return address.getHostAddress();
3725ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            } catch (UnsupportedOperationException e) {
3735ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                // array() failed. Cannot happen, mPacket is array-backed and read-write.
3745ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                return "???";
3750668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            } catch (ClassCastException|UnknownHostException e) {
3765ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                // Cannot happen.
3775ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                return "???";
3785ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            }
3795ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        }
3805ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
3815ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        // Can't be static because it's in a non-static inner class.
382cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi        // TODO: Make this static once RA is its own class.
383059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        private void prefixOptionToString(StringBuffer sb, int offset) {
384059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            String prefix = IPv6AddresstoString(offset + 16);
3854104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi            int length = getUint8(mPacket, offset + 2);
3864104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi            long valid = getUint32(mPacket, offset + 4);
3874104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi            long preferred = getUint32(mPacket, offset + 8);
388059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
389059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        }
390059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
391059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        private void rdnssOptionToString(StringBuffer sb, int offset) {
3924104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi            int optLen = getUint8(mPacket, offset + 1) * 8;
393059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            if (optLen < 24) return;  // Malformed or empty.
3944104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi            long lifetime = getUint32(mPacket, offset + 4);
395059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            int numServers = (optLen - 8) / 16;
396059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            sb.append("DNS ").append(lifetime).append("s");
397059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            for (int server = 0; server < numServers; server++) {
398059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
399059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            }
400059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        }
401059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
4025ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        public String toString() {
4035ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            try {
4045ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                StringBuffer sb = new StringBuffer();
405059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                sb.append(String.format("RA %s -> %s %ds ",
4065ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
407dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
4084104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                        getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
4095ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                for (int i: mPrefixOptionOffsets) {
410059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                    prefixOptionToString(sb, i);
411059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                }
412059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                for (int i: mRdnssOptionOffsets) {
413059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                    rdnssOptionToString(sb, i);
4145ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                }
4155ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                return sb.toString();
4160668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
4175ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                return "<Malformed RA>";
4185ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            }
4195ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        }
4205ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
421578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        /**
422578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
423578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * Assumes mPacket.position() is as far as we've parsed the packet.
424578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * @param lastNonLifetimeStart offset within packet of where the last binary range of
425578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         *                             data not including a lifetime.
426578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
427578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * @param lifetimeLength length of the next lifetime data.
428578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         * @return offset within packet of where the next binary range of data not including
4296ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi         *         a lifetime. This can be passed into the next invocation of this function
430578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         *         via {@code lastNonLifetimeStart}.
431578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen         */
432578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
433578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                int lifetimeLength) {
434578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            lifetimeOffset += mPacket.position();
435578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
436578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    lifetimeOffset - lastNonLifetimeStart));
437578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return lifetimeOffset + lifetimeLength;
438578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
439578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
440cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi        private int addNonLifetimeU32(int lastNonLifetimeStart) {
441cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi            return addNonLifetime(lastNonLifetimeStart,
442cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                    ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
443cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi        }
444cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi
445578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Note that this parses RA and may throw IllegalArgumentException (from
4468995d85b9432387520c9f04a69251536754b996bLorenzo Colitti        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
4478995d85b9432387520c9f04a69251536754b996bLorenzo Colitti        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
4488995d85b9432387520c9f04a69251536754b996bLorenzo Colitti        // specifications.
4490668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi        Ra(byte[] packet, int length) throws InvalidRaException {
4500668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            if (length < ICMP6_RA_OPTION_OFFSET) {
4510668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi                throw new InvalidRaException("Not an ICMP6 router advertisement");
4520668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            }
4530668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi
4546ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
4554456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi            mLastSeen = currentTimeSeconds();
4564b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen
4574b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen            // Sanity check packet in case a packet arrives before we attach RA filter
4584b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen            // to our packet socket. b/29586253
4594b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
4604104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                    getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
4614104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
4620668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi                throw new InvalidRaException("Not an ICMP6 router advertisement");
4634b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen            }
4644b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen
4654b545b04f6533b5e0377f2d2dec219ad816e47edPaul Jensen
4666ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi            RaEvent.Builder builder = new RaEvent.Builder();
467578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
468e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti            // Ignore the checksum.
469e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti            int lastNonLifetimeStart = addNonLifetime(0,
470e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    ICMP6_RA_CHECKSUM_OFFSET,
471e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    ICMP6_RA_CHECKSUM_LEN);
472e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti
473578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Parse router lifetime
474e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
475e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
476578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    ICMP6_RA_ROUTER_LIFETIME_LEN);
4776ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi            builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
478cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi
479059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            // Ensures that the RA is not truncated.
480578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mPacket.position(ICMP6_RA_OPTION_OFFSET);
481578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            while (mPacket.hasRemaining()) {
482cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                final int position = mPacket.position();
4834104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                final int optionType = getUint8(mPacket, position);
4844104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                final int optionLength = getUint8(mPacket, position + 1) * 8;
4856ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                long lifetime;
486578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                switch (optionType) {
487578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    case ICMP6_PREFIX_OPTION_TYPE:
488578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        // Parse valid lifetime
489578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
490578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
491578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
4926ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        lifetime = getUint32(mPacket,
4936ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                                position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
4946ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        builder.updatePrefixValidLifetime(lifetime);
495578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        // Parse preferred lifetime
496578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
497578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
498578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
4996ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        lifetime = getUint32(mPacket,
5006ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                                position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
5016ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        builder.updatePrefixPreferredLifetime(lifetime);
502cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        mPrefixOptionOffsets.add(position);
503578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        break;
504cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                    // These three options have the same lifetime offset and size, and
5056ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                    // are processed with the same specialized addNonLifetimeU32:
506578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    case ICMP6_RDNSS_OPTION_TYPE:
507cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        mRdnssOptionOffsets.add(position);
508cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
5096ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
5106ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        builder.updateRdnssLifetime(lifetime);
511cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        break;
512059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
513cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
5146ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
5156ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        builder.updateRouteInfoLifetime(lifetime);
516cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        break;
517578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    case ICMP6_DNSSL_OPTION_TYPE:
518cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
5196ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
5206ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                        builder.updateDnsslLifetime(lifetime);
521578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        break;
522578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    default:
523578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
524578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        // compatibility.
525578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        break;
526578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                }
5278995d85b9432387520c9f04a69251536754b996bLorenzo Colitti                if (optionLength <= 0) {
5280668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi                    throw new InvalidRaException(String.format(
5298995d85b9432387520c9f04a69251536754b996bLorenzo Colitti                        "Invalid option length opt=%d len=%d", optionType, optionLength));
5308995d85b9432387520c9f04a69251536754b996bLorenzo Colitti                }
531cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                mPacket.position(position + optionLength);
532578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
533578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Mark non-lifetime bytes since last lifetime.
534578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            addNonLifetime(lastNonLifetimeStart, 0, 0);
535578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mMinLifetime = minLifetime(packet, length);
5366ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi            mMetricsLog.log(builder.build());
537578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
538578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
539578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
540578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        boolean matches(byte[] packet, int length) {
5411c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen            if (length != mPacket.capacity()) return false;
5421c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen            byte[] referencePacket = mPacket.array();
543578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
5441c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
5451c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen                    if (packet[i] != referencePacket[i]) return false;
5461c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen                }
547578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
548578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return true;
549578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
550578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
551578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // What is the minimum of all lifetimes within {@code packet} in seconds?
552578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Precondition: matches(packet, length) already returned true.
553578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long minLifetime(byte[] packet, int length) {
554578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            long minLifetime = Long.MAX_VALUE;
555578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Wrap packet in ByteBuffer so we can read big-endian values easily
556578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
557578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
558578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
559e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti
560e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                // The checksum is in mNonLifetimes, but it's not a lifetime.
561e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
562e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                     continue;
563e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                }
564e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti
565cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
566cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                final long optionLifetime;
567578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                switch (lifetimeLength) {
568cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                    case 2:
5694104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                        optionLifetime = getUint16(byteBuffer, offset);
570cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        break;
571cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                    case 4:
5724104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi                        optionLifetime = getUint32(byteBuffer, offset);
573cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        break;
574cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                    default:
575cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                        throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
576578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                }
577cfbf7414a14cf91d1b5c83154aab54c32d6be76aHugo Benichi                minLifetime = Math.min(minLifetime, optionLifetime);
578578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
579578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return minLifetime;
580578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
581578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
582578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // How many seconds does this RA's have to live, taking into account the fact
583578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // that we might have seen it a while ago.
584578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long currentLifetime() {
5854456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi            return mMinLifetime - (currentTimeSeconds() - mLastSeen);
586578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
587578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
588578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        boolean isExpired() {
589dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
590dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
591dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            return currentLifetime() <= 0;
592578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
593578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
594578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
595578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Jump to the next filter if packet doesn't match this RA.
596dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        @GuardedBy("ApfFilter.this")
597dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
598dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
599578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Skip if packet is not the right size
600578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
6011c71cb3e728c5f7b3bc76daf581e108ed5c0fa3cPaul Jensen            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
602578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
603578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Skip filter if expired
604578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
605578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
606578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            for (int i = 0; i < mNonLifetimes.size(); i++) {
607578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Generate code to match the packet bytes
608578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
6097c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                // Don't generate JNEBS instruction for 0 bytes as it always fails the
6107c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
6117c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                // the number of bytes to compare. nonLifetime is zero between the
6127c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                // valid and preferred lifetimes in the prefix option.
6137c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                if (nonLifetime.second != 0) {
6147c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
6157c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                    gen.addJumpIfBytesNotEqual(Register.R0,
6167c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
6177c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                                               nonLifetime.first + nonLifetime.second),
6187c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                            nextFilterLabel);
6197c34b15f749fdc4889cf2ee77edab9f017281c65Paul Jensen                }
620578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Generate code to test the lifetimes haven't gone down too far
621578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                if ((i + 1) < mNonLifetimes.size()) {
622578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
623578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    int offset = nonLifetime.first + nonLifetime.second;
624e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    // Skip the checksum.
625e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
626e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                        continue;
627e6dfc1736b3e37ad2ea0e9005cab36432de196b2Lorenzo Colitti                    }
628578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    int length = nextNonLifetime.first - offset;
629578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    switch (length) {
630578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        case 4: gen.addLoad32(Register.R0, offset); break;
631578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        case 2: gen.addLoad16(Register.R0, offset); break;
632578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                        default: throw new IllegalStateException("bogus lifetime size " + length);
633578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    }
634578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
635578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                }
636578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
637578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            gen.addJump(gen.DROP_LABEL);
638578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            gen.defineLabel(nextFilterLabel);
639578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return filterLifetime;
640578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
641578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
642578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
643578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // Maximum number of RAs to filter for.
644578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private static final int MAX_RAS = 10;
645dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
646dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
647578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private ArrayList<Ra> mRas = new ArrayList<Ra>();
648578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
649578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // There is always some marginal benefit to updating the installed APF program when an RA is
650578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // seen because we can extend the program's lifetime slightly, but there is some cost to
651578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // updating the program, so don't bother unless the program is going to expire soon. This
652578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // constant defines "soon" in seconds.
653578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
654578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
655578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
656578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // packets may be dropped, so let's use 6.
657578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
658578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
659578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // When did we last install a filter program? In seconds since Unix Epoch.
660dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
661578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private long mLastTimeInstalledProgram;
662578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    // How long should the last installed filter program live for? In seconds.
663dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
664578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private long mLastInstalledProgramMinLifetime;
66522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    @GuardedBy("this")
66622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    private ApfProgramEvent mLastInstallEvent;
667578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
668dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    // For debugging only. The last program installed.
669dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
67039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti    private byte[] mLastInstalledProgram;
6715ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
67222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    // How many times the program was updated since we started.
67322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    @GuardedBy("this")
67422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    private int mNumProgramUpdates = 0;
67522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    // How many times the program was updated since we started for allowing multicast traffic.
676059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti    @GuardedBy("this")
67722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    private int mNumProgramUpdatesAllowingMulticast = 0;
678059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
679dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    /**
680a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     * Generate filter code to process ARP packets. Execution of this code ends in either the
681a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     * DROP_LABEL or PASS_LABEL and does not fall off the end.
682a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     * Preconditions:
683a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     *  - Packet being filtered is ARP
684a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     */
685a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    @GuardedBy("this")
686a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
687a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // Here's a basic summary of what the ARP filter program does:
688a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        //
68938db976514ff2ad12d207a927219762eab179882Hugo Benichi        // if not ARP IPv4
69038db976514ff2ad12d207a927219762eab179882Hugo Benichi        //   pass
69138db976514ff2ad12d207a927219762eab179882Hugo Benichi        // if not ARP IPv4 reply or request
69238db976514ff2ad12d207a927219762eab179882Hugo Benichi        //   pass
69338db976514ff2ad12d207a927219762eab179882Hugo Benichi        // if unicast ARP reply
69438db976514ff2ad12d207a927219762eab179882Hugo Benichi        //   pass
69538db976514ff2ad12d207a927219762eab179882Hugo Benichi        // if interface has no IPv4 address
69638db976514ff2ad12d207a927219762eab179882Hugo Benichi        //   if target ip is 0.0.0.0
69738db976514ff2ad12d207a927219762eab179882Hugo Benichi        //      drop
69838db976514ff2ad12d207a927219762eab179882Hugo Benichi        // else
69938db976514ff2ad12d207a927219762eab179882Hugo Benichi        //   if target ip is not the interface ip
70038db976514ff2ad12d207a927219762eab179882Hugo Benichi        //      drop
701a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // pass
702a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
70338db976514ff2ad12d207a927219762eab179882Hugo Benichi        final String checkTargetIPv4 = "checkTargetIPv4";
70438db976514ff2ad12d207a927219762eab179882Hugo Benichi
70538db976514ff2ad12d207a927219762eab179882Hugo Benichi        // Pass if not ARP IPv4.
70638db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
70738db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL);
70838db976514ff2ad12d207a927219762eab179882Hugo Benichi
70938db976514ff2ad12d207a927219762eab179882Hugo Benichi        // Pass if unknown ARP opcode.
71038db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
71138db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
71238db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL);
71338db976514ff2ad12d207a927219762eab179882Hugo Benichi
71438db976514ff2ad12d207a927219762eab179882Hugo Benichi        // Pass if unicast reply.
71538db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
71638db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
71738db976514ff2ad12d207a927219762eab179882Hugo Benichi
71838db976514ff2ad12d207a927219762eab179882Hugo Benichi        // Either a unicast request, a unicast reply, or a broadcast reply.
71938db976514ff2ad12d207a927219762eab179882Hugo Benichi        gen.defineLabel(checkTargetIPv4);
72038db976514ff2ad12d207a927219762eab179882Hugo Benichi        if (mIPv4Address == null) {
72138db976514ff2ad12d207a927219762eab179882Hugo Benichi            // When there is no IPv4 address, drop GARP replies (b/29404209).
72238db976514ff2ad12d207a927219762eab179882Hugo Benichi            gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
72338db976514ff2ad12d207a927219762eab179882Hugo Benichi            gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL);
72438db976514ff2ad12d207a927219762eab179882Hugo Benichi        } else {
72538db976514ff2ad12d207a927219762eab179882Hugo Benichi            // When there is an IPv4 address, drop unicast/broadcast requests
72638db976514ff2ad12d207a927219762eab179882Hugo Benichi            // and broadcast replies with a different target IPv4 address.
727dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen            gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
728dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen            gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
729dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        }
730a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
731a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        gen.addJump(gen.PASS_LABEL);
732a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    }
733a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
734a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    /**
735dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
736dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * DROP_LABEL or PASS_LABEL and does not fall off the end.
737dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * Preconditions:
738dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     *  - Packet being filtered is IPv4
739dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     */
740dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
741dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
742dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Here's a basic summary of what the IPv4 filter program does:
743dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //
744f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen        // if filtering multicast (i.e. multicast lock not held):
7450dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //   if it's DHCP destined to our MAC:
746f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen        //     pass
7470dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //   if it's L2 broadcast:
7480dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //     drop
7490dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //   if it's IPv4 multicast:
7500dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //     drop
7510dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi        //   if it's IPv4 broadcast:
752f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen        //     drop
753dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // pass
754dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
755dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        if (mMulticastFilter) {
7560dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
757dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
7580dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Pass DHCP addressed to us.
7590dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Check it's UDP.
760f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
7610dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
7620dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
763f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
7640dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
7650dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Check it's addressed to DHCP client port.
766f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
767f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
7680dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
7690dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Check it's DHCP to our MAC address.
770f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
771f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            // NOTE: Relies on R1 containing IPv4 header offset.
772f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen            gen.addAddR1();
7730dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
7740dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJump(gen.PASS_LABEL);
7750dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi
7760dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // Drop all multicasts/broadcasts.
7770dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.defineLabel(skipDhcpv4Filter);
7780dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi
7790dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // If IPv4 destination address is in multicast range, drop.
7800dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
7810dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addAnd(0xf0);
7820dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
7830dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi
7840dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
7850dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
7860dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
7877d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
7887d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
7897d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
7907d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            }
7910dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi
7920dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            // If L2 broadcast packet, drop.
7930dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
7940dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
7950dc1d314709d579ccdc3fc59a5f66557f6cd319dHugo Benichi            gen.addJump(gen.DROP_LABEL);
796f8a01e84317fcb9d27a294e95603b846143c7fcbPaul Jensen        }
797dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
798dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Otherwise, pass
799dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addJump(gen.PASS_LABEL);
800dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    }
801dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
802dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
803dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    /**
804dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
805dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
806dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * Preconditions:
807dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     *  - Packet being filtered is IPv6
808dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     */
809dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
810dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
811dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Here's a basic summary of what the IPv6 filter program does:
812dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //
813dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // if it's not ICMPv6:
81411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        //   if it's multicast and we're dropping multicast:
81511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        //     drop
816dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //   pass
81702428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        // if it's ICMPv6 RS to any:
81802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        //   drop
819dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // if it's ICMPv6 NA to ff02::1:
820dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //   drop
821dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
822dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
82311e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti
82411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        // Drop multicast if the multicast filter is enabled.
82511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        if (mMulticastFilter) {
82611e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
82711e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
82811e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
82911e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti
83011e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            // Drop all other packets sent to ff00::/8.
83111e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
83211e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
83311e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            // Not multicast and not ICMPv6. Pass.
83411e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.addJump(gen.PASS_LABEL);
83511e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.defineLabel(skipIpv6MulticastFilterLabel);
83611e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        } else {
83711e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            // If not ICMPv6, pass.
83811e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
83911e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti        }
84011e13e2175674389ed18c2b1e1af69c5ad931e8fLorenzo Colitti
841dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Add unsolicited multicast neighbor announcements filter
842dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
843dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
84402428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        // Drop all router solicitations (b/32833400)
84502428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
84602428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        // If not neighbor announcements, skip filter.
847dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
84802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi        // If to ff02::1, drop.
849dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // TODO: Drop only if they don't contain the address of on-link neighbours.
850dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
851dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
852dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                skipUnsolicitedMulticastNALabel);
853dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addJump(gen.DROP_LABEL);
854dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.defineLabel(skipUnsolicitedMulticastNALabel);
855dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    }
856dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
857dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    /**
858dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * Begin generating an APF program to:
859dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <ul>
860a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen     * <li>Drop ARP requests not for us, if mIPv4Address is set,
861dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
862dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
863dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Pass all other IPv4 packets,
864dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen     * <li>Drop all broadcast non-IP non-ARP packets.
865dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Pass all non-ICMPv6 IPv6 packets,
866dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Pass all non-IPv4 and non-IPv6 packets,
867dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
86802428988ad90a2bd294b9ce752c2fced5b649519Hugo Benichi     * <li>Drop IPv6 ICMPv6 RSs.
869dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
870dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     *     insertion of RA filters here, or if there aren't any, just passes the packets.
871dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     * </ul>
872dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen     */
873dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
874dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private ApfGenerator beginProgramLocked() throws IllegalInstructionException {
875dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        ApfGenerator gen = new ApfGenerator();
876dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // This is guaranteed to return true because of the check in maybeCreate.
877f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        gen.setApfVersion(mApfCapabilities.apfVersionSupported);
878dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
879dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Here's a basic summary of what the initial program does:
880dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //
881a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // if it's ARP:
882dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        //   insert ARP filter to drop or pass these appropriately
883dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // if it's IPv4:
884dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //   insert IPv4 filter to drop or pass these appropriately
885dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // if it's not IPv6:
886dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        //   if it's broadcast:
887dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        //     drop
888dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        //   pass
889dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
890dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
891dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        // Add ARP filters:
892dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        String skipArpFiltersLabel = "skipArpFilters";
893a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
894dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
895dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        generateArpFilterLocked(gen);
896dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.defineLabel(skipArpFiltersLabel);
897a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
898dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Add IPv4 filters:
899dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        String skipIPv4FiltersLabel = "skipIPv4Filters";
900a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
901a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // execute the ARP filter, since that filter does not fall through, but either drops or
902a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // passes.
903dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
904dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        generateIPv4FilterLocked(gen);
905dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        gen.defineLabel(skipIPv4FiltersLabel);
906dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
907dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        // Check for IPv6:
908dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
909a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
910a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // drop or pass.
911dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        String ipv6FilterLabel = "IPv6Filters";
912dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
913dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen
914dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        // Drop non-IP non-ARP broadcasts, pass the rest
915dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
916dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
917dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.addJump(gen.DROP_LABEL);
918dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen
919dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        // Add IPv6 filters:
920dd7bee87725795d0d71c5f6a309dda78df957d8aPaul Jensen        gen.defineLabel(ipv6FilterLabel);
921dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        generateIPv6FilterLocked(gen);
922dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        return gen;
923dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    }
924dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
9254fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi    /**
9264fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi     * Generate and install a new filter program.
9274fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi     */
928dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
9299132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    @VisibleForTesting
9309132f34976f16a626c2ec1d3d90624d71e054346Paul Jensen    void installNewProgramLocked() {
931dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        purgeExpiredRasLocked();
9324fc3ee5be223122792ebc0ee8a05c93d93e26a52Hugo Benichi        ArrayList<Ra> rasToFilter = new ArrayList<>();
933578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        final byte[] program;
934578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long programMinLifetime = Long.MAX_VALUE;
935578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        try {
936578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Step 1: Determine how many RA filters we can fit in the program.
937dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            ApfGenerator gen = beginProgramLocked();
938578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            for (Ra ra : mRas) {
939dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                ra.generateFilterLocked(gen);
940dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                // Stop if we get too big.
941f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen                if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break;
942dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                rasToFilter.add(ra);
943578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
944dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            // Step 2: Actually generate the program
945dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            gen = beginProgramLocked();
946dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            for (Ra ra : rasToFilter) {
947dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
948578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
949578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // Execution will reach the end of the program if no filters match, which will pass the
950578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            // packet to the AP.
951578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            program = gen.generate();
9520668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi        } catch (IllegalInstructionException|IllegalStateException e) {
9530668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            Log.e(TAG, "Failed to generate APF program.", e);
954578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            return;
955578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
95622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        final long now = currentTimeSeconds();
95722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastTimeInstalledProgram = now;
958578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        mLastInstalledProgramMinLifetime = programMinLifetime;
95939c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        mLastInstalledProgram = program;
960059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        mNumProgramUpdates++;
961059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
9625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        if (VDBG) {
9635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            hexDump("Installing filter: ", program, program.length);
9645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        }
965f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        mIpManagerCallback.installPacketFilter(program);
96622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        logApfProgramEventLocked(now);
96722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent = new ApfProgramEvent();
96822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent.lifetime = programMinLifetime;
96922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent.filteredRas = rasToFilter.size();
97022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent.currentRas = mRas.size();
97122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent.programLength = program.length;
97222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
97322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    }
97422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi
97522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    private void logApfProgramEventLocked(long now) {
97622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        if (mLastInstallEvent == null) {
97722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            return;
97822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        }
97922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        ApfProgramEvent ev = mLastInstallEvent;
98022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mLastInstallEvent = null;
98122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        ev.actualLifetime = now - mLastTimeInstalledProgram;
98222d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
98322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            return;
98422d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        }
98522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mMetricsLog.log(ev);
986578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
987578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
988647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    /**
989647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     * Returns {@code true} if a new program should be installed because the current one dies soon.
990647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     */
991647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    private boolean shouldInstallnewProgram() {
992578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
9934456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi        return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
994578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
995578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
996578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    private void hexDump(String msg, byte[] packet, int length) {
99739c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
998578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
999578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1000dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    @GuardedBy("this")
1001dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    private void purgeExpiredRasLocked() {
1002dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        for (int i = 0; i < mRas.size();) {
1003dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            if (mRas.get(i).isExpired()) {
1004dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                log("Expiring " + mRas.get(i));
1005dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                mRas.remove(i);
1006dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            } else {
1007dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen                i++;
1008dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            }
1009dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        }
1010dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    }
1011dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
1012647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi    /**
1013647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     * Process an RA packet, updating the list of known RAs and installing a new APF program
1014647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     * if the current APF program should be updated.
1015647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     * @return a ProcessRaResult enum describing what action was performed.
1016647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi     */
10170668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    @VisibleForTesting
10180668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi    synchronized ProcessRaResult processRa(byte[] packet, int length) {
10195ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        if (VDBG) hexDump("Read packet = ", packet, length);
1020578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1021578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // Have we seen this RA before?
1022578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        for (int i = 0; i < mRas.size(); i++) {
1023578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            Ra ra = mRas.get(i);
1024578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            if (ra.matches(packet, length)) {
10255ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                if (VDBG) log("matched RA " + ra);
1026578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Update lifetimes.
10274456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi                ra.mLastSeen = currentTimeSeconds();
1028578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                ra.mMinLifetime = ra.minLifetime(packet, length);
10295ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                ra.seenCount++;
1030578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1031578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
1032578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
1033578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // until the filter program exceeds the maximum filter program size allowed by the
1034578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
1035578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // filter program.
1036578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // TODO: consider sorting the RAs in order of increasing expiry time as well.
1037578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                // Swap to front of array.
1038578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen                mRas.add(0, mRas.remove(i));
1039578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1040647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                // If the current program doesn't expire for a while, don't update.
1041647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                if (shouldInstallnewProgram()) {
1042647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    installNewProgramLocked();
1043647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                    return ProcessRaResult.UPDATE_EXPIRY;
1044647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                }
1045647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi                return ProcessRaResult.MATCH;
1046578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            }
1047578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
1048dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        purgeExpiredRasLocked();
1049578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
1050647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        if (mRas.size() >= MAX_RAS) {
1051647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            return ProcessRaResult.DROPPED;
1052647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        }
1053dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        final Ra ra;
1054578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        try {
1055dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen            ra = new Ra(packet, length);
1056578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        } catch (Exception e) {
10570668a61d82a424fb3714b6222f0e4213c18fc7b1Hugo Benichi            Log.e(TAG, "Error parsing RA", e);
1058647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            return ProcessRaResult.PARSE_ERROR;
1059578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
1060dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        // Ignore 0 lifetime RAs.
1061647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        if (ra.isExpired()) {
1062647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi            return ProcessRaResult.ZERO_LIFETIME;
1063647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        }
1064dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        log("Adding " + ra);
1065dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        mRas.add(ra);
1066dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        installNewProgramLocked();
1067647c86d70a0f2162dcc95854e9dccb925c16ecf3Hugo Benichi        return ProcessRaResult.UPDATE_NEW_RA;
1068578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
1069578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1070578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    /**
1071f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
1072578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen     * filtering using APF programs.
1073578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen     */
1074f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
10752e074db972355a77f91378b5b1daceb500dde019Paul Jensen            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
10762e074db972355a77f91378b5b1daceb500dde019Paul Jensen            boolean multicastFilter) {
1077f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        if (apfCapabilities == null || networkInterface == null) return null;
1078f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        if (apfCapabilities.apfVersionSupported == 0) return null;
1079f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        if (apfCapabilities.maximumApfProgramSize < 512) {
1080f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
1081f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            return null;
1082578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
1083578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // For now only support generating programs for Ethernet frames. If this restriction is
1084578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        // lifted:
1085578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        //   1. the program generator will need its offsets adjusted.
1086578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        //   2. the packet filter attached to our packet socket will need its offset adjusted.
1087f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
1088f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen        if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) {
1089f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
1090f21b4dc1d6e9cc3fc164828e9eba33445c0801d0Paul Jensen            return null;
1091578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
10926ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
10936ccd51a338fed39217cb3a5c0f229ed547918634Hugo Benichi                multicastFilter, new IpConnectivityLog());
1094578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
1095578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen
1096dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    public synchronized void shutdown() {
1097578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        if (mReceiveThread != null) {
10985ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            log("shutting down");
1099578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mReceiveThread.halt();  // Also closes socket.
1100578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen            mReceiveThread = null;
1101578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen        }
1102dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        mRas.clear();
1103dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    }
1104dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen
110522d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi    public synchronized void setMulticastFilter(boolean isEnabled) {
110622d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        if (mMulticastFilter == isEnabled) {
110722d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            return;
110822d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        }
110922d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        mMulticastFilter = isEnabled;
111022d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        if (!isEnabled) {
111122d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi            mNumProgramUpdatesAllowingMulticast++;
1112dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen        }
111322d9b2d430c9a4fe17b54811bb77289b821e32dbHugo Benichi        installNewProgramLocked();
1114578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen    }
11155ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
11167d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
11177d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
11187d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        LinkAddress ipv4Address = null;
11197d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        for (LinkAddress address : lp.getLinkAddresses()) {
11207d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            if (!(address.getAddress() instanceof Inet4Address)) {
11217d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                continue;
11227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            }
11237d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
11247d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                // More than one IPv4 address, abort.
11257d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                return null;
11267d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            }
11277d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            ipv4Address = address;
1128a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        }
1129a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        return ipv4Address;
1130a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    }
1131a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
1132a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    public synchronized void setLinkProperties(LinkProperties lp) {
1133a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
11347d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
11357d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
11367d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
11377d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
11387d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi            return;
11397d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        }
11407d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        mIPv4Address = addr;
11417d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        mIPv4PrefixLength = prefix;
1142a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        installNewProgramLocked();
1143a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen    }
1144a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen
1145dfd5a949fbbba78793c261f5a0d585b27dc33851Paul Jensen    public synchronized void dump(IndentingPrintWriter pw) {
1146059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        pw.println("Capabilities: " + mApfCapabilities);
11475ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
1148059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
1149a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        try {
1150059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
1151a8458c0363851c7324a8e64efe9f73d0bb6ef0b4Paul Jensen        } catch (UnknownHostException|NullPointerException e) {}
1152059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti
11535ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        if (mLastTimeInstalledProgram == 0) {
11545ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            pw.println("No program installed.");
11555ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            return;
11565ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        }
1157059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        pw.println("Program updates: " + mNumProgramUpdates);
11585ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        pw.println(String.format(
1159059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti                "Last program length %d, installed %ds ago, lifetime %ds",
11604456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi                mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
11615ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti                mLastInstalledProgramMinLifetime));
11625ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti
11635ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        pw.println("RA filters:");
11645ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        pw.increaseIndent();
11655ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        for (Ra ra: mRas) {
11665ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            pw.println(ra);
11675ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            pw.increaseIndent();
11685ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            pw.println(String.format(
11694456f33a958a7f09e608399da83c4d12b2e7d191Hugo Benichi                    "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
117039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            if (DBG) {
117139c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti                pw.println("Last match:");
117239c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti                pw.increaseIndent();
117339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti                pw.println(ra.getLastMatchingPacket());
117439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti                pw.decreaseIndent();
117539c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            }
11765ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti            pw.decreaseIndent();
11775ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti        }
1178059e2bb376418aeb16551866c384dd1be032db62Lorenzo Colitti        pw.decreaseIndent();
117939c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti
118039c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        if (DBG) {
118139c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            pw.println("Last program:");
118239c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            pw.increaseIndent();
118339c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
118439c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti            pw.decreaseIndent();
118539c0d42f8120eae5f8c56a6acd223998a1debc3eLorenzo Colitti        }
11865ff640d1f257c351a0e22e243532fecc4682f36dLorenzo Colitti    }
11877d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
11887d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private static int uint8(byte b) {
11897d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return b & 0xff;
11907d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
11917d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
11927d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private static int uint16(short s) {
11937d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return s & 0xffff;
11947d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
11957d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
11967d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private static long uint32(int i) {
11977d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return i & 0xffffffffL;
11987d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
11997d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
12004104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi    private static int getUint8(ByteBuffer buffer, int position) {
12014104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi        return uint8(buffer.get(position));
12024104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi    }
12034104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi
12044104ff922040540b73f79f0f89dab3ae42b50462Hugo Benichi    private static int getUint16(ByteBuffer buffer, int position) {
12057d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return uint16(buffer.getShort(position));
12067d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
12077d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
12087d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    private static long getUint32(ByteBuffer buffer, int position) {
12097d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return uint32(buffer.getInt(position));
12107d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
12117d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
12127d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    // TODO: move to android.net.NetworkUtils
12137d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    @VisibleForTesting
12147d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
12157d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
12167d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
12177d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi
12187d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    @VisibleForTesting
12197d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    public static int bytesToInt(byte[] addrBytes) {
12207d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi        return (uint8(addrBytes[0]) << 24)
12217d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                + (uint8(addrBytes[1]) << 16)
12227d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                + (uint8(addrBytes[2]) << 8)
12237d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi                + (uint8(addrBytes[3]));
12247d21eaedade0e01bed665dd2e4ba15e0c217237cHugo Benichi    }
1225578a76e7de77492ac33e407fff4fb9a2f5550d8aPaul Jensen}
1226