Home | History | Annotate | Download | only in apf
      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 
     17 package android.net.apf;
     18 
     19 import static android.system.OsConstants.*;
     20 
     21 import android.os.SystemClock;
     22 import android.net.LinkAddress;
     23 import android.net.LinkProperties;
     24 import android.net.NetworkUtils;
     25 import android.net.apf.ApfGenerator;
     26 import android.net.apf.ApfGenerator.IllegalInstructionException;
     27 import android.net.apf.ApfGenerator.Register;
     28 import android.net.ip.IpManager;
     29 import android.net.metrics.ApfProgramEvent;
     30 import android.net.metrics.ApfStats;
     31 import android.net.metrics.IpConnectivityLog;
     32 import android.net.metrics.RaEvent;
     33 import android.system.ErrnoException;
     34 import android.system.Os;
     35 import android.system.PacketSocketAddress;
     36 import android.text.format.DateUtils;
     37 import android.util.Log;
     38 import android.util.Pair;
     39 
     40 import com.android.internal.annotations.GuardedBy;
     41 import com.android.internal.annotations.VisibleForTesting;
     42 import com.android.internal.util.HexDump;
     43 import com.android.internal.util.IndentingPrintWriter;
     44 
     45 import java.io.FileDescriptor;
     46 import java.io.IOException;
     47 import java.lang.Thread;
     48 import java.net.Inet4Address;
     49 import java.net.Inet6Address;
     50 import java.net.InetAddress;
     51 import java.net.NetworkInterface;
     52 import java.net.SocketException;
     53 import java.net.UnknownHostException;
     54 import java.nio.ByteBuffer;
     55 import java.nio.BufferUnderflowException;
     56 import java.util.ArrayList;
     57 import java.util.Arrays;
     58 
     59 import 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  */
     79 public 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