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