1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.apf;
18
19import static android.system.OsConstants.*;
20
21import static com.android.internal.util.BitUtils.bytesToBEInt;
22import static com.android.internal.util.BitUtils.getUint16;
23import static com.android.internal.util.BitUtils.getUint32;
24import static com.android.internal.util.BitUtils.getUint8;
25import static com.android.internal.util.BitUtils.uint16;
26import static com.android.internal.util.BitUtils.uint32;
27import static com.android.internal.util.BitUtils.uint8;
28
29import android.os.SystemClock;
30import android.net.LinkAddress;
31import android.net.LinkProperties;
32import android.net.NetworkUtils;
33import android.net.apf.ApfGenerator;
34import android.net.apf.ApfGenerator.IllegalInstructionException;
35import android.net.apf.ApfGenerator.Register;
36import android.net.ip.IpManager;
37import android.net.metrics.ApfProgramEvent;
38import android.net.metrics.ApfStats;
39import android.net.metrics.IpConnectivityLog;
40import android.net.metrics.RaEvent;
41import android.system.ErrnoException;
42import android.system.Os;
43import android.system.PacketSocketAddress;
44import android.text.format.DateUtils;
45import android.util.Log;
46import android.util.Pair;
47
48import com.android.internal.annotations.GuardedBy;
49import com.android.internal.annotations.VisibleForTesting;
50import com.android.internal.util.HexDump;
51import com.android.internal.util.IndentingPrintWriter;
52
53import java.io.FileDescriptor;
54import java.io.IOException;
55import java.lang.Thread;
56import java.net.Inet4Address;
57import java.net.Inet6Address;
58import java.net.InetAddress;
59import java.net.NetworkInterface;
60import java.net.SocketException;
61import java.net.UnknownHostException;
62import java.nio.ByteBuffer;
63import java.nio.BufferUnderflowException;
64import java.util.ArrayList;
65import java.util.Arrays;
66
67import libcore.io.IoBridge;
68
69/**
70 * For networks that support packet filtering via APF programs, {@code ApfFilter}
71 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
72 * filter out redundant duplicate ones.
73 *
74 * Threading model:
75 * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
76 * know what RAs to filter for, thus generating APF programs is dependent on mRas.
77 * mRas can be accessed by multiple threads:
78 * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
79 * - callers of:
80 *    - setMulticastFilter(), which can cause an APF program to be generated.
81 *    - dump(), which dumps mRas among other things.
82 *    - shutdown(), which clears mRas.
83 * So access to mRas is synchronized.
84 *
85 * @hide
86 */
87public class ApfFilter {
88
89    // Enums describing the outcome of receiving an RA packet.
90    private static enum ProcessRaResult {
91        MATCH,          // Received RA matched a known RA
92        DROPPED,        // Received RA ignored due to MAX_RAS
93        PARSE_ERROR,    // Received RA could not be parsed
94        ZERO_LIFETIME,  // Received RA had 0 lifetime
95        UPDATE_NEW_RA,  // APF program updated for new RA
96        UPDATE_EXPIRY   // APF program updated for expiry
97    }
98
99    // Thread to listen for RAs.
100    @VisibleForTesting
101    class ReceiveThread extends Thread {
102        private final byte[] mPacket = new byte[1514];
103        private final FileDescriptor mSocket;
104        private final long mStart = SystemClock.elapsedRealtime();
105        private final ApfStats mStats = new ApfStats();
106
107        private volatile boolean mStopped;
108
109        public ReceiveThread(FileDescriptor socket) {
110            mSocket = socket;
111        }
112
113        public void halt() {
114            mStopped = true;
115            try {
116                // Interrupts the read() call the thread is blocked in.
117                IoBridge.closeAndSignalBlockedThreads(mSocket);
118            } catch (IOException ignored) {}
119        }
120
121        @Override
122        public void run() {
123            log("begin monitoring");
124            while (!mStopped) {
125                try {
126                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
127                    updateStats(processRa(mPacket, length));
128                } catch (IOException|ErrnoException e) {
129                    if (!mStopped) {
130                        Log.e(TAG, "Read error", e);
131                    }
132                }
133            }
134            logStats();
135        }
136
137        private void updateStats(ProcessRaResult result) {
138            mStats.receivedRas++;
139            switch(result) {
140                case MATCH:
141                    mStats.matchingRas++;
142                    return;
143                case DROPPED:
144                    mStats.droppedRas++;
145                    return;
146                case PARSE_ERROR:
147                    mStats.parseErrors++;
148                    return;
149                case ZERO_LIFETIME:
150                    mStats.zeroLifetimeRas++;
151                    return;
152                case UPDATE_EXPIRY:
153                    mStats.matchingRas++;
154                    mStats.programUpdates++;
155                    return;
156                case UPDATE_NEW_RA:
157                    mStats.programUpdates++;
158                    return;
159            }
160        }
161
162        private void logStats() {
163            final long nowMs = SystemClock.elapsedRealtime();
164            synchronized (this) {
165                mStats.durationMs = nowMs - mStart;
166                mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize;
167                mStats.programUpdatesAll = mNumProgramUpdates;
168                mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast;
169                mMetricsLog.log(mStats);
170                logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
171            }
172        }
173    }
174
175    private static final String TAG = "ApfFilter";
176    private static final boolean DBG = true;
177    private static final boolean VDBG = false;
178
179    private static final int ETH_HEADER_LEN = 14;
180    private static final int ETH_DEST_ADDR_OFFSET = 0;
181    private static final int ETH_ETHERTYPE_OFFSET = 12;
182    private static final int ETH_TYPE_MIN = 0x0600;
183    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
184            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
185    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
186    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
187    // Endianness is not an issue for this constant because the APF interpreter always operates in
188    // network byte order.
189    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
190    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
191    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
192    private static final int IPV4_ANY_HOST_ADDRESS = 0;
193    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
194
195    // Traffic class and Flow label are not byte aligned. Luckily we
196    // don't care about either value so we'll consider bytes 1-3 of the
197    // IPv6 header as don't care.
198    private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
199    private static final int IPV6_FLOW_LABEL_LEN = 3;
200    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
201    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
202    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
203    private static final int IPV6_HEADER_LEN = 40;
204    // The IPv6 all nodes address ff02::1
205    private static final byte[] IPV6_ALL_NODES_ADDRESS =
206            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
207
208    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
209    private static final int ICMP6_ROUTER_SOLICITATION = 133;
210    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
211    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
212    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
213
214    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
215    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
216    private static final int UDP_HEADER_LEN = 8;
217
218    private static final int DHCP_CLIENT_PORT = 68;
219    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
220    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
221
222    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
223    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
224    private static final short ARP_OPCODE_REQUEST = 1;
225    private static final short ARP_OPCODE_REPLY = 2;
226    private static final byte[] ARP_IPV4_HEADER = {
227            0, 1, // Hardware type: Ethernet (1)
228            8, 0, // Protocol type: IP (0x0800)
229            6,    // Hardware size: 6
230            4,    // Protocol size: 4
231    };
232    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
233    // Do not log ApfProgramEvents whose actual lifetimes was less than this.
234    private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
235
236    private final ApfCapabilities mApfCapabilities;
237    private final IpManager.Callback mIpManagerCallback;
238    private final NetworkInterface mNetworkInterface;
239    private final IpConnectivityLog mMetricsLog;
240
241    @VisibleForTesting
242    byte[] mHardwareAddress;
243    @VisibleForTesting
244    ReceiveThread mReceiveThread;
245    @GuardedBy("this")
246    private long mUniqueCounter;
247    @GuardedBy("this")
248    private boolean mMulticastFilter;
249    private final boolean mDrop802_3Frames;
250    // Our IPv4 address, if we have just one, otherwise null.
251    @GuardedBy("this")
252    private byte[] mIPv4Address;
253    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
254    @GuardedBy("this")
255    private int mIPv4PrefixLength;
256
257    @VisibleForTesting
258    ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
259            IpManager.Callback ipManagerCallback, boolean multicastFilter,
260            boolean ieee802_3Filter, IpConnectivityLog log) {
261        mApfCapabilities = apfCapabilities;
262        mIpManagerCallback = ipManagerCallback;
263        mNetworkInterface = networkInterface;
264        mMulticastFilter = multicastFilter;
265        mDrop802_3Frames = ieee802_3Filter;
266        mMetricsLog = log;
267
268        // TODO: ApfFilter should not generate programs until IpManager sends provisioning success.
269        maybeStartFilter();
270    }
271
272    private void log(String s) {
273        Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s);
274    }
275
276    @GuardedBy("this")
277    private long getUniqueNumberLocked() {
278        return mUniqueCounter++;
279    }
280
281    /**
282     * Attempt to start listening for RAs and, if RAs are received, generating and installing
283     * filters to ignore useless RAs.
284     */
285    @VisibleForTesting
286    void maybeStartFilter() {
287        FileDescriptor socket;
288        try {
289            mHardwareAddress = mNetworkInterface.getHardwareAddress();
290            synchronized(this) {
291                // Install basic filters
292                installNewProgramLocked();
293            }
294            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
295            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
296                    mNetworkInterface.getIndex());
297            Os.bind(socket, addr);
298            NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
299        } catch(SocketException|ErrnoException e) {
300            Log.e(TAG, "Error starting filter", e);
301            return;
302        }
303        mReceiveThread = new ReceiveThread(socket);
304        mReceiveThread.start();
305    }
306
307    // Returns seconds since device boot.
308    @VisibleForTesting
309    protected long currentTimeSeconds() {
310        return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
311    }
312
313    public static class InvalidRaException extends Exception {
314        public InvalidRaException(String m) {
315            super(m);
316        }
317    }
318
319    // A class to hold information about an RA.
320    @VisibleForTesting
321    class Ra {
322        // From RFC4861:
323        private static final int ICMP6_RA_HEADER_LEN = 16;
324        private static final int ICMP6_RA_CHECKSUM_OFFSET =
325                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
326        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
327        private static final int ICMP6_RA_OPTION_OFFSET =
328                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
329        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
330                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
331        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
332        // Prefix information option.
333        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
334        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
335        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
336        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
337        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
338        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
339
340        // From RFC6106: Recursive DNS Server option
341        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
342        // From RFC6106: DNS Search List option
343        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
344
345        // From RFC4191: Route Information option
346        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
347        // Above three options all have the same format:
348        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
349        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
350
351        // Note: mPacket's position() cannot be assumed to be reset.
352        private final ByteBuffer mPacket;
353        // List of binary ranges that include the whole packet except the lifetimes.
354        // Pairs consist of offset and length.
355        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
356                new ArrayList<Pair<Integer, Integer>>();
357        // Minimum lifetime in packet
358        long mMinLifetime;
359        // When the packet was last captured, in seconds since Unix Epoch
360        long mLastSeen;
361
362        // For debugging only. Offsets into the packet where PIOs are.
363        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
364
365        // For debugging only. Offsets into the packet where RDNSS options are.
366        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
367
368        // For debugging only. How many times this RA was seen.
369        int seenCount = 0;
370
371        // For debugging only. Returns the hex representation of the last matching packet.
372        String getLastMatchingPacket() {
373            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
374                    false /* lowercase */);
375        }
376
377        // For debugging only. Returns the string representation of the IPv6 address starting at
378        // position pos in the packet.
379        private String IPv6AddresstoString(int pos) {
380            try {
381                byte[] array = mPacket.array();
382                // Can't just call copyOfRange() and see if it throws, because if it reads past the
383                // end it pads with zeros instead of throwing.
384                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
385                    return "???";
386                }
387                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
388                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
389                return address.getHostAddress();
390            } catch (UnsupportedOperationException e) {
391                // array() failed. Cannot happen, mPacket is array-backed and read-write.
392                return "???";
393            } catch (ClassCastException|UnknownHostException e) {
394                // Cannot happen.
395                return "???";
396            }
397        }
398
399        // Can't be static because it's in a non-static inner class.
400        // TODO: Make this static once RA is its own class.
401        private void prefixOptionToString(StringBuffer sb, int offset) {
402            String prefix = IPv6AddresstoString(offset + 16);
403            int length = getUint8(mPacket, offset + 2);
404            long valid = getUint32(mPacket, offset + 4);
405            long preferred = getUint32(mPacket, offset + 8);
406            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
407        }
408
409        private void rdnssOptionToString(StringBuffer sb, int offset) {
410            int optLen = getUint8(mPacket, offset + 1) * 8;
411            if (optLen < 24) return;  // Malformed or empty.
412            long lifetime = getUint32(mPacket, offset + 4);
413            int numServers = (optLen - 8) / 16;
414            sb.append("DNS ").append(lifetime).append("s");
415            for (int server = 0; server < numServers; server++) {
416                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
417            }
418        }
419
420        public String toString() {
421            try {
422                StringBuffer sb = new StringBuffer();
423                sb.append(String.format("RA %s -> %s %ds ",
424                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
425                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
426                        getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
427                for (int i: mPrefixOptionOffsets) {
428                    prefixOptionToString(sb, i);
429                }
430                for (int i: mRdnssOptionOffsets) {
431                    rdnssOptionToString(sb, i);
432                }
433                return sb.toString();
434            } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
435                return "<Malformed RA>";
436            }
437        }
438
439        /**
440         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
441         * Assumes mPacket.position() is as far as we've parsed the packet.
442         * @param lastNonLifetimeStart offset within packet of where the last binary range of
443         *                             data not including a lifetime.
444         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
445         * @param lifetimeLength length of the next lifetime data.
446         * @return offset within packet of where the next binary range of data not including
447         *         a lifetime. This can be passed into the next invocation of this function
448         *         via {@code lastNonLifetimeStart}.
449         */
450        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
451                int lifetimeLength) {
452            lifetimeOffset += mPacket.position();
453            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
454                    lifetimeOffset - lastNonLifetimeStart));
455            return lifetimeOffset + lifetimeLength;
456        }
457
458        private int addNonLifetimeU32(int lastNonLifetimeStart) {
459            return addNonLifetime(lastNonLifetimeStart,
460                    ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
461        }
462
463        // Note that this parses RA and may throw IllegalArgumentException (from
464        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
465        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
466        // specifications.
467        Ra(byte[] packet, int length) throws InvalidRaException {
468            if (length < ICMP6_RA_OPTION_OFFSET) {
469                throw new InvalidRaException("Not an ICMP6 router advertisement");
470            }
471
472            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
473            mLastSeen = currentTimeSeconds();
474
475            // Sanity check packet in case a packet arrives before we attach RA filter
476            // to our packet socket. b/29586253
477            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
478                    getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
479                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
480                throw new InvalidRaException("Not an ICMP6 router advertisement");
481            }
482
483
484            RaEvent.Builder builder = new RaEvent.Builder();
485
486            // Ignore the flow label and low 4 bits of traffic class.
487            int lastNonLifetimeStart = addNonLifetime(0,
488                    IPV6_FLOW_LABEL_OFFSET,
489                    IPV6_FLOW_LABEL_LEN);
490
491            // Ignore the checksum.
492            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
493                    ICMP6_RA_CHECKSUM_OFFSET,
494                    ICMP6_RA_CHECKSUM_LEN);
495
496            // Parse router lifetime
497            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
498                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
499                    ICMP6_RA_ROUTER_LIFETIME_LEN);
500            builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
501
502            // Ensures that the RA is not truncated.
503            mPacket.position(ICMP6_RA_OPTION_OFFSET);
504            while (mPacket.hasRemaining()) {
505                final int position = mPacket.position();
506                final int optionType = getUint8(mPacket, position);
507                final int optionLength = getUint8(mPacket, position + 1) * 8;
508                long lifetime;
509                switch (optionType) {
510                    case ICMP6_PREFIX_OPTION_TYPE:
511                        // Parse valid lifetime
512                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
513                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
514                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
515                        lifetime = getUint32(mPacket,
516                                position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
517                        builder.updatePrefixValidLifetime(lifetime);
518                        // Parse preferred lifetime
519                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
520                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
521                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
522                        lifetime = getUint32(mPacket,
523                                position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
524                        builder.updatePrefixPreferredLifetime(lifetime);
525                        mPrefixOptionOffsets.add(position);
526                        break;
527                    // These three options have the same lifetime offset and size, and
528                    // are processed with the same specialized addNonLifetimeU32:
529                    case ICMP6_RDNSS_OPTION_TYPE:
530                        mRdnssOptionOffsets.add(position);
531                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
532                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
533                        builder.updateRdnssLifetime(lifetime);
534                        break;
535                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
536                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
537                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
538                        builder.updateRouteInfoLifetime(lifetime);
539                        break;
540                    case ICMP6_DNSSL_OPTION_TYPE:
541                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
542                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
543                        builder.updateDnsslLifetime(lifetime);
544                        break;
545                    default:
546                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
547                        // compatibility.
548                        break;
549                }
550                if (optionLength <= 0) {
551                    throw new InvalidRaException(String.format(
552                        "Invalid option length opt=%d len=%d", optionType, optionLength));
553                }
554                mPacket.position(position + optionLength);
555            }
556            // Mark non-lifetime bytes since last lifetime.
557            addNonLifetime(lastNonLifetimeStart, 0, 0);
558            mMinLifetime = minLifetime(packet, length);
559            mMetricsLog.log(builder.build());
560        }
561
562        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
563        boolean matches(byte[] packet, int length) {
564            if (length != mPacket.capacity()) return false;
565            byte[] referencePacket = mPacket.array();
566            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
567                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
568                    if (packet[i] != referencePacket[i]) return false;
569                }
570            }
571            return true;
572        }
573
574        // What is the minimum of all lifetimes within {@code packet} in seconds?
575        // Precondition: matches(packet, length) already returned true.
576        long minLifetime(byte[] packet, int length) {
577            long minLifetime = Long.MAX_VALUE;
578            // Wrap packet in ByteBuffer so we can read big-endian values easily
579            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
580            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
581                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
582
583                // The flow label is in mNonLifetimes, but it's not a lifetime.
584                if (offset == IPV6_FLOW_LABEL_OFFSET) {
585                    continue;
586                }
587
588                // The checksum is in mNonLifetimes, but it's not a lifetime.
589                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
590                    continue;
591                }
592
593                final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
594                final long optionLifetime;
595                switch (lifetimeLength) {
596                    case 2:
597                        optionLifetime = getUint16(byteBuffer, offset);
598                        break;
599                    case 4:
600                        optionLifetime = getUint32(byteBuffer, offset);
601                        break;
602                    default:
603                        throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
604                }
605                minLifetime = Math.min(minLifetime, optionLifetime);
606            }
607            return minLifetime;
608        }
609
610        // How many seconds does this RA's have to live, taking into account the fact
611        // that we might have seen it a while ago.
612        long currentLifetime() {
613            return mMinLifetime - (currentTimeSeconds() - mLastSeen);
614        }
615
616        boolean isExpired() {
617            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
618            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
619            return currentLifetime() <= 0;
620        }
621
622        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
623        // Jump to the next filter if packet doesn't match this RA.
624        @GuardedBy("ApfFilter.this")
625        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
626            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
627            // Skip if packet is not the right size
628            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
629            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
630            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
631            // Skip filter if expired
632            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
633            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
634            for (int i = 0; i < mNonLifetimes.size(); i++) {
635                // Generate code to match the packet bytes
636                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
637                // Don't generate JNEBS instruction for 0 bytes as it always fails the
638                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
639                // the number of bytes to compare. nonLifetime is zero between the
640                // valid and preferred lifetimes in the prefix option.
641                if (nonLifetime.second != 0) {
642                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
643                    gen.addJumpIfBytesNotEqual(Register.R0,
644                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
645                                               nonLifetime.first + nonLifetime.second),
646                            nextFilterLabel);
647                }
648                // Generate code to test the lifetimes haven't gone down too far
649                if ((i + 1) < mNonLifetimes.size()) {
650                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
651                    int offset = nonLifetime.first + nonLifetime.second;
652
653                    // Skip the Flow label.
654                    if (offset == IPV6_FLOW_LABEL_OFFSET) {
655                        continue;
656                    }
657                    // Skip the checksum.
658                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
659                        continue;
660                    }
661                    int length = nextNonLifetime.first - offset;
662                    switch (length) {
663                        case 4: gen.addLoad32(Register.R0, offset); break;
664                        case 2: gen.addLoad16(Register.R0, offset); break;
665                        default: throw new IllegalStateException("bogus lifetime size " + length);
666                    }
667                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
668                }
669            }
670            gen.addJump(gen.DROP_LABEL);
671            gen.defineLabel(nextFilterLabel);
672            return filterLifetime;
673        }
674    }
675
676    // Maximum number of RAs to filter for.
677    private static final int MAX_RAS = 10;
678
679    @GuardedBy("this")
680    private ArrayList<Ra> mRas = new ArrayList<Ra>();
681
682    // There is always some marginal benefit to updating the installed APF program when an RA is
683    // seen because we can extend the program's lifetime slightly, but there is some cost to
684    // updating the program, so don't bother unless the program is going to expire soon. This
685    // constant defines "soon" in seconds.
686    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
687    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
688    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
689    // packets may be dropped, so let's use 6.
690    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
691
692    // When did we last install a filter program? In seconds since Unix Epoch.
693    @GuardedBy("this")
694    private long mLastTimeInstalledProgram;
695    // How long should the last installed filter program live for? In seconds.
696    @GuardedBy("this")
697    private long mLastInstalledProgramMinLifetime;
698    @GuardedBy("this")
699    private ApfProgramEvent mLastInstallEvent;
700
701    // For debugging only. The last program installed.
702    @GuardedBy("this")
703    private byte[] mLastInstalledProgram;
704
705    // How many times the program was updated since we started.
706    @GuardedBy("this")
707    private int mNumProgramUpdates = 0;
708    // How many times the program was updated since we started for allowing multicast traffic.
709    @GuardedBy("this")
710    private int mNumProgramUpdatesAllowingMulticast = 0;
711
712    /**
713     * Generate filter code to process ARP packets. Execution of this code ends in either the
714     * DROP_LABEL or PASS_LABEL and does not fall off the end.
715     * Preconditions:
716     *  - Packet being filtered is ARP
717     */
718    @GuardedBy("this")
719    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
720        // Here's a basic summary of what the ARP filter program does:
721        //
722        // if not ARP IPv4
723        //   pass
724        // if not ARP IPv4 reply or request
725        //   pass
726        // if unicast ARP reply
727        //   pass
728        // if interface has no IPv4 address
729        //   if target ip is 0.0.0.0
730        //      drop
731        // else
732        //   if target ip is not the interface ip
733        //      drop
734        // pass
735
736        final String checkTargetIPv4 = "checkTargetIPv4";
737
738        // Pass if not ARP IPv4.
739        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
740        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL);
741
742        // Pass if unknown ARP opcode.
743        gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
744        gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
745        gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL);
746
747        // Pass if unicast reply.
748        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
749        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
750
751        // Either a unicast request, a unicast reply, or a broadcast reply.
752        gen.defineLabel(checkTargetIPv4);
753        if (mIPv4Address == null) {
754            // When there is no IPv4 address, drop GARP replies (b/29404209).
755            gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
756            gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL);
757        } else {
758            // When there is an IPv4 address, drop unicast/broadcast requests
759            // and broadcast replies with a different target IPv4 address.
760            gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
761            gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
762        }
763
764        gen.addJump(gen.PASS_LABEL);
765    }
766
767    /**
768     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
769     * DROP_LABEL or PASS_LABEL and does not fall off the end.
770     * Preconditions:
771     *  - Packet being filtered is IPv4
772     */
773    @GuardedBy("this")
774    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
775        // Here's a basic summary of what the IPv4 filter program does:
776        //
777        // if filtering multicast (i.e. multicast lock not held):
778        //   if it's DHCP destined to our MAC:
779        //     pass
780        //   if it's L2 broadcast:
781        //     drop
782        //   if it's IPv4 multicast:
783        //     drop
784        //   if it's IPv4 broadcast:
785        //     drop
786        // pass
787
788        if (mMulticastFilter) {
789            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
790
791            // Pass DHCP addressed to us.
792            // Check it's UDP.
793            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
794            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
795            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
796            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
797            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
798            // Check it's addressed to DHCP client port.
799            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
800            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
801            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
802            // Check it's DHCP to our MAC address.
803            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
804            // NOTE: Relies on R1 containing IPv4 header offset.
805            gen.addAddR1();
806            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
807            gen.addJump(gen.PASS_LABEL);
808
809            // Drop all multicasts/broadcasts.
810            gen.defineLabel(skipDhcpv4Filter);
811
812            // If IPv4 destination address is in multicast range, drop.
813            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
814            gen.addAnd(0xf0);
815            gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
816
817            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
818            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
819            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
820            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
821                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
822                gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
823            }
824
825            // If L2 broadcast packet, drop.
826            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
827            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
828            gen.addJump(gen.DROP_LABEL);
829        }
830
831        // Otherwise, pass
832        gen.addJump(gen.PASS_LABEL);
833    }
834
835
836    /**
837     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
838     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
839     * Preconditions:
840     *  - Packet being filtered is IPv6
841     */
842    @GuardedBy("this")
843    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
844        // Here's a basic summary of what the IPv6 filter program does:
845        //
846        // if it's not ICMPv6:
847        //   if it's multicast and we're dropping multicast:
848        //     drop
849        //   pass
850        // if it's ICMPv6 RS to any:
851        //   drop
852        // if it's ICMPv6 NA to ff02::1:
853        //   drop
854
855        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
856
857        // Drop multicast if the multicast filter is enabled.
858        if (mMulticastFilter) {
859            // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
860            String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
861            gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
862
863            // Drop all other packets sent to ff00::/8.
864            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
865            gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
866            // Not multicast and not ICMPv6. Pass.
867            gen.addJump(gen.PASS_LABEL);
868            gen.defineLabel(skipIpv6MulticastFilterLabel);
869        } else {
870            // If not ICMPv6, pass.
871            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
872        }
873
874        // Add unsolicited multicast neighbor announcements filter
875        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
876        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
877        // Drop all router solicitations (b/32833400)
878        gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
879        // If not neighbor announcements, skip filter.
880        gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
881        // If to ff02::1, drop.
882        // TODO: Drop only if they don't contain the address of on-link neighbours.
883        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
884        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
885                skipUnsolicitedMulticastNALabel);
886        gen.addJump(gen.DROP_LABEL);
887        gen.defineLabel(skipUnsolicitedMulticastNALabel);
888    }
889
890    /**
891     * Begin generating an APF program to:
892     * <ul>
893     * <li>Drop/Pass 802.3 frames (based on policy)
894     * <li>Drop ARP requests not for us, if mIPv4Address is set,
895     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
896     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
897     * <li>Pass all other IPv4 packets,
898     * <li>Drop all broadcast non-IP non-ARP packets.
899     * <li>Pass all non-ICMPv6 IPv6 packets,
900     * <li>Pass all non-IPv4 and non-IPv6 packets,
901     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
902     * <li>Drop IPv6 ICMPv6 RSs.
903     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
904     *     insertion of RA filters here, or if there aren't any, just passes the packets.
905     * </ul>
906     */
907    @GuardedBy("this")
908    private ApfGenerator beginProgramLocked() throws IllegalInstructionException {
909        ApfGenerator gen = new ApfGenerator();
910        // This is guaranteed to return true because of the check in maybeCreate.
911        gen.setApfVersion(mApfCapabilities.apfVersionSupported);
912
913        // Here's a basic summary of what the initial program does:
914        //
915        // if it's a 802.3 Frame (ethtype < 0x0600):
916        //    drop or pass based on configurations
917        // if it's ARP:
918        //   insert ARP filter to drop or pass these appropriately
919        // if it's IPv4:
920        //   insert IPv4 filter to drop or pass these appropriately
921        // if it's not IPv6:
922        //   if it's broadcast:
923        //     drop
924        //   pass
925        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
926
927        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
928
929        if (mDrop802_3Frames) {
930            // drop 802.3 frames (ethtype < 0x0600)
931            gen.addJumpIfR0LessThan(ETH_TYPE_MIN, gen.DROP_LABEL);
932        }
933
934        // Add ARP filters:
935        String skipArpFiltersLabel = "skipArpFilters";
936        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
937        generateArpFilterLocked(gen);
938        gen.defineLabel(skipArpFiltersLabel);
939
940        // Add IPv4 filters:
941        String skipIPv4FiltersLabel = "skipIPv4Filters";
942        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
943        // execute the ARP filter, since that filter does not fall through, but either drops or
944        // passes.
945        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
946        generateIPv4FilterLocked(gen);
947        gen.defineLabel(skipIPv4FiltersLabel);
948
949        // Check for IPv6:
950        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
951        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
952        // drop or pass.
953        String ipv6FilterLabel = "IPv6Filters";
954        gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
955
956        // Drop non-IP non-ARP broadcasts, pass the rest
957        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
958        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
959        gen.addJump(gen.DROP_LABEL);
960
961        // Add IPv6 filters:
962        gen.defineLabel(ipv6FilterLabel);
963        generateIPv6FilterLocked(gen);
964        return gen;
965    }
966
967    /**
968     * Generate and install a new filter program.
969     */
970    @GuardedBy("this")
971    @VisibleForTesting
972    void installNewProgramLocked() {
973        purgeExpiredRasLocked();
974        ArrayList<Ra> rasToFilter = new ArrayList<>();
975        final byte[] program;
976        long programMinLifetime = Long.MAX_VALUE;
977        try {
978            // Step 1: Determine how many RA filters we can fit in the program.
979            ApfGenerator gen = beginProgramLocked();
980            for (Ra ra : mRas) {
981                ra.generateFilterLocked(gen);
982                // Stop if we get too big.
983                if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break;
984                rasToFilter.add(ra);
985            }
986            // Step 2: Actually generate the program
987            gen = beginProgramLocked();
988            for (Ra ra : rasToFilter) {
989                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
990            }
991            // Execution will reach the end of the program if no filters match, which will pass the
992            // packet to the AP.
993            program = gen.generate();
994        } catch (IllegalInstructionException|IllegalStateException e) {
995            Log.e(TAG, "Failed to generate APF program.", e);
996            return;
997        }
998        final long now = currentTimeSeconds();
999        mLastTimeInstalledProgram = now;
1000        mLastInstalledProgramMinLifetime = programMinLifetime;
1001        mLastInstalledProgram = program;
1002        mNumProgramUpdates++;
1003
1004        if (VDBG) {
1005            hexDump("Installing filter: ", program, program.length);
1006        }
1007        mIpManagerCallback.installPacketFilter(program);
1008        logApfProgramEventLocked(now);
1009        mLastInstallEvent = new ApfProgramEvent();
1010        mLastInstallEvent.lifetime = programMinLifetime;
1011        mLastInstallEvent.filteredRas = rasToFilter.size();
1012        mLastInstallEvent.currentRas = mRas.size();
1013        mLastInstallEvent.programLength = program.length;
1014        mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
1015    }
1016
1017    private void logApfProgramEventLocked(long now) {
1018        if (mLastInstallEvent == null) {
1019            return;
1020        }
1021        ApfProgramEvent ev = mLastInstallEvent;
1022        mLastInstallEvent = null;
1023        ev.actualLifetime = now - mLastTimeInstalledProgram;
1024        if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
1025            return;
1026        }
1027        mMetricsLog.log(ev);
1028    }
1029
1030    /**
1031     * Returns {@code true} if a new program should be installed because the current one dies soon.
1032     */
1033    private boolean shouldInstallnewProgram() {
1034        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
1035        return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
1036    }
1037
1038    private void hexDump(String msg, byte[] packet, int length) {
1039        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
1040    }
1041
1042    @GuardedBy("this")
1043    private void purgeExpiredRasLocked() {
1044        for (int i = 0; i < mRas.size();) {
1045            if (mRas.get(i).isExpired()) {
1046                log("Expiring " + mRas.get(i));
1047                mRas.remove(i);
1048            } else {
1049                i++;
1050            }
1051        }
1052    }
1053
1054    /**
1055     * Process an RA packet, updating the list of known RAs and installing a new APF program
1056     * if the current APF program should be updated.
1057     * @return a ProcessRaResult enum describing what action was performed.
1058     */
1059    @VisibleForTesting
1060    synchronized ProcessRaResult processRa(byte[] packet, int length) {
1061        if (VDBG) hexDump("Read packet = ", packet, length);
1062
1063        // Have we seen this RA before?
1064        for (int i = 0; i < mRas.size(); i++) {
1065            Ra ra = mRas.get(i);
1066            if (ra.matches(packet, length)) {
1067                if (VDBG) log("matched RA " + ra);
1068                // Update lifetimes.
1069                ra.mLastSeen = currentTimeSeconds();
1070                ra.mMinLifetime = ra.minLifetime(packet, length);
1071                ra.seenCount++;
1072
1073                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
1074                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
1075                // until the filter program exceeds the maximum filter program size allowed by the
1076                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
1077                // filter program.
1078                // TODO: consider sorting the RAs in order of increasing expiry time as well.
1079                // Swap to front of array.
1080                mRas.add(0, mRas.remove(i));
1081
1082                // If the current program doesn't expire for a while, don't update.
1083                if (shouldInstallnewProgram()) {
1084                    installNewProgramLocked();
1085                    return ProcessRaResult.UPDATE_EXPIRY;
1086                }
1087                return ProcessRaResult.MATCH;
1088            }
1089        }
1090        purgeExpiredRasLocked();
1091        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
1092        if (mRas.size() >= MAX_RAS) {
1093            return ProcessRaResult.DROPPED;
1094        }
1095        final Ra ra;
1096        try {
1097            ra = new Ra(packet, length);
1098        } catch (Exception e) {
1099            Log.e(TAG, "Error parsing RA", e);
1100            return ProcessRaResult.PARSE_ERROR;
1101        }
1102        // Ignore 0 lifetime RAs.
1103        if (ra.isExpired()) {
1104            return ProcessRaResult.ZERO_LIFETIME;
1105        }
1106        log("Adding " + ra);
1107        mRas.add(ra);
1108        installNewProgramLocked();
1109        return ProcessRaResult.UPDATE_NEW_RA;
1110    }
1111
1112    /**
1113     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
1114     * filtering using APF programs.
1115     */
1116    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
1117            NetworkInterface networkInterface, IpManager.Callback ipManagerCallback,
1118            boolean multicastFilter, boolean ieee802_3Filter) {
1119        if (apfCapabilities == null || networkInterface == null) return null;
1120        if (apfCapabilities.apfVersionSupported == 0) return null;
1121        if (apfCapabilities.maximumApfProgramSize < 512) {
1122            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
1123            return null;
1124        }
1125        // For now only support generating programs for Ethernet frames. If this restriction is
1126        // lifted:
1127        //   1. the program generator will need its offsets adjusted.
1128        //   2. the packet filter attached to our packet socket will need its offset adjusted.
1129        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
1130        if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) {
1131            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
1132            return null;
1133        }
1134        return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback,
1135                multicastFilter, ieee802_3Filter, new IpConnectivityLog());
1136    }
1137
1138    public synchronized void shutdown() {
1139        if (mReceiveThread != null) {
1140            log("shutting down");
1141            mReceiveThread.halt();  // Also closes socket.
1142            mReceiveThread = null;
1143        }
1144        mRas.clear();
1145    }
1146
1147    public synchronized void setMulticastFilter(boolean isEnabled) {
1148        if (mMulticastFilter == isEnabled) {
1149            return;
1150        }
1151        mMulticastFilter = isEnabled;
1152        if (!isEnabled) {
1153            mNumProgramUpdatesAllowingMulticast++;
1154        }
1155        installNewProgramLocked();
1156    }
1157
1158    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
1159    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
1160        LinkAddress ipv4Address = null;
1161        for (LinkAddress address : lp.getLinkAddresses()) {
1162            if (!(address.getAddress() instanceof Inet4Address)) {
1163                continue;
1164            }
1165            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
1166                // More than one IPv4 address, abort.
1167                return null;
1168            }
1169            ipv4Address = address;
1170        }
1171        return ipv4Address;
1172    }
1173
1174    public synchronized void setLinkProperties(LinkProperties lp) {
1175        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
1176        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
1177        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
1178        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
1179        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
1180            return;
1181        }
1182        mIPv4Address = addr;
1183        mIPv4PrefixLength = prefix;
1184        installNewProgramLocked();
1185    }
1186
1187    public synchronized void dump(IndentingPrintWriter pw) {
1188        pw.println("Capabilities: " + mApfCapabilities);
1189        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
1190        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
1191        try {
1192            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
1193        } catch (UnknownHostException|NullPointerException e) {}
1194
1195        if (mLastTimeInstalledProgram == 0) {
1196            pw.println("No program installed.");
1197            return;
1198        }
1199        pw.println("Program updates: " + mNumProgramUpdates);
1200        pw.println(String.format(
1201                "Last program length %d, installed %ds ago, lifetime %ds",
1202                mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
1203                mLastInstalledProgramMinLifetime));
1204
1205        pw.println("RA filters:");
1206        pw.increaseIndent();
1207        for (Ra ra: mRas) {
1208            pw.println(ra);
1209            pw.increaseIndent();
1210            pw.println(String.format(
1211                    "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
1212            if (DBG) {
1213                pw.println("Last match:");
1214                pw.increaseIndent();
1215                pw.println(ra.getLastMatchingPacket());
1216                pw.decreaseIndent();
1217            }
1218            pw.decreaseIndent();
1219        }
1220        pw.decreaseIndent();
1221
1222        if (DBG) {
1223            pw.println("Last program:");
1224            pw.increaseIndent();
1225            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
1226            pw.decreaseIndent();
1227        }
1228    }
1229
1230    // TODO: move to android.net.NetworkUtils
1231    @VisibleForTesting
1232    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
1233        return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
1234    }
1235}
1236