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.net.util.NetworkConstants.*;
     20 import static android.system.OsConstants.*;
     21 import static com.android.internal.util.BitUtils.bytesToBEInt;
     22 import static com.android.internal.util.BitUtils.getUint16;
     23 import static com.android.internal.util.BitUtils.getUint32;
     24 import static com.android.internal.util.BitUtils.getUint8;
     25 import static com.android.internal.util.BitUtils.uint32;
     26 
     27 import android.annotation.Nullable;
     28 import android.content.BroadcastReceiver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.IntentFilter;
     32 import android.net.LinkAddress;
     33 import android.net.LinkProperties;
     34 import android.net.NetworkUtils;
     35 import android.net.apf.ApfGenerator.IllegalInstructionException;
     36 import android.net.apf.ApfGenerator.Register;
     37 import android.net.ip.IpClient;
     38 import android.net.metrics.ApfProgramEvent;
     39 import android.net.metrics.ApfStats;
     40 import android.net.metrics.IpConnectivityLog;
     41 import android.net.metrics.RaEvent;
     42 import android.net.util.InterfaceParams;
     43 import android.os.PowerManager;
     44 import android.os.SystemClock;
     45 import android.system.ErrnoException;
     46 import android.system.Os;
     47 import android.system.PacketSocketAddress;
     48 import android.text.format.DateUtils;
     49 import android.util.Log;
     50 import android.util.Pair;
     51 import com.android.internal.annotations.GuardedBy;
     52 import com.android.internal.annotations.VisibleForTesting;
     53 import com.android.internal.util.HexDump;
     54 import com.android.internal.util.IndentingPrintWriter;
     55 import java.io.FileDescriptor;
     56 import java.io.IOException;
     57 import java.net.Inet4Address;
     58 import java.net.Inet6Address;
     59 import java.net.InetAddress;
     60 import java.net.SocketException;
     61 import java.net.UnknownHostException;
     62 import java.nio.BufferUnderflowException;
     63 import java.nio.ByteBuffer;
     64 import java.util.ArrayList;
     65 import java.util.Arrays;
     66 import libcore.io.IoBridge;
     67 
     68 /**
     69  * For networks that support packet filtering via APF programs, {@code ApfFilter}
     70  * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
     71  * filter out redundant duplicate ones.
     72  *
     73  * Threading model:
     74  * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
     75  * know what RAs to filter for, thus generating APF programs is dependent on mRas.
     76  * mRas can be accessed by multiple threads:
     77  * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
     78  * - callers of:
     79  *    - setMulticastFilter(), which can cause an APF program to be generated.
     80  *    - dump(), which dumps mRas among other things.
     81  *    - shutdown(), which clears mRas.
     82  * So access to mRas is synchronized.
     83  *
     84  * @hide
     85  */
     86 public class ApfFilter {
     87 
     88     // Helper class for specifying functional filter parameters.
     89     public static class ApfConfiguration {
     90         public ApfCapabilities apfCapabilities;
     91         public boolean multicastFilter;
     92         public boolean ieee802_3Filter;
     93         public int[] ethTypeBlackList;
     94     }
     95 
     96     // Enums describing the outcome of receiving an RA packet.
     97     private static enum ProcessRaResult {
     98         MATCH,          // Received RA matched a known RA
     99         DROPPED,        // Received RA ignored due to MAX_RAS
    100         PARSE_ERROR,    // Received RA could not be parsed
    101         ZERO_LIFETIME,  // Received RA had 0 lifetime
    102         UPDATE_NEW_RA,  // APF program updated for new RA
    103         UPDATE_EXPIRY   // APF program updated for expiry
    104     }
    105 
    106     /**
    107      * APF packet counters.
    108      *
    109      * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
    110      * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
    111      * the last writable 32bit word.
    112      */
    113     @VisibleForTesting
    114     private static enum Counter {
    115         RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
    116         TOTAL_PACKETS,
    117         PASSED_ARP,
    118         PASSED_DHCP,
    119         PASSED_IPV4,
    120         PASSED_IPV6_NON_ICMP,
    121         PASSED_IPV4_UNICAST,
    122         PASSED_IPV6_ICMP,
    123         PASSED_IPV6_UNICAST_NON_ICMP,
    124         PASSED_ARP_NON_IPV4,
    125         PASSED_ARP_UNKNOWN,
    126         PASSED_ARP_UNICAST_REPLY,
    127         PASSED_NON_IP_UNICAST,
    128         DROPPED_ETH_BROADCAST,
    129         DROPPED_RA,
    130         DROPPED_GARP_REPLY,
    131         DROPPED_ARP_OTHER_HOST,
    132         DROPPED_IPV4_L2_BROADCAST,
    133         DROPPED_IPV4_BROADCAST_ADDR,
    134         DROPPED_IPV4_BROADCAST_NET,
    135         DROPPED_IPV4_MULTICAST,
    136         DROPPED_IPV6_ROUTER_SOLICITATION,
    137         DROPPED_IPV6_MULTICAST_NA,
    138         DROPPED_IPV6_MULTICAST,
    139         DROPPED_IPV6_MULTICAST_PING,
    140         DROPPED_IPV6_NON_ICMP_MULTICAST,
    141         DROPPED_802_3_FRAME,
    142         DROPPED_ETHERTYPE_BLACKLISTED;
    143 
    144         // Returns the negative byte offset from the end of the APF data segment for
    145         // a given counter.
    146         public int offset() {
    147             return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
    148         }
    149 
    150         // Returns the total size of the data segment in bytes.
    151         public static int totalSize() {
    152             return (Counter.class.getEnumConstants().length - 1) * 4;
    153         }
    154     }
    155 
    156     /**
    157      * When APFv4 is supported, loads R1 with the offset of the specified counter.
    158      */
    159     private void maybeSetCounter(ApfGenerator gen, Counter c) {
    160         if (mApfCapabilities.hasDataAccess()) {
    161             gen.addLoadImmediate(Register.R1, c.offset());
    162         }
    163     }
    164 
    165     // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
    166     // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
    167     private final String mCountAndPassLabel;
    168     private final String mCountAndDropLabel;
    169 
    170     // Thread to listen for RAs.
    171     @VisibleForTesting
    172     class ReceiveThread extends Thread {
    173         private final byte[] mPacket = new byte[1514];
    174         private final FileDescriptor mSocket;
    175         private final long mStart = SystemClock.elapsedRealtime();
    176         private final ApfStats mStats = new ApfStats();
    177 
    178         private volatile boolean mStopped;
    179 
    180         public ReceiveThread(FileDescriptor socket) {
    181             mSocket = socket;
    182         }
    183 
    184         public void halt() {
    185             mStopped = true;
    186             try {
    187                 // Interrupts the read() call the thread is blocked in.
    188                 IoBridge.closeAndSignalBlockedThreads(mSocket);
    189             } catch (IOException ignored) {}
    190         }
    191 
    192         @Override
    193         public void run() {
    194             log("begin monitoring");
    195             while (!mStopped) {
    196                 try {
    197                     int length = Os.read(mSocket, mPacket, 0, mPacket.length);
    198                     updateStats(processRa(mPacket, length));
    199                 } catch (IOException|ErrnoException e) {
    200                     if (!mStopped) {
    201                         Log.e(TAG, "Read error", e);
    202                     }
    203                 }
    204             }
    205             logStats();
    206         }
    207 
    208         private void updateStats(ProcessRaResult result) {
    209             mStats.receivedRas++;
    210             switch(result) {
    211                 case MATCH:
    212                     mStats.matchingRas++;
    213                     return;
    214                 case DROPPED:
    215                     mStats.droppedRas++;
    216                     return;
    217                 case PARSE_ERROR:
    218                     mStats.parseErrors++;
    219                     return;
    220                 case ZERO_LIFETIME:
    221                     mStats.zeroLifetimeRas++;
    222                     return;
    223                 case UPDATE_EXPIRY:
    224                     mStats.matchingRas++;
    225                     mStats.programUpdates++;
    226                     return;
    227                 case UPDATE_NEW_RA:
    228                     mStats.programUpdates++;
    229                     return;
    230             }
    231         }
    232 
    233         private void logStats() {
    234             final long nowMs = SystemClock.elapsedRealtime();
    235             synchronized (this) {
    236                 mStats.durationMs = nowMs - mStart;
    237                 mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize;
    238                 mStats.programUpdatesAll = mNumProgramUpdates;
    239                 mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast;
    240                 mMetricsLog.log(mStats);
    241                 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
    242             }
    243         }
    244     }
    245 
    246     private static final String TAG = "ApfFilter";
    247     private static final boolean DBG = true;
    248     private static final boolean VDBG = false;
    249 
    250     private static final int ETH_HEADER_LEN = 14;
    251     private static final int ETH_DEST_ADDR_OFFSET = 0;
    252     private static final int ETH_ETHERTYPE_OFFSET = 12;
    253     private static final int ETH_TYPE_MIN = 0x0600;
    254     private static final int ETH_TYPE_MAX = 0xFFFF;
    255     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
    256             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
    257     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
    258     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
    259     // Endianness is not an issue for this constant because the APF interpreter always operates in
    260     // network byte order.
    261     private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
    262     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
    263     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
    264     private static final int IPV4_ANY_HOST_ADDRESS = 0;
    265     private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
    266 
    267     // Traffic class and Flow label are not byte aligned. Luckily we
    268     // don't care about either value so we'll consider bytes 1-3 of the
    269     // IPv6 header as don't care.
    270     private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
    271     private static final int IPV6_FLOW_LABEL_LEN = 3;
    272     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
    273     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
    274     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
    275     private static final int IPV6_HEADER_LEN = 40;
    276     // The IPv6 all nodes address ff02::1
    277     private static final byte[] IPV6_ALL_NODES_ADDRESS =
    278             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
    279 
    280     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
    281 
    282     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
    283     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
    284     private static final int UDP_HEADER_LEN = 8;
    285 
    286     private static final int DHCP_CLIENT_PORT = 68;
    287     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
    288     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
    289 
    290     private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
    291     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
    292     private static final short ARP_OPCODE_REQUEST = 1;
    293     private static final short ARP_OPCODE_REPLY = 2;
    294     private static final byte[] ARP_IPV4_HEADER = {
    295             0, 1, // Hardware type: Ethernet (1)
    296             8, 0, // Protocol type: IP (0x0800)
    297             6,    // Hardware size: 6
    298             4,    // Protocol size: 4
    299     };
    300     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
    301     // Do not log ApfProgramEvents whose actual lifetimes was less than this.
    302     private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
    303     // Limit on the Black List size to cap on program usage for this
    304     // TODO: Select a proper max length
    305     private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
    306 
    307     private final ApfCapabilities mApfCapabilities;
    308     private final IpClient.Callback mIpClientCallback;
    309     private final InterfaceParams mInterfaceParams;
    310     private final IpConnectivityLog mMetricsLog;
    311 
    312     @VisibleForTesting
    313     byte[] mHardwareAddress;
    314     @VisibleForTesting
    315     ReceiveThread mReceiveThread;
    316     @GuardedBy("this")
    317     private long mUniqueCounter;
    318     @GuardedBy("this")
    319     private boolean mMulticastFilter;
    320     @GuardedBy("this")
    321     private boolean mInDozeMode;
    322     private final boolean mDrop802_3Frames;
    323     private final int[] mEthTypeBlackList;
    324 
    325     // Detects doze mode state transitions.
    326     private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
    327         @Override
    328         public void onReceive(Context context, Intent intent) {
    329             String action = intent.getAction();
    330             if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
    331                 PowerManager powerManager =
    332                         (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    333                 final boolean deviceIdle = powerManager.isDeviceIdleMode();
    334                 setDozeMode(deviceIdle);
    335             }
    336         }
    337     };
    338     private final Context mContext;
    339 
    340     // Our IPv4 address, if we have just one, otherwise null.
    341     @GuardedBy("this")
    342     private byte[] mIPv4Address;
    343     // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
    344     @GuardedBy("this")
    345     private int mIPv4PrefixLength;
    346 
    347     @VisibleForTesting
    348     ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
    349             IpClient.Callback ipClientCallback, IpConnectivityLog log) {
    350         mApfCapabilities = config.apfCapabilities;
    351         mIpClientCallback = ipClientCallback;
    352         mInterfaceParams = ifParams;
    353         mMulticastFilter = config.multicastFilter;
    354         mDrop802_3Frames = config.ieee802_3Filter;
    355         mContext = context;
    356 
    357         if (mApfCapabilities.hasDataAccess()) {
    358             mCountAndPassLabel = "countAndPass";
    359             mCountAndDropLabel = "countAndDrop";
    360         } else {
    361             // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
    362             // preserving the original pre-APFv4 behavior.
    363             mCountAndPassLabel = ApfGenerator.PASS_LABEL;
    364             mCountAndDropLabel = ApfGenerator.DROP_LABEL;
    365         }
    366 
    367         // Now fill the black list from the passed array
    368         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
    369 
    370         mMetricsLog = log;
    371 
    372         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
    373         maybeStartFilter();
    374 
    375         // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
    376         mContext.registerReceiver(mDeviceIdleReceiver,
    377                 new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
    378     }
    379 
    380     public synchronized void setDataSnapshot(byte[] data) {
    381         mDataSnapshot = data;
    382     }
    383 
    384     private void log(String s) {
    385         Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
    386     }
    387 
    388     @GuardedBy("this")
    389     private long getUniqueNumberLocked() {
    390         return mUniqueCounter++;
    391     }
    392 
    393     @GuardedBy("this")
    394     private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
    395         ArrayList<Integer> bl = new ArrayList<Integer>();
    396 
    397         for (int p : ethTypeBlackList) {
    398             // Check if the protocol is a valid ether type
    399             if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
    400                 continue;
    401             }
    402 
    403             // Check if the protocol is not repeated in the passed array
    404             if (bl.contains(p)) {
    405                 continue;
    406             }
    407 
    408             // Check if list reach its max size
    409             if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
    410                 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
    411                         ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
    412                 break;
    413             }
    414 
    415             // Now add the protocol to the list
    416             bl.add(p);
    417         }
    418 
    419         return bl.stream().mapToInt(Integer::intValue).toArray();
    420     }
    421 
    422     /**
    423      * Attempt to start listening for RAs and, if RAs are received, generating and installing
    424      * filters to ignore useless RAs.
    425      */
    426     @VisibleForTesting
    427     void maybeStartFilter() {
    428         FileDescriptor socket;
    429         try {
    430             mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
    431             synchronized(this) {
    432                 // Clear the APF memory to reset all counters upon connecting to the first AP
    433                 // in an SSID. This is limited to APFv4 devices because this large write triggers
    434                 // a crash on some older devices (b/78905546).
    435                 if (mApfCapabilities.hasDataAccess()) {
    436                     byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
    437                     mIpClientCallback.installPacketFilter(zeroes);
    438                 }
    439 
    440                 // Install basic filters
    441                 installNewProgramLocked();
    442             }
    443             socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
    444             PacketSocketAddress addr = new PacketSocketAddress(
    445                     (short) ETH_P_IPV6, mInterfaceParams.index);
    446             Os.bind(socket, addr);
    447             NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
    448         } catch(SocketException|ErrnoException e) {
    449             Log.e(TAG, "Error starting filter", e);
    450             return;
    451         }
    452         mReceiveThread = new ReceiveThread(socket);
    453         mReceiveThread.start();
    454     }
    455 
    456     // Returns seconds since device boot.
    457     @VisibleForTesting
    458     protected long currentTimeSeconds() {
    459         return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
    460     }
    461 
    462     public static class InvalidRaException extends Exception {
    463         public InvalidRaException(String m) {
    464             super(m);
    465         }
    466     }
    467 
    468     // A class to hold information about an RA.
    469     @VisibleForTesting
    470     class Ra {
    471         // From RFC4861:
    472         private static final int ICMP6_RA_HEADER_LEN = 16;
    473         private static final int ICMP6_RA_CHECKSUM_OFFSET =
    474                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
    475         private static final int ICMP6_RA_CHECKSUM_LEN = 2;
    476         private static final int ICMP6_RA_OPTION_OFFSET =
    477                 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
    478         private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
    479                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
    480         private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
    481         // Prefix information option.
    482         private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
    483         private static final int ICMP6_PREFIX_OPTION_LEN = 32;
    484         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
    485         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
    486         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
    487         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
    488 
    489         // From RFC6106: Recursive DNS Server option
    490         private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
    491         // From RFC6106: DNS Search List option
    492         private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
    493 
    494         // From RFC4191: Route Information option
    495         private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
    496         // Above three options all have the same format:
    497         private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
    498         private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
    499 
    500         // Note: mPacket's position() cannot be assumed to be reset.
    501         private final ByteBuffer mPacket;
    502         // List of binary ranges that include the whole packet except the lifetimes.
    503         // Pairs consist of offset and length.
    504         private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
    505                 new ArrayList<Pair<Integer, Integer>>();
    506         // Minimum lifetime in packet
    507         long mMinLifetime;
    508         // When the packet was last captured, in seconds since Unix Epoch
    509         long mLastSeen;
    510 
    511         // For debugging only. Offsets into the packet where PIOs are.
    512         private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
    513 
    514         // For debugging only. Offsets into the packet where RDNSS options are.
    515         private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
    516 
    517         // For debugging only. How many times this RA was seen.
    518         int seenCount = 0;
    519 
    520         // For debugging only. Returns the hex representation of the last matching packet.
    521         String getLastMatchingPacket() {
    522             return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
    523                     false /* lowercase */);
    524         }
    525 
    526         // For debugging only. Returns the string representation of the IPv6 address starting at
    527         // position pos in the packet.
    528         private String IPv6AddresstoString(int pos) {
    529             try {
    530                 byte[] array = mPacket.array();
    531                 // Can't just call copyOfRange() and see if it throws, because if it reads past the
    532                 // end it pads with zeros instead of throwing.
    533                 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
    534                     return "???";
    535                 }
    536                 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
    537                 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
    538                 return address.getHostAddress();
    539             } catch (UnsupportedOperationException e) {
    540                 // array() failed. Cannot happen, mPacket is array-backed and read-write.
    541                 return "???";
    542             } catch (ClassCastException|UnknownHostException e) {
    543                 // Cannot happen.
    544                 return "???";
    545             }
    546         }
    547 
    548         // Can't be static because it's in a non-static inner class.
    549         // TODO: Make this static once RA is its own class.
    550         private void prefixOptionToString(StringBuffer sb, int offset) {
    551             String prefix = IPv6AddresstoString(offset + 16);
    552             int length = getUint8(mPacket, offset + 2);
    553             long valid = getUint32(mPacket, offset + 4);
    554             long preferred = getUint32(mPacket, offset + 8);
    555             sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
    556         }
    557 
    558         private void rdnssOptionToString(StringBuffer sb, int offset) {
    559             int optLen = getUint8(mPacket, offset + 1) * 8;
    560             if (optLen < 24) return;  // Malformed or empty.
    561             long lifetime = getUint32(mPacket, offset + 4);
    562             int numServers = (optLen - 8) / 16;
    563             sb.append("DNS ").append(lifetime).append("s");
    564             for (int server = 0; server < numServers; server++) {
    565                 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
    566             }
    567         }
    568 
    569         public String toString() {
    570             try {
    571                 StringBuffer sb = new StringBuffer();
    572                 sb.append(String.format("RA %s -> %s %ds ",
    573                         IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
    574                         IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
    575                         getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
    576                 for (int i: mPrefixOptionOffsets) {
    577                     prefixOptionToString(sb, i);
    578                 }
    579                 for (int i: mRdnssOptionOffsets) {
    580                     rdnssOptionToString(sb, i);
    581                 }
    582                 return sb.toString();
    583             } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
    584                 return "<Malformed RA>";
    585             }
    586         }
    587 
    588         /**
    589          * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
    590          * Assumes mPacket.position() is as far as we've parsed the packet.
    591          * @param lastNonLifetimeStart offset within packet of where the last binary range of
    592          *                             data not including a lifetime.
    593          * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
    594          * @param lifetimeLength length of the next lifetime data.
    595          * @return offset within packet of where the next binary range of data not including
    596          *         a lifetime. This can be passed into the next invocation of this function
    597          *         via {@code lastNonLifetimeStart}.
    598          */
    599         private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
    600                 int lifetimeLength) {
    601             lifetimeOffset += mPacket.position();
    602             mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
    603                     lifetimeOffset - lastNonLifetimeStart));
    604             return lifetimeOffset + lifetimeLength;
    605         }
    606 
    607         private int addNonLifetimeU32(int lastNonLifetimeStart) {
    608             return addNonLifetime(lastNonLifetimeStart,
    609                     ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
    610         }
    611 
    612         // Note that this parses RA and may throw InvalidRaException (from
    613         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
    614         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
    615         // specifications.
    616         Ra(byte[] packet, int length) throws InvalidRaException {
    617             if (length < ICMP6_RA_OPTION_OFFSET) {
    618                 throw new InvalidRaException("Not an ICMP6 router advertisement");
    619             }
    620 
    621             mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
    622             mLastSeen = currentTimeSeconds();
    623 
    624             // Sanity check packet in case a packet arrives before we attach RA filter
    625             // to our packet socket. b/29586253
    626             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
    627                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
    628                     getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
    629                 throw new InvalidRaException("Not an ICMP6 router advertisement");
    630             }
    631 
    632 
    633             RaEvent.Builder builder = new RaEvent.Builder();
    634 
    635             // Ignore the flow label and low 4 bits of traffic class.
    636             int lastNonLifetimeStart = addNonLifetime(0,
    637                     IPV6_FLOW_LABEL_OFFSET,
    638                     IPV6_FLOW_LABEL_LEN);
    639 
    640             // Ignore the checksum.
    641             lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
    642                     ICMP6_RA_CHECKSUM_OFFSET,
    643                     ICMP6_RA_CHECKSUM_LEN);
    644 
    645             // Parse router lifetime
    646             lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
    647                     ICMP6_RA_ROUTER_LIFETIME_OFFSET,
    648                     ICMP6_RA_ROUTER_LIFETIME_LEN);
    649             builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
    650 
    651             // Ensures that the RA is not truncated.
    652             mPacket.position(ICMP6_RA_OPTION_OFFSET);
    653             while (mPacket.hasRemaining()) {
    654                 final int position = mPacket.position();
    655                 final int optionType = getUint8(mPacket, position);
    656                 final int optionLength = getUint8(mPacket, position + 1) * 8;
    657                 long lifetime;
    658                 switch (optionType) {
    659                     case ICMP6_PREFIX_OPTION_TYPE:
    660                         // Parse valid lifetime
    661                         lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
    662                                 ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
    663                                 ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
    664                         lifetime = getUint32(mPacket,
    665                                 position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
    666                         builder.updatePrefixValidLifetime(lifetime);
    667                         // Parse preferred lifetime
    668                         lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
    669                                 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
    670                                 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
    671                         lifetime = getUint32(mPacket,
    672                                 position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
    673                         builder.updatePrefixPreferredLifetime(lifetime);
    674                         mPrefixOptionOffsets.add(position);
    675                         break;
    676                     // These three options have the same lifetime offset and size, and
    677                     // are processed with the same specialized addNonLifetimeU32:
    678                     case ICMP6_RDNSS_OPTION_TYPE:
    679                         mRdnssOptionOffsets.add(position);
    680                         lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
    681                         lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
    682                         builder.updateRdnssLifetime(lifetime);
    683                         break;
    684                     case ICMP6_ROUTE_INFO_OPTION_TYPE:
    685                         lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
    686                         lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
    687                         builder.updateRouteInfoLifetime(lifetime);
    688                         break;
    689                     case ICMP6_DNSSL_OPTION_TYPE:
    690                         lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
    691                         lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
    692                         builder.updateDnsslLifetime(lifetime);
    693                         break;
    694                     default:
    695                         // RFC4861 section 4.2 dictates we ignore unknown options for fowards
    696                         // compatibility.
    697                         break;
    698                 }
    699                 if (optionLength <= 0) {
    700                     throw new InvalidRaException(String.format(
    701                         "Invalid option length opt=%d len=%d", optionType, optionLength));
    702                 }
    703                 mPacket.position(position + optionLength);
    704             }
    705             // Mark non-lifetime bytes since last lifetime.
    706             addNonLifetime(lastNonLifetimeStart, 0, 0);
    707             mMinLifetime = minLifetime(packet, length);
    708             mMetricsLog.log(builder.build());
    709         }
    710 
    711         // Ignoring lifetimes (which may change) does {@code packet} match this RA?
    712         boolean matches(byte[] packet, int length) {
    713             if (length != mPacket.capacity()) return false;
    714             byte[] referencePacket = mPacket.array();
    715             for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
    716                 for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
    717                     if (packet[i] != referencePacket[i]) return false;
    718                 }
    719             }
    720             return true;
    721         }
    722 
    723         // What is the minimum of all lifetimes within {@code packet} in seconds?
    724         // Precondition: matches(packet, length) already returned true.
    725         long minLifetime(byte[] packet, int length) {
    726             long minLifetime = Long.MAX_VALUE;
    727             // Wrap packet in ByteBuffer so we can read big-endian values easily
    728             ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
    729             for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
    730                 int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
    731 
    732                 // The flow label is in mNonLifetimes, but it's not a lifetime.
    733                 if (offset == IPV6_FLOW_LABEL_OFFSET) {
    734                     continue;
    735                 }
    736 
    737                 // The checksum is in mNonLifetimes, but it's not a lifetime.
    738                 if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
    739                     continue;
    740                 }
    741 
    742                 final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
    743                 final long optionLifetime;
    744                 switch (lifetimeLength) {
    745                     case 2:
    746                         optionLifetime = getUint16(byteBuffer, offset);
    747                         break;
    748                     case 4:
    749                         optionLifetime = getUint32(byteBuffer, offset);
    750                         break;
    751                     default:
    752                         throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
    753                 }
    754                 minLifetime = Math.min(minLifetime, optionLifetime);
    755             }
    756             return minLifetime;
    757         }
    758 
    759         // How many seconds does this RA's have to live, taking into account the fact
    760         // that we might have seen it a while ago.
    761         long currentLifetime() {
    762             return mMinLifetime - (currentTimeSeconds() - mLastSeen);
    763         }
    764 
    765         boolean isExpired() {
    766             // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
    767             // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
    768             return currentLifetime() <= 0;
    769         }
    770 
    771         // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
    772         // Jump to the next filter if packet doesn't match this RA.
    773         @GuardedBy("ApfFilter.this")
    774         long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
    775             String nextFilterLabel = "Ra" + getUniqueNumberLocked();
    776             // Skip if packet is not the right size
    777             gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
    778             gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
    779             int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
    780             // Skip filter if expired
    781             gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
    782             gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
    783             for (int i = 0; i < mNonLifetimes.size(); i++) {
    784                 // Generate code to match the packet bytes
    785                 Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
    786                 // Don't generate JNEBS instruction for 0 bytes as it always fails the
    787                 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
    788                 // the number of bytes to compare. nonLifetime is zero between the
    789                 // valid and preferred lifetimes in the prefix option.
    790                 if (nonLifetime.second != 0) {
    791                     gen.addLoadImmediate(Register.R0, nonLifetime.first);
    792                     gen.addJumpIfBytesNotEqual(Register.R0,
    793                             Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
    794                                                nonLifetime.first + nonLifetime.second),
    795                             nextFilterLabel);
    796                 }
    797                 // Generate code to test the lifetimes haven't gone down too far
    798                 if ((i + 1) < mNonLifetimes.size()) {
    799                     Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
    800                     int offset = nonLifetime.first + nonLifetime.second;
    801 
    802                     // Skip the Flow label.
    803                     if (offset == IPV6_FLOW_LABEL_OFFSET) {
    804                         continue;
    805                     }
    806                     // Skip the checksum.
    807                     if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
    808                         continue;
    809                     }
    810                     int length = nextNonLifetime.first - offset;
    811                     switch (length) {
    812                         case 4: gen.addLoad32(Register.R0, offset); break;
    813                         case 2: gen.addLoad16(Register.R0, offset); break;
    814                         default: throw new IllegalStateException("bogus lifetime size " + length);
    815                     }
    816                     gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
    817                 }
    818             }
    819             maybeSetCounter(gen, Counter.DROPPED_RA);
    820             gen.addJump(mCountAndDropLabel);
    821             gen.defineLabel(nextFilterLabel);
    822             return filterLifetime;
    823         }
    824     }
    825 
    826     // Maximum number of RAs to filter for.
    827     private static final int MAX_RAS = 10;
    828 
    829     @GuardedBy("this")
    830     private ArrayList<Ra> mRas = new ArrayList<Ra>();
    831 
    832     // There is always some marginal benefit to updating the installed APF program when an RA is
    833     // seen because we can extend the program's lifetime slightly, but there is some cost to
    834     // updating the program, so don't bother unless the program is going to expire soon. This
    835     // constant defines "soon" in seconds.
    836     private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
    837     // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
    838     // see a refresh.  Using half the lifetime might be a good idea except for the fact that
    839     // packets may be dropped, so let's use 6.
    840     private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
    841 
    842     // When did we last install a filter program? In seconds since Unix Epoch.
    843     @GuardedBy("this")
    844     private long mLastTimeInstalledProgram;
    845     // How long should the last installed filter program live for? In seconds.
    846     @GuardedBy("this")
    847     private long mLastInstalledProgramMinLifetime;
    848     @GuardedBy("this")
    849     private ApfProgramEvent mLastInstallEvent;
    850 
    851     // For debugging only. The last program installed.
    852     @GuardedBy("this")
    853     private byte[] mLastInstalledProgram;
    854 
    855     /**
    856      * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
    857      *
    858      * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
    859      * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
    860      * the opcodes to access the data buffer (LDDW and STDW).
    861      */
    862     @GuardedBy("this") @Nullable
    863     private byte[] mDataSnapshot;
    864 
    865     // How many times the program was updated since we started.
    866     @GuardedBy("this")
    867     private int mNumProgramUpdates = 0;
    868     // How many times the program was updated since we started for allowing multicast traffic.
    869     @GuardedBy("this")
    870     private int mNumProgramUpdatesAllowingMulticast = 0;
    871 
    872     /**
    873      * Generate filter code to process ARP packets. Execution of this code ends in either the
    874      * DROP_LABEL or PASS_LABEL and does not fall off the end.
    875      * Preconditions:
    876      *  - Packet being filtered is ARP
    877      */
    878     @GuardedBy("this")
    879     private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
    880         // Here's a basic summary of what the ARP filter program does:
    881         //
    882         // if not ARP IPv4
    883         //   pass
    884         // if not ARP IPv4 reply or request
    885         //   pass
    886         // if unicast ARP reply
    887         //   pass
    888         // if interface has no IPv4 address
    889         //   if target ip is 0.0.0.0
    890         //      drop
    891         // else
    892         //   if target ip is not the interface ip
    893         //      drop
    894         // pass
    895 
    896         final String checkTargetIPv4 = "checkTargetIPv4";
    897 
    898         // Pass if not ARP IPv4.
    899         gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
    900         maybeSetCounter(gen, Counter.PASSED_ARP_NON_IPV4);
    901         gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
    902 
    903         // Pass if unknown ARP opcode.
    904         gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
    905         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
    906         maybeSetCounter(gen, Counter.PASSED_ARP_UNKNOWN);
    907         gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
    908 
    909         // Pass if unicast reply.
    910         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    911         maybeSetCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
    912         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
    913 
    914         // Either a unicast request, a unicast reply, or a broadcast reply.
    915         gen.defineLabel(checkTargetIPv4);
    916         if (mIPv4Address == null) {
    917             // When there is no IPv4 address, drop GARP replies (b/29404209).
    918             gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
    919             maybeSetCounter(gen, Counter.DROPPED_GARP_REPLY);
    920             gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
    921         } else {
    922             // When there is an IPv4 address, drop unicast/broadcast requests
    923             // and broadcast replies with a different target IPv4 address.
    924             gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
    925             maybeSetCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
    926             gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
    927         }
    928 
    929         maybeSetCounter(gen, Counter.PASSED_ARP);
    930         gen.addJump(mCountAndPassLabel);
    931     }
    932 
    933     /**
    934      * Generate filter code to process IPv4 packets. Execution of this code ends in either the
    935      * DROP_LABEL or PASS_LABEL and does not fall off the end.
    936      * Preconditions:
    937      *  - Packet being filtered is IPv4
    938      */
    939     @GuardedBy("this")
    940     private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
    941         // Here's a basic summary of what the IPv4 filter program does:
    942         //
    943         // if filtering multicast (i.e. multicast lock not held):
    944         //   if it's DHCP destined to our MAC:
    945         //     pass
    946         //   if it's L2 broadcast:
    947         //     drop
    948         //   if it's IPv4 multicast:
    949         //     drop
    950         //   if it's IPv4 broadcast:
    951         //     drop
    952         // pass
    953 
    954         if (mMulticastFilter) {
    955             final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
    956 
    957             // Pass DHCP addressed to us.
    958             // Check it's UDP.
    959             gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
    960             gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
    961             // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
    962             gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
    963             gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
    964             // Check it's addressed to DHCP client port.
    965             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
    966             gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
    967             gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
    968             // Check it's DHCP to our MAC address.
    969             gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
    970             // NOTE: Relies on R1 containing IPv4 header offset.
    971             gen.addAddR1();
    972             gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
    973             maybeSetCounter(gen, Counter.PASSED_DHCP);
    974             gen.addJump(mCountAndPassLabel);
    975 
    976             // Drop all multicasts/broadcasts.
    977             gen.defineLabel(skipDhcpv4Filter);
    978 
    979             // If IPv4 destination address is in multicast range, drop.
    980             gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
    981             gen.addAnd(0xf0);
    982             maybeSetCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
    983             gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
    984 
    985             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
    986             maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
    987             gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
    988             gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
    989             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
    990                 maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
    991                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
    992                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
    993             }
    994 
    995             // If L2 broadcast packet, drop.
    996             // TODO: can we invert this condition to fall through to the common pass case below?
    997             maybeSetCounter(gen, Counter.PASSED_IPV4_UNICAST);
    998             gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
    999             gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
   1000             maybeSetCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
   1001             gen.addJump(mCountAndDropLabel);
   1002         }
   1003 
   1004         // Otherwise, pass
   1005         maybeSetCounter(gen, Counter.PASSED_IPV4);
   1006         gen.addJump(mCountAndPassLabel);
   1007     }
   1008 
   1009 
   1010     /**
   1011      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
   1012      * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
   1013      * Preconditions:
   1014      *  - Packet being filtered is IPv6
   1015      */
   1016     @GuardedBy("this")
   1017     private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
   1018         // Here's a basic summary of what the IPv6 filter program does:
   1019         //
   1020         // if we're dropping multicast
   1021         //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
   1022         //     if it's multicast:
   1023         //       drop
   1024         //     pass
   1025         // if it's ICMPv6 RS to any:
   1026         //   drop
   1027         // if it's ICMPv6 NA to ff02::1:
   1028         //   drop
   1029 
   1030         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
   1031 
   1032         // Drop multicast if the multicast filter is enabled.
   1033         if (mMulticastFilter) {
   1034             final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
   1035             final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
   1036 
   1037             // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
   1038             // While awake, let all ICMPv6 multicasts through.
   1039             if (mInDozeMode) {
   1040                 // Not ICMPv6? -> Proceed to multicast filtering
   1041                 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
   1042 
   1043                 // ICMPv6 but not ECHO? -> Skip the multicast filter.
   1044                 // (ICMPv6 ECHO requests will go through the multicast filter below).
   1045                 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
   1046                 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
   1047             } else {
   1048                 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
   1049             }
   1050 
   1051             // Drop all other packets sent to ff00::/8 (multicast prefix).
   1052             gen.defineLabel(dropAllIPv6MulticastsLabel);
   1053             maybeSetCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
   1054             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
   1055             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
   1056             // Not multicast. Pass.
   1057             maybeSetCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
   1058             gen.addJump(mCountAndPassLabel);
   1059             gen.defineLabel(skipIPv6MulticastFilterLabel);
   1060         } else {
   1061             // If not ICMPv6, pass.
   1062             maybeSetCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
   1063             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
   1064         }
   1065 
   1066         // If we got this far, the packet is ICMPv6.  Drop some specific types.
   1067 
   1068         // Add unsolicited multicast neighbor announcements filter
   1069         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
   1070         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
   1071         // Drop all router solicitations (b/32833400)
   1072         maybeSetCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
   1073         gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
   1074         // If not neighbor announcements, skip filter.
   1075         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
   1076         // If to ff02::1, drop.
   1077         // TODO: Drop only if they don't contain the address of on-link neighbours.
   1078         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
   1079         gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
   1080                 skipUnsolicitedMulticastNALabel);
   1081         maybeSetCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
   1082         gen.addJump(mCountAndDropLabel);
   1083         gen.defineLabel(skipUnsolicitedMulticastNALabel);
   1084     }
   1085 
   1086     /**
   1087      * Begin generating an APF program to:
   1088      * <ul>
   1089      * <li>Drop/Pass 802.3 frames (based on policy)
   1090      * <li>Drop packets with EtherType within the Black List
   1091      * <li>Drop ARP requests not for us, if mIPv4Address is set,
   1092      * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
   1093      * <li>Drop IPv4 multicast packets, if mMulticastFilter,
   1094      * <li>Pass all other IPv4 packets,
   1095      * <li>Drop all broadcast non-IP non-ARP packets.
   1096      * <li>Pass all non-ICMPv6 IPv6 packets,
   1097      * <li>Pass all non-IPv4 and non-IPv6 packets,
   1098      * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
   1099      * <li>Drop IPv6 ICMPv6 RSs.
   1100      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
   1101      *     insertion of RA filters here, or if there aren't any, just passes the packets.
   1102      * </ul>
   1103      */
   1104     @GuardedBy("this")
   1105     private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
   1106         // This is guaranteed to succeed because of the check in maybeCreate.
   1107         ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
   1108 
   1109         if (mApfCapabilities.hasDataAccess()) {
   1110             // Increment TOTAL_PACKETS
   1111             maybeSetCounter(gen, Counter.TOTAL_PACKETS);
   1112             gen.addLoadData(Register.R0, 0);  // load counter
   1113             gen.addAdd(1);
   1114             gen.addStoreData(Register.R0, 0);  // write-back counter
   1115         }
   1116 
   1117         // Here's a basic summary of what the initial program does:
   1118         //
   1119         // if it's a 802.3 Frame (ethtype < 0x0600):
   1120         //    drop or pass based on configurations
   1121         // if it has a ether-type that belongs to the black list
   1122         //    drop
   1123         // if it's ARP:
   1124         //   insert ARP filter to drop or pass these appropriately
   1125         // if it's IPv4:
   1126         //   insert IPv4 filter to drop or pass these appropriately
   1127         // if it's not IPv6:
   1128         //   if it's broadcast:
   1129         //     drop
   1130         //   pass
   1131         // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
   1132 
   1133         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
   1134 
   1135         if (mDrop802_3Frames) {
   1136             // drop 802.3 frames (ethtype < 0x0600)
   1137             maybeSetCounter(gen, Counter.DROPPED_802_3_FRAME);
   1138             gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
   1139         }
   1140 
   1141         // Handle ether-type black list
   1142         maybeSetCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
   1143         for (int p : mEthTypeBlackList) {
   1144             gen.addJumpIfR0Equals(p, mCountAndDropLabel);
   1145         }
   1146 
   1147         // Add ARP filters:
   1148         String skipArpFiltersLabel = "skipArpFilters";
   1149         gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
   1150         generateArpFilterLocked(gen);
   1151         gen.defineLabel(skipArpFiltersLabel);
   1152 
   1153         // Add IPv4 filters:
   1154         String skipIPv4FiltersLabel = "skipIPv4Filters";
   1155         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
   1156         // execute the ARP filter, since that filter does not fall through, but either drops or
   1157         // passes.
   1158         gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
   1159         generateIPv4FilterLocked(gen);
   1160         gen.defineLabel(skipIPv4FiltersLabel);
   1161 
   1162         // Check for IPv6:
   1163         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
   1164         // execute the ARP or IPv4 filters, since those filters do not fall through, but either
   1165         // drop or pass.
   1166         String ipv6FilterLabel = "IPv6Filters";
   1167         gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
   1168 
   1169         // Drop non-IP non-ARP broadcasts, pass the rest
   1170         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
   1171         maybeSetCounter(gen, Counter.PASSED_NON_IP_UNICAST);
   1172         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
   1173         maybeSetCounter(gen, Counter.DROPPED_ETH_BROADCAST);
   1174         gen.addJump(mCountAndDropLabel);
   1175 
   1176         // Add IPv6 filters:
   1177         gen.defineLabel(ipv6FilterLabel);
   1178         generateIPv6FilterLocked(gen);
   1179         return gen;
   1180     }
   1181 
   1182     /**
   1183      * Append packet counting epilogue to the APF program.
   1184      *
   1185      * Currently, the epilogue consists of two trampolines which count passed and dropped packets
   1186      * before jumping to the actual PASS and DROP labels.
   1187      */
   1188     @GuardedBy("this")
   1189     private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
   1190         // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
   1191         // will just fall-through to the PASS label.
   1192         if (!mApfCapabilities.hasDataAccess()) return;
   1193 
   1194         // Execution will reach the bottom of the program if none of the filters match,
   1195         // which will pass the packet to the application processor.
   1196         maybeSetCounter(gen, Counter.PASSED_IPV6_ICMP);
   1197 
   1198         // Append the count & pass trampoline, which increments the counter at the data address
   1199         // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
   1200         // the entire sequence inline for every counter.
   1201         gen.defineLabel(mCountAndPassLabel);
   1202         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
   1203         gen.addAdd(1);                     // R0++
   1204         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
   1205         gen.addJump(gen.PASS_LABEL);
   1206 
   1207         // Same as above for the count & drop trampoline.
   1208         gen.defineLabel(mCountAndDropLabel);
   1209         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
   1210         gen.addAdd(1);                     // R0++
   1211         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
   1212         gen.addJump(gen.DROP_LABEL);
   1213     }
   1214 
   1215     /**
   1216      * Generate and install a new filter program.
   1217      */
   1218     @GuardedBy("this")
   1219     @VisibleForTesting
   1220     void installNewProgramLocked() {
   1221         purgeExpiredRasLocked();
   1222         ArrayList<Ra> rasToFilter = new ArrayList<>();
   1223         final byte[] program;
   1224         long programMinLifetime = Long.MAX_VALUE;
   1225         long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
   1226         if (mApfCapabilities.hasDataAccess()) {
   1227             // Reserve space for the counters.
   1228             maximumApfProgramSize -= Counter.totalSize();
   1229         }
   1230 
   1231         try {
   1232             // Step 1: Determine how many RA filters we can fit in the program.
   1233             ApfGenerator gen = emitPrologueLocked();
   1234 
   1235             // The epilogue normally goes after the RA filters, but add it early to include its
   1236             // length when estimating the total.
   1237             emitEpilogue(gen);
   1238 
   1239             // Can't fit the program even without any RA filters?
   1240             if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
   1241                 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
   1242                 return;
   1243             }
   1244 
   1245             for (Ra ra : mRas) {
   1246                 ra.generateFilterLocked(gen);
   1247                 // Stop if we get too big.
   1248                 if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
   1249                 rasToFilter.add(ra);
   1250             }
   1251 
   1252             // Step 2: Actually generate the program
   1253             gen = emitPrologueLocked();
   1254             for (Ra ra : rasToFilter) {
   1255                 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
   1256             }
   1257             emitEpilogue(gen);
   1258             program = gen.generate();
   1259         } catch (IllegalInstructionException|IllegalStateException e) {
   1260             Log.e(TAG, "Failed to generate APF program.", e);
   1261             return;
   1262         }
   1263         final long now = currentTimeSeconds();
   1264         mLastTimeInstalledProgram = now;
   1265         mLastInstalledProgramMinLifetime = programMinLifetime;
   1266         mLastInstalledProgram = program;
   1267         mNumProgramUpdates++;
   1268 
   1269         if (VDBG) {
   1270             hexDump("Installing filter: ", program, program.length);
   1271         }
   1272         mIpClientCallback.installPacketFilter(program);
   1273         logApfProgramEventLocked(now);
   1274         mLastInstallEvent = new ApfProgramEvent();
   1275         mLastInstallEvent.lifetime = programMinLifetime;
   1276         mLastInstallEvent.filteredRas = rasToFilter.size();
   1277         mLastInstallEvent.currentRas = mRas.size();
   1278         mLastInstallEvent.programLength = program.length;
   1279         mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
   1280     }
   1281 
   1282     @GuardedBy("this")
   1283     private void logApfProgramEventLocked(long now) {
   1284         if (mLastInstallEvent == null) {
   1285             return;
   1286         }
   1287         ApfProgramEvent ev = mLastInstallEvent;
   1288         mLastInstallEvent = null;
   1289         ev.actualLifetime = now - mLastTimeInstalledProgram;
   1290         if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
   1291             return;
   1292         }
   1293         mMetricsLog.log(ev);
   1294     }
   1295 
   1296     /**
   1297      * Returns {@code true} if a new program should be installed because the current one dies soon.
   1298      */
   1299     private boolean shouldInstallnewProgram() {
   1300         long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
   1301         return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
   1302     }
   1303 
   1304     private void hexDump(String msg, byte[] packet, int length) {
   1305         log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
   1306     }
   1307 
   1308     @GuardedBy("this")
   1309     private void purgeExpiredRasLocked() {
   1310         for (int i = 0; i < mRas.size();) {
   1311             if (mRas.get(i).isExpired()) {
   1312                 log("Expiring " + mRas.get(i));
   1313                 mRas.remove(i);
   1314             } else {
   1315                 i++;
   1316             }
   1317         }
   1318     }
   1319 
   1320     /**
   1321      * Process an RA packet, updating the list of known RAs and installing a new APF program
   1322      * if the current APF program should be updated.
   1323      * @return a ProcessRaResult enum describing what action was performed.
   1324      */
   1325     @VisibleForTesting
   1326     synchronized ProcessRaResult processRa(byte[] packet, int length) {
   1327         if (VDBG) hexDump("Read packet = ", packet, length);
   1328 
   1329         // Have we seen this RA before?
   1330         for (int i = 0; i < mRas.size(); i++) {
   1331             Ra ra = mRas.get(i);
   1332             if (ra.matches(packet, length)) {
   1333                 if (VDBG) log("matched RA " + ra);
   1334                 // Update lifetimes.
   1335                 ra.mLastSeen = currentTimeSeconds();
   1336                 ra.mMinLifetime = ra.minLifetime(packet, length);
   1337                 ra.seenCount++;
   1338 
   1339                 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
   1340                 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
   1341                 // until the filter program exceeds the maximum filter program size allowed by the
   1342                 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
   1343                 // filter program.
   1344                 // TODO: consider sorting the RAs in order of increasing expiry time as well.
   1345                 // Swap to front of array.
   1346                 mRas.add(0, mRas.remove(i));
   1347 
   1348                 // If the current program doesn't expire for a while, don't update.
   1349                 if (shouldInstallnewProgram()) {
   1350                     installNewProgramLocked();
   1351                     return ProcessRaResult.UPDATE_EXPIRY;
   1352                 }
   1353                 return ProcessRaResult.MATCH;
   1354             }
   1355         }
   1356         purgeExpiredRasLocked();
   1357         // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
   1358         if (mRas.size() >= MAX_RAS) {
   1359             return ProcessRaResult.DROPPED;
   1360         }
   1361         final Ra ra;
   1362         try {
   1363             ra = new Ra(packet, length);
   1364         } catch (Exception e) {
   1365             Log.e(TAG, "Error parsing RA", e);
   1366             return ProcessRaResult.PARSE_ERROR;
   1367         }
   1368         // Ignore 0 lifetime RAs.
   1369         if (ra.isExpired()) {
   1370             return ProcessRaResult.ZERO_LIFETIME;
   1371         }
   1372         log("Adding " + ra);
   1373         mRas.add(ra);
   1374         installNewProgramLocked();
   1375         return ProcessRaResult.UPDATE_NEW_RA;
   1376     }
   1377 
   1378     /**
   1379      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
   1380      * filtering using APF programs.
   1381      */
   1382     public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
   1383             InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
   1384         if (context == null || config == null || ifParams == null) return null;
   1385         ApfCapabilities apfCapabilities =  config.apfCapabilities;
   1386         if (apfCapabilities == null) return null;
   1387         if (apfCapabilities.apfVersionSupported == 0) return null;
   1388         if (apfCapabilities.maximumApfProgramSize < 512) {
   1389             Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
   1390             return null;
   1391         }
   1392         // For now only support generating programs for Ethernet frames. If this restriction is
   1393         // lifted:
   1394         //   1. the program generator will need its offsets adjusted.
   1395         //   2. the packet filter attached to our packet socket will need its offset adjusted.
   1396         if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
   1397         if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
   1398             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
   1399             return null;
   1400         }
   1401 
   1402         return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
   1403     }
   1404 
   1405     public synchronized void shutdown() {
   1406         if (mReceiveThread != null) {
   1407             log("shutting down");
   1408             mReceiveThread.halt();  // Also closes socket.
   1409             mReceiveThread = null;
   1410         }
   1411         mRas.clear();
   1412         mContext.unregisterReceiver(mDeviceIdleReceiver);
   1413     }
   1414 
   1415     public synchronized void setMulticastFilter(boolean isEnabled) {
   1416         if (mMulticastFilter == isEnabled) return;
   1417         mMulticastFilter = isEnabled;
   1418         if (!isEnabled) {
   1419             mNumProgramUpdatesAllowingMulticast++;
   1420         }
   1421         installNewProgramLocked();
   1422     }
   1423 
   1424     @VisibleForTesting
   1425     public synchronized void setDozeMode(boolean isEnabled) {
   1426         if (mInDozeMode == isEnabled) return;
   1427         mInDozeMode = isEnabled;
   1428         installNewProgramLocked();
   1429     }
   1430 
   1431     /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
   1432     private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
   1433         LinkAddress ipv4Address = null;
   1434         for (LinkAddress address : lp.getLinkAddresses()) {
   1435             if (!(address.getAddress() instanceof Inet4Address)) {
   1436                 continue;
   1437             }
   1438             if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
   1439                 // More than one IPv4 address, abort.
   1440                 return null;
   1441             }
   1442             ipv4Address = address;
   1443         }
   1444         return ipv4Address;
   1445     }
   1446 
   1447     public synchronized void setLinkProperties(LinkProperties lp) {
   1448         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
   1449         final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
   1450         final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
   1451         final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
   1452         if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
   1453             return;
   1454         }
   1455         mIPv4Address = addr;
   1456         mIPv4PrefixLength = prefix;
   1457         installNewProgramLocked();
   1458     }
   1459 
   1460     static public long counterValue(byte[] data, Counter counter)
   1461             throws ArrayIndexOutOfBoundsException {
   1462         // Follow the same wrap-around addressing scheme of the interpreter.
   1463         int offset = counter.offset();
   1464         if (offset < 0) {
   1465             offset = data.length + offset;
   1466         }
   1467 
   1468         // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
   1469         long value = 0;
   1470         for (int i = 0; i < 4; i++) {
   1471             value = value << 8 | (data[offset] & 0xFF);
   1472             offset++;
   1473         }
   1474         return value;
   1475     }
   1476 
   1477     public synchronized void dump(IndentingPrintWriter pw) {
   1478         pw.println("Capabilities: " + mApfCapabilities);
   1479         pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
   1480         pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
   1481         try {
   1482             pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
   1483         } catch (UnknownHostException|NullPointerException e) {}
   1484 
   1485         if (mLastTimeInstalledProgram == 0) {
   1486             pw.println("No program installed.");
   1487             return;
   1488         }
   1489         pw.println("Program updates: " + mNumProgramUpdates);
   1490         pw.println(String.format(
   1491                 "Last program length %d, installed %ds ago, lifetime %ds",
   1492                 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
   1493                 mLastInstalledProgramMinLifetime));
   1494 
   1495         pw.println("RA filters:");
   1496         pw.increaseIndent();
   1497         for (Ra ra: mRas) {
   1498             pw.println(ra);
   1499             pw.increaseIndent();
   1500             pw.println(String.format(
   1501                     "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
   1502             if (DBG) {
   1503                 pw.println("Last match:");
   1504                 pw.increaseIndent();
   1505                 pw.println(ra.getLastMatchingPacket());
   1506                 pw.decreaseIndent();
   1507             }
   1508             pw.decreaseIndent();
   1509         }
   1510         pw.decreaseIndent();
   1511 
   1512         if (DBG) {
   1513             pw.println("Last program:");
   1514             pw.increaseIndent();
   1515             pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
   1516             pw.decreaseIndent();
   1517         }
   1518 
   1519         pw.println("APF packet counters: ");
   1520         pw.increaseIndent();
   1521         if (!mApfCapabilities.hasDataAccess()) {
   1522             pw.println("APF counters not supported");
   1523         } else if (mDataSnapshot == null) {
   1524             pw.println("No last snapshot.");
   1525         } else {
   1526             try {
   1527                 Counter[] counters = Counter.class.getEnumConstants();
   1528                 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
   1529                     long value = counterValue(mDataSnapshot, c);
   1530                     // Only print non-zero counters
   1531                     if (value != 0) {
   1532                         pw.println(c.toString() + ": " + value);
   1533                     }
   1534                 }
   1535             } catch (ArrayIndexOutOfBoundsException e) {
   1536                 pw.println("Uh-oh: " + e);
   1537             }
   1538             if (VDBG) {
   1539                 pw.println("Raw data dump: ");
   1540                 pw.println(HexDump.dumpHexString(mDataSnapshot));
   1541             }
   1542         }
   1543         pw.decreaseIndent();
   1544     }
   1545 
   1546     // TODO: move to android.net.NetworkUtils
   1547     @VisibleForTesting
   1548     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
   1549         return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
   1550     }
   1551 }
   1552