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.SocketUtils.makePacketSocketAddress;
20 import static android.system.OsConstants.AF_PACKET;
21 import static android.system.OsConstants.ARPHRD_ETHER;
22 import static android.system.OsConstants.ETH_P_ARP;
23 import static android.system.OsConstants.ETH_P_IP;
24 import static android.system.OsConstants.ETH_P_IPV6;
25 import static android.system.OsConstants.IPPROTO_ICMPV6;
26 import static android.system.OsConstants.IPPROTO_TCP;
27 import static android.system.OsConstants.IPPROTO_UDP;
28 import static android.system.OsConstants.SOCK_RAW;
29 
30 import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
31 import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
32 import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
33 import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
34 import static com.android.server.util.NetworkStackConstants.IPV6_ADDR_LEN;
35 
36 import android.content.BroadcastReceiver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.net.LinkAddress;
41 import android.net.LinkProperties;
42 import android.net.NattKeepalivePacketDataParcelable;
43 import android.net.TcpKeepalivePacketDataParcelable;
44 import android.net.apf.ApfGenerator.IllegalInstructionException;
45 import android.net.apf.ApfGenerator.Register;
46 import android.net.ip.IpClient.IpClientCallbacksWrapper;
47 import android.net.metrics.ApfProgramEvent;
48 import android.net.metrics.ApfStats;
49 import android.net.metrics.IpConnectivityLog;
50 import android.net.metrics.RaEvent;
51 import android.net.util.InterfaceParams;
52 import android.net.util.NetworkStackUtils;
53 import android.os.PowerManager;
54 import android.os.SystemClock;
55 import android.system.ErrnoException;
56 import android.system.Os;
57 import android.text.format.DateUtils;
58 import android.util.Log;
59 import android.util.SparseArray;
60 
61 import androidx.annotation.Nullable;
62 
63 import com.android.internal.annotations.GuardedBy;
64 import com.android.internal.annotations.VisibleForTesting;
65 import com.android.internal.util.HexDump;
66 import com.android.internal.util.IndentingPrintWriter;
67 
68 import java.io.FileDescriptor;
69 import java.io.IOException;
70 import java.net.Inet4Address;
71 import java.net.Inet6Address;
72 import java.net.InetAddress;
73 import java.net.SocketAddress;
74 import java.net.SocketException;
75 import java.net.UnknownHostException;
76 import java.nio.BufferUnderflowException;
77 import java.nio.ByteBuffer;
78 import java.nio.ByteOrder;
79 import java.util.ArrayList;
80 import java.util.Arrays;
81 
82 /**
83  * For networks that support packet filtering via APF programs, {@code ApfFilter}
84  * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
85  * filter out redundant duplicate ones.
86  *
87  * Threading model:
88  * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
89  * know what RAs to filter for, thus generating APF programs is dependent on mRas.
90  * mRas can be accessed by multiple threads:
91  * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
92  * - callers of:
93  *    - setMulticastFilter(), which can cause an APF program to be generated.
94  *    - dump(), which dumps mRas among other things.
95  *    - shutdown(), which clears mRas.
96  * So access to mRas is synchronized.
97  *
98  * @hide
99  */
100 public class ApfFilter {
101 
102     // Helper class for specifying functional filter parameters.
103     public static class ApfConfiguration {
104         public ApfCapabilities apfCapabilities;
105         public boolean multicastFilter;
106         public boolean ieee802_3Filter;
107         public int[] ethTypeBlackList;
108         public int minRdnssLifetimeSec;
109     }
110 
111     // Enums describing the outcome of receiving an RA packet.
112     private static enum ProcessRaResult {
113         MATCH,          // Received RA matched a known RA
114         DROPPED,        // Received RA ignored due to MAX_RAS
115         PARSE_ERROR,    // Received RA could not be parsed
116         ZERO_LIFETIME,  // Received RA had 0 lifetime
117         UPDATE_NEW_RA,  // APF program updated for new RA
118         UPDATE_EXPIRY   // APF program updated for expiry
119     }
120 
121     /**
122      * APF packet counters.
123      *
124      * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
125      * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
126      * the last writable 32bit word.
127      */
128     @VisibleForTesting
129     public static enum Counter {
130         RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
131         TOTAL_PACKETS,
132         PASSED_ARP,
133         PASSED_DHCP,
134         PASSED_IPV4,
135         PASSED_IPV6_NON_ICMP,
136         PASSED_IPV4_UNICAST,
137         PASSED_IPV6_ICMP,
138         PASSED_IPV6_UNICAST_NON_ICMP,
139         PASSED_ARP_NON_IPV4,
140         PASSED_ARP_UNKNOWN,
141         PASSED_ARP_UNICAST_REPLY,
142         PASSED_NON_IP_UNICAST,
143         DROPPED_ETH_BROADCAST,
144         DROPPED_RA,
145         DROPPED_GARP_REPLY,
146         DROPPED_ARP_OTHER_HOST,
147         DROPPED_IPV4_L2_BROADCAST,
148         DROPPED_IPV4_BROADCAST_ADDR,
149         DROPPED_IPV4_BROADCAST_NET,
150         DROPPED_IPV4_MULTICAST,
151         DROPPED_IPV6_ROUTER_SOLICITATION,
152         DROPPED_IPV6_MULTICAST_NA,
153         DROPPED_IPV6_MULTICAST,
154         DROPPED_IPV6_MULTICAST_PING,
155         DROPPED_IPV6_NON_ICMP_MULTICAST,
156         DROPPED_802_3_FRAME,
157         DROPPED_ETHERTYPE_BLACKLISTED,
158         DROPPED_ARP_REPLY_SPA_NO_HOST,
159         DROPPED_IPV4_KEEPALIVE_ACK,
160         DROPPED_IPV6_KEEPALIVE_ACK,
161         DROPPED_IPV4_NATT_KEEPALIVE;
162 
163         // Returns the negative byte offset from the end of the APF data segment for
164         // a given counter.
offset()165         public int offset() {
166             return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
167         }
168 
169         // Returns the total size of the data segment in bytes.
totalSize()170         public static int totalSize() {
171             return (Counter.class.getEnumConstants().length - 1) * 4;
172         }
173     }
174 
175     /**
176      * When APFv4 is supported, loads R1 with the offset of the specified counter.
177      */
maybeSetupCounter(ApfGenerator gen, Counter c)178     private void maybeSetupCounter(ApfGenerator gen, Counter c) {
179         if (mApfCapabilities.hasDataAccess()) {
180             gen.addLoadImmediate(Register.R1, c.offset());
181         }
182     }
183 
184     // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
185     // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
186     private final String mCountAndPassLabel;
187     private final String mCountAndDropLabel;
188 
189     // Thread to listen for RAs.
190     @VisibleForTesting
191     class ReceiveThread extends Thread {
192         private final byte[] mPacket = new byte[1514];
193         private final FileDescriptor mSocket;
194         private final long mStart = SystemClock.elapsedRealtime();
195 
196         private int mReceivedRas = 0;
197         private int mMatchingRas = 0;
198         private int mDroppedRas = 0;
199         private int mParseErrors = 0;
200         private int mZeroLifetimeRas = 0;
201         private int mProgramUpdates = 0;
202 
203         private volatile boolean mStopped;
204 
ReceiveThread(FileDescriptor socket)205         public ReceiveThread(FileDescriptor socket) {
206             mSocket = socket;
207         }
208 
halt()209         public void halt() {
210             mStopped = true;
211             // Interrupts the read() call the thread is blocked in.
212             NetworkStackUtils.closeSocketQuietly(mSocket);
213         }
214 
215         @Override
run()216         public void run() {
217             log("begin monitoring");
218             while (!mStopped) {
219                 try {
220                     int length = Os.read(mSocket, mPacket, 0, mPacket.length);
221                     updateStats(processRa(mPacket, length));
222                 } catch (IOException|ErrnoException e) {
223                     if (!mStopped) {
224                         Log.e(TAG, "Read error", e);
225                     }
226                 }
227             }
228             logStats();
229         }
230 
updateStats(ProcessRaResult result)231         private void updateStats(ProcessRaResult result) {
232             mReceivedRas++;
233             switch(result) {
234                 case MATCH:
235                     mMatchingRas++;
236                     return;
237                 case DROPPED:
238                     mDroppedRas++;
239                     return;
240                 case PARSE_ERROR:
241                     mParseErrors++;
242                     return;
243                 case ZERO_LIFETIME:
244                     mZeroLifetimeRas++;
245                     return;
246                 case UPDATE_EXPIRY:
247                     mMatchingRas++;
248                     mProgramUpdates++;
249                     return;
250                 case UPDATE_NEW_RA:
251                     mProgramUpdates++;
252                     return;
253             }
254         }
255 
logStats()256         private void logStats() {
257             final long nowMs = SystemClock.elapsedRealtime();
258             synchronized (this) {
259                 final ApfStats stats = new ApfStats.Builder()
260                         .setReceivedRas(mReceivedRas)
261                         .setMatchingRas(mMatchingRas)
262                         .setDroppedRas(mDroppedRas)
263                         .setParseErrors(mParseErrors)
264                         .setZeroLifetimeRas(mZeroLifetimeRas)
265                         .setProgramUpdates(mProgramUpdates)
266                         .setDurationMs(nowMs - mStart)
267                         .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize)
268                         .setProgramUpdatesAll(mNumProgramUpdates)
269                         .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast)
270                         .build();
271                 mMetricsLog.log(stats);
272                 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
273             }
274         }
275     }
276 
277     private static final String TAG = "ApfFilter";
278     private static final boolean DBG = true;
279     private static final boolean VDBG = false;
280 
281     private static final int ETH_HEADER_LEN = 14;
282     private static final int ETH_DEST_ADDR_OFFSET = 0;
283     private static final int ETH_ETHERTYPE_OFFSET = 12;
284     private static final int ETH_TYPE_MIN = 0x0600;
285     private static final int ETH_TYPE_MAX = 0xFFFF;
286     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
287             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
288     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
289     private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
290     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
291     // Endianness is not an issue for this constant because the APF interpreter always operates in
292     // network byte order.
293     private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
294     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
295     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
296     private static final int IPV4_ANY_HOST_ADDRESS = 0;
297     private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
298     private static final int IPV4_HEADER_LEN = 20; // Without options
299 
300     // Traffic class and Flow label are not byte aligned. Luckily we
301     // don't care about either value so we'll consider bytes 1-3 of the
302     // IPv6 header as don't care.
303     private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
304     private static final int IPV6_FLOW_LABEL_LEN = 3;
305     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
306     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
307     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
308     private static final int IPV6_HEADER_LEN = 40;
309     // The IPv6 all nodes address ff02::1
310     private static final byte[] IPV6_ALL_NODES_ADDRESS =
311             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
312 
313     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
314 
315     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
316     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
317     private static final int UDP_HEADER_LEN = 8;
318 
319     private static final int TCP_HEADER_SIZE_OFFSET = 12;
320 
321     private static final int DHCP_CLIENT_PORT = 68;
322     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
323     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
324 
325     private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
326     private static final byte[] ARP_IPV4_HEADER = {
327             0, 1, // Hardware type: Ethernet (1)
328             8, 0, // Protocol type: IP (0x0800)
329             6,    // Hardware size: 6
330             4,    // Protocol size: 4
331     };
332     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
333     // Opcode: ARP request (0x0001), ARP reply (0x0002)
334     private static final short ARP_OPCODE_REQUEST = 1;
335     private static final short ARP_OPCODE_REPLY = 2;
336     private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
337     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
338     // Do not log ApfProgramEvents whose actual lifetimes was less than this.
339     private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
340     // Limit on the Black List size to cap on program usage for this
341     // TODO: Select a proper max length
342     private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
343 
344     private final ApfCapabilities mApfCapabilities;
345     private final IpClientCallbacksWrapper mIpClientCallback;
346     private final InterfaceParams mInterfaceParams;
347     private final IpConnectivityLog mMetricsLog;
348 
349     @VisibleForTesting
350     byte[] mHardwareAddress;
351     @VisibleForTesting
352     ReceiveThread mReceiveThread;
353     @GuardedBy("this")
354     private long mUniqueCounter;
355     @GuardedBy("this")
356     private boolean mMulticastFilter;
357     @GuardedBy("this")
358     private boolean mInDozeMode;
359     private final boolean mDrop802_3Frames;
360     private final int[] mEthTypeBlackList;
361 
362     // Ignore non-zero RDNSS lifetimes below this value.
363     private final int mMinRdnssLifetimeSec;
364 
365     // Detects doze mode state transitions.
366     private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
367         @Override
368         public void onReceive(Context context, Intent intent) {
369             String action = intent.getAction();
370             if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
371                 PowerManager powerManager =
372                         (PowerManager) context.getSystemService(Context.POWER_SERVICE);
373                 final boolean deviceIdle = powerManager.isDeviceIdleMode();
374                 setDozeMode(deviceIdle);
375             }
376         }
377     };
378     private final Context mContext;
379 
380     // Our IPv4 address, if we have just one, otherwise null.
381     @GuardedBy("this")
382     private byte[] mIPv4Address;
383     // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
384     @GuardedBy("this")
385     private int mIPv4PrefixLength;
386 
387     @VisibleForTesting
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log)388     ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
389             IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) {
390         mApfCapabilities = config.apfCapabilities;
391         mIpClientCallback = ipClientCallback;
392         mInterfaceParams = ifParams;
393         mMulticastFilter = config.multicastFilter;
394         mDrop802_3Frames = config.ieee802_3Filter;
395         mMinRdnssLifetimeSec = config.minRdnssLifetimeSec;
396         mContext = context;
397 
398         if (mApfCapabilities.hasDataAccess()) {
399             mCountAndPassLabel = "countAndPass";
400             mCountAndDropLabel = "countAndDrop";
401         } else {
402             // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
403             // preserving the original pre-APFv4 behavior.
404             mCountAndPassLabel = ApfGenerator.PASS_LABEL;
405             mCountAndDropLabel = ApfGenerator.DROP_LABEL;
406         }
407 
408         // Now fill the black list from the passed array
409         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
410 
411         mMetricsLog = log;
412 
413         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
414         maybeStartFilter();
415 
416         // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
417         mContext.registerReceiver(mDeviceIdleReceiver,
418                 new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
419     }
420 
setDataSnapshot(byte[] data)421     public synchronized void setDataSnapshot(byte[] data) {
422         mDataSnapshot = data;
423     }
424 
log(String s)425     private void log(String s) {
426         Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
427     }
428 
429     @GuardedBy("this")
getUniqueNumberLocked()430     private long getUniqueNumberLocked() {
431         return mUniqueCounter++;
432     }
433 
434     @GuardedBy("this")
filterEthTypeBlackList(int[] ethTypeBlackList)435     private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
436         ArrayList<Integer> bl = new ArrayList<Integer>();
437 
438         for (int p : ethTypeBlackList) {
439             // Check if the protocol is a valid ether type
440             if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
441                 continue;
442             }
443 
444             // Check if the protocol is not repeated in the passed array
445             if (bl.contains(p)) {
446                 continue;
447             }
448 
449             // Check if list reach its max size
450             if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
451                 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
452                         ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
453                 break;
454             }
455 
456             // Now add the protocol to the list
457             bl.add(p);
458         }
459 
460         return bl.stream().mapToInt(Integer::intValue).toArray();
461     }
462 
463     /**
464      * Attempt to start listening for RAs and, if RAs are received, generating and installing
465      * filters to ignore useless RAs.
466      */
467     @VisibleForTesting
maybeStartFilter()468     void maybeStartFilter() {
469         FileDescriptor socket;
470         try {
471             mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
472             synchronized(this) {
473                 // Clear the APF memory to reset all counters upon connecting to the first AP
474                 // in an SSID. This is limited to APFv4 devices because this large write triggers
475                 // a crash on some older devices (b/78905546).
476                 if (mApfCapabilities.hasDataAccess()) {
477                     byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
478                     mIpClientCallback.installPacketFilter(zeroes);
479                 }
480 
481                 // Install basic filters
482                 installNewProgramLocked();
483             }
484             socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
485             SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, mInterfaceParams.index);
486             Os.bind(socket, addr);
487             NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
488         } catch(SocketException|ErrnoException e) {
489             Log.e(TAG, "Error starting filter", e);
490             return;
491         }
492         mReceiveThread = new ReceiveThread(socket);
493         mReceiveThread.start();
494     }
495 
496     // Returns seconds since device boot.
497     @VisibleForTesting
currentTimeSeconds()498     protected long currentTimeSeconds() {
499         return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
500     }
501 
502     public static class InvalidRaException extends Exception {
InvalidRaException(String m)503         public InvalidRaException(String m) {
504             super(m);
505         }
506     }
507 
508     /**
509      *  Class to keep track of a section in a packet.
510      */
511     private static class PacketSection {
512         public enum Type {
513             MATCH,     // A field that should be matched (e.g., the router IP address).
514             IGNORE,    // An ignored field such as the checksum of the flow label. Not matched.
515             LIFETIME,  // A lifetime. Not matched, and generally counts toward minimum RA lifetime.
516         }
517 
518         /** The type of section. */
519         public final Type type;
520         /** Offset into the packet at which this section begins. */
521         public final int start;
522         /** Length of this section in bytes. */
523         public final int length;
524         /** If this is a lifetime, the ICMP option that defined it. 0 for router lifetime. */
525         public final int option;
526         /** If this is a lifetime, the lifetime value. */
527         public final long lifetime;
528 
PacketSection(int start, int length, Type type, int option, long lifetime)529         PacketSection(int start, int length, Type type, int option, long lifetime) {
530             this.start = start;
531             this.length = length;
532             this.type = type;
533             this.option = option;
534             this.lifetime = lifetime;
535         }
536 
toString()537         public String toString() {
538             if (type == Type.LIFETIME) {
539                 return String.format("%s: (%d, %d) %d %d", type, start, length, option, lifetime);
540             } else {
541                 return String.format("%s: (%d, %d)", type, start, length);
542             }
543         }
544     }
545 
546     // A class to hold information about an RA.
547     @VisibleForTesting
548     class Ra {
549         // From RFC4861:
550         private static final int ICMP6_RA_HEADER_LEN = 16;
551         private static final int ICMP6_RA_CHECKSUM_OFFSET =
552                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
553         private static final int ICMP6_RA_CHECKSUM_LEN = 2;
554         private static final int ICMP6_RA_OPTION_OFFSET =
555                 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
556         private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
557                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
558         private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
559         // Prefix information option.
560         private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
561         private static final int ICMP6_PREFIX_OPTION_LEN = 32;
562         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
563         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
564         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
565         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
566 
567         // From RFC6106: Recursive DNS Server option
568         private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
569         // From RFC6106: DNS Search List option
570         private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
571 
572         // From RFC4191: Route Information option
573         private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
574         // Above three options all have the same format:
575         private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
576         private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
577 
578         // Note: mPacket's position() cannot be assumed to be reset.
579         private final ByteBuffer mPacket;
580 
581         // List of sections in the packet.
582         private final ArrayList<PacketSection> mPacketSections = new ArrayList<>();
583 
584         // Minimum lifetime in packet
585         long mMinLifetime;
586         // When the packet was last captured, in seconds since Unix Epoch
587         long mLastSeen;
588 
589         // For debugging only. Offsets into the packet where PIOs are.
590         private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
591 
592         // For debugging only. Offsets into the packet where RDNSS options are.
593         private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
594 
595         // For debugging only. Offsets into the packet where RIO options are.
596         private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>();
597 
598         // For debugging only. How many times this RA was seen.
599         int seenCount = 0;
600 
601         // For debugging only. Returns the hex representation of the last matching packet.
getLastMatchingPacket()602         String getLastMatchingPacket() {
603             return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
604                     false /* lowercase */);
605         }
606 
607         // For debugging only. Returns the string representation of the IPv6 address starting at
608         // position pos in the packet.
IPv6AddresstoString(int pos)609         private String IPv6AddresstoString(int pos) {
610             try {
611                 byte[] array = mPacket.array();
612                 // Can't just call copyOfRange() and see if it throws, because if it reads past the
613                 // end it pads with zeros instead of throwing.
614                 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
615                     return "???";
616                 }
617                 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
618                 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
619                 return address.getHostAddress();
620             } catch (UnsupportedOperationException e) {
621                 // array() failed. Cannot happen, mPacket is array-backed and read-write.
622                 return "???";
623             } catch (ClassCastException|UnknownHostException e) {
624                 // Cannot happen.
625                 return "???";
626             }
627         }
628 
629         // Can't be static because it's in a non-static inner class.
630         // TODO: Make this static once RA is its own class.
prefixOptionToString(StringBuffer sb, int offset)631         private void prefixOptionToString(StringBuffer sb, int offset) {
632             String prefix = IPv6AddresstoString(offset + 16);
633             int length = getUint8(mPacket, offset + 2);
634             long valid = getUint32(mPacket, offset + 4);
635             long preferred = getUint32(mPacket, offset + 8);
636             sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
637         }
638 
rdnssOptionToString(StringBuffer sb, int offset)639         private void rdnssOptionToString(StringBuffer sb, int offset) {
640             int optLen = getUint8(mPacket, offset + 1) * 8;
641             if (optLen < 24) return;  // Malformed or empty.
642             long lifetime = getUint32(mPacket, offset + 4);
643             int numServers = (optLen - 8) / 16;
644             sb.append("DNS ").append(lifetime).append("s");
645             for (int server = 0; server < numServers; server++) {
646                 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
647             }
648             sb.append(" ");
649         }
650 
rioOptionToString(StringBuffer sb, int offset)651         private void rioOptionToString(StringBuffer sb, int offset) {
652             int optLen = getUint8(mPacket, offset + 1) * 8;
653             if (optLen < 8 || optLen > 24) return;  // Malformed or empty.
654             int prefixLen = getUint8(mPacket, offset + 2);
655             long lifetime = getUint32(mPacket, offset + 4);
656 
657             // This read is variable length because the prefix can be 0, 8 or 16 bytes long.
658             // We can't use any of the ByteBuffer#get methods here because they all start reading
659             // from the buffer's current position.
660             byte[] prefix = new byte[IPV6_ADDR_LEN];
661             System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8);
662             sb.append("RIO ").append(lifetime).append("s ");
663             try {
664                 InetAddress address = (Inet6Address) InetAddress.getByAddress(prefix);
665                 sb.append(address.getHostAddress());
666             } catch (UnknownHostException impossible) {
667                 sb.append("???");
668             }
669             sb.append("/").append(prefixLen).append(" ");
670         }
671 
toString()672         public String toString() {
673             try {
674                 StringBuffer sb = new StringBuffer();
675                 sb.append(String.format("RA %s -> %s %ds ",
676                         IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
677                         IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
678                         getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
679                 for (int i: mPrefixOptionOffsets) {
680                     prefixOptionToString(sb, i);
681                 }
682                 for (int i: mRdnssOptionOffsets) {
683                     rdnssOptionToString(sb, i);
684                 }
685                 for (int i: mRioOptionOffsets) {
686                     rioOptionToString(sb, i);
687                 }
688                 return sb.toString();
689             } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
690                 return "<Malformed RA>";
691             }
692         }
693 
694         /**
695          * Add a packet section that should be matched, starting from the current position.
696          * @param length the length of the section
697          */
addMatchSection(int length)698         private void addMatchSection(int length) {
699             // Don't generate JNEBS instruction for 0 bytes as they will fail the
700             // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is
701             // the number of bytes to compare) and immediately pass the packet.
702             // The code does not attempt to generate such matches, but add a safety
703             // check to prevent doing so in the presence of bugs or malformed or
704             // truncated packets.
705             if (length == 0) return;
706             mPacketSections.add(
707                     new PacketSection(mPacket.position(), length, PacketSection.Type.MATCH, 0, 0));
708             mPacket.position(mPacket.position() + length);
709         }
710 
711         /**
712          * Add a packet section that should be matched, starting from the current position.
713          * @param end the offset in the packet before which the section ends
714          */
addMatchUntil(int end)715         private void addMatchUntil(int end) {
716             addMatchSection(end - mPacket.position());
717         }
718 
719         /**
720          * Add a packet section that should be ignored, starting from the current position.
721          * @param length the length of the section in bytes
722          */
addIgnoreSection(int length)723         private void addIgnoreSection(int length) {
724             mPacketSections.add(
725                     new PacketSection(mPacket.position(), length, PacketSection.Type.IGNORE, 0, 0));
726             mPacket.position(mPacket.position() + length);
727         }
728 
729         /**
730          * Add a packet section that represents a lifetime, starting from the current position.
731          * @param length the length of the section in bytes
732          * @param optionType the RA option containing this lifetime, or 0 for router lifetime
733          * @param lifetime the lifetime
734          */
addLifetimeSection(int length, int optionType, long lifetime)735         private void addLifetimeSection(int length, int optionType, long lifetime) {
736             mPacketSections.add(
737                     new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME,
738                             optionType, lifetime));
739             mPacket.position(mPacket.position() + length);
740         }
741 
742         /**
743          * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option
744          * @param optionType the RA option that is being added
745          * @param optionLength the length of the option in bytes
746          */
add4ByteLifetimeOption(int optionType, int optionLength)747         private long add4ByteLifetimeOption(int optionType, int optionLength) {
748             addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET);
749             final long lifetime = getUint32(mPacket, mPacket.position());
750             addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, optionType, lifetime);
751             addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET
752                     - ICMP6_4_BYTE_LIFETIME_LEN);
753             return lifetime;
754         }
755 
756         // http://b/66928272 http://b/65056012
757         // DnsServerRepository ignores RDNSS servers with lifetimes that are too low. Ignore these
758         // lifetimes for the purpose of filter lifetime calculations.
shouldIgnoreLifetime(int optionType, long lifetime)759         private boolean shouldIgnoreLifetime(int optionType, long lifetime) {
760             return optionType == ICMP6_RDNSS_OPTION_TYPE
761                     && lifetime != 0 && lifetime < mMinRdnssLifetimeSec;
762         }
763 
isRelevantLifetime(PacketSection section)764         private boolean isRelevantLifetime(PacketSection section) {
765             return section.type == PacketSection.Type.LIFETIME
766                     && !shouldIgnoreLifetime(section.option, section.lifetime);
767         }
768 
769         // Note that this parses RA and may throw InvalidRaException (from
770         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
771         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
772         // specifications.
Ra(byte[] packet, int length)773         Ra(byte[] packet, int length) throws InvalidRaException {
774             if (length < ICMP6_RA_OPTION_OFFSET) {
775                 throw new InvalidRaException("Not an ICMP6 router advertisement: too short");
776             }
777 
778             mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
779             mLastSeen = currentTimeSeconds();
780 
781             // Sanity check packet in case a packet arrives before we attach RA filter
782             // to our packet socket. b/29586253
783             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
784                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
785                     getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
786                 throw new InvalidRaException("Not an ICMP6 router advertisement");
787             }
788 
789 
790             RaEvent.Builder builder = new RaEvent.Builder();
791 
792             // Ignore the flow label and low 4 bits of traffic class.
793             addMatchUntil(IPV6_FLOW_LABEL_OFFSET);
794             addIgnoreSection(IPV6_FLOW_LABEL_LEN);
795 
796             // Ignore checksum.
797             addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET);
798             addIgnoreSection(ICMP6_RA_CHECKSUM_LEN);
799 
800             // Parse router lifetime
801             addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET);
802             final long routerLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET);
803             addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, 0, routerLifetime);
804             builder.updateRouterLifetime(routerLifetime);
805 
806             // Add remaining fields (reachable time and retransmission timer) to match section.
807             addMatchUntil(ICMP6_RA_OPTION_OFFSET);
808 
809             while (mPacket.hasRemaining()) {
810                 final int position = mPacket.position();
811                 final int optionType = getUint8(mPacket, position);
812                 final int optionLength = getUint8(mPacket, position + 1) * 8;
813                 long lifetime;
814                 switch (optionType) {
815                     case ICMP6_PREFIX_OPTION_TYPE:
816                         mPrefixOptionOffsets.add(position);
817 
818                         // Parse valid lifetime
819                         addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
820                         lifetime = getUint32(mPacket, mPacket.position());
821                         addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
822                                 ICMP6_PREFIX_OPTION_TYPE, lifetime);
823                         builder.updatePrefixValidLifetime(lifetime);
824 
825                         // Parse preferred lifetime
826                         lifetime = getUint32(mPacket, mPacket.position());
827                         addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN,
828                                 ICMP6_PREFIX_OPTION_TYPE, lifetime);
829                         builder.updatePrefixPreferredLifetime(lifetime);
830 
831                         addMatchSection(4);       // Reserved bytes
832                         addMatchSection(IPV6_ADDR_LEN);  // The prefix itself
833                         break;
834                     // These three options have the same lifetime offset and size, and
835                     // are processed with the same specialized add4ByteLifetimeOption:
836                     case ICMP6_RDNSS_OPTION_TYPE:
837                         mRdnssOptionOffsets.add(position);
838                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
839                         builder.updateRdnssLifetime(lifetime);
840                         break;
841                     case ICMP6_ROUTE_INFO_OPTION_TYPE:
842                         mRioOptionOffsets.add(position);
843                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
844                         builder.updateRouteInfoLifetime(lifetime);
845                         break;
846                     case ICMP6_DNSSL_OPTION_TYPE:
847                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
848                         builder.updateDnsslLifetime(lifetime);
849                         break;
850                     default:
851                         // RFC4861 section 4.2 dictates we ignore unknown options for forwards
852                         // compatibility.
853                         mPacket.position(position + optionLength);
854                         break;
855                 }
856                 if (optionLength <= 0) {
857                     throw new InvalidRaException(String.format(
858                         "Invalid option length opt=%d len=%d", optionType, optionLength));
859                 }
860             }
861             mMinLifetime = minLifetime();
862             mMetricsLog.log(builder.build());
863         }
864 
865         // Considering only the MATCH sections, does {@code packet} match this RA?
matches(byte[] packet, int length)866         boolean matches(byte[] packet, int length) {
867             if (length != mPacket.capacity()) return false;
868             byte[] referencePacket = mPacket.array();
869             for (PacketSection section : mPacketSections) {
870                 if (section.type != PacketSection.Type.MATCH) continue;
871                 for (int i = section.start; i < (section.start + section.length); i++) {
872                     if (packet[i] != referencePacket[i]) return false;
873                 }
874             }
875             return true;
876         }
877 
878         // What is the minimum of all lifetimes within {@code packet} in seconds?
879         // Precondition: matches(packet, length) already returned true.
minLifetime()880         long minLifetime() {
881             long minLifetime = Long.MAX_VALUE;
882             for (PacketSection section : mPacketSections) {
883                 if (isRelevantLifetime(section)) {
884                     minLifetime = Math.min(minLifetime, section.lifetime);
885                 }
886             }
887             return minLifetime;
888         }
889 
890         // How many seconds does this RA's have to live, taking into account the fact
891         // that we might have seen it a while ago.
currentLifetime()892         long currentLifetime() {
893             return mMinLifetime - (currentTimeSeconds() - mLastSeen);
894         }
895 
isExpired()896         boolean isExpired() {
897             // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
898             // have to calculate the filter lifetime specially as a fraction of 0 is still 0.
899             return currentLifetime() <= 0;
900         }
901 
902         // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
903         // Jump to the next filter if packet doesn't match this RA.
904         @GuardedBy("ApfFilter.this")
generateFilterLocked(ApfGenerator gen)905         long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
906             String nextFilterLabel = "Ra" + getUniqueNumberLocked();
907             // Skip if packet is not the right size
908             gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
909             gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
910             int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
911             // Skip filter if expired
912             gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
913             gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
914             for (PacketSection section : mPacketSections) {
915                 // Generate code to match the packet bytes.
916                 if (section.type == PacketSection.Type.MATCH) {
917                     gen.addLoadImmediate(Register.R0, section.start);
918                     gen.addJumpIfBytesNotEqual(Register.R0,
919                             Arrays.copyOfRange(mPacket.array(), section.start,
920                                     section.start + section.length),
921                             nextFilterLabel);
922                 }
923 
924                 // Generate code to test the lifetimes haven't gone down too far.
925                 // The packet is accepted if any non-ignored lifetime is lower than filterLifetime.
926                 if (isRelevantLifetime(section)) {
927                     switch (section.length) {
928                         case 4: gen.addLoad32(Register.R0, section.start); break;
929                         case 2: gen.addLoad16(Register.R0, section.start); break;
930                         default:
931                             throw new IllegalStateException(
932                                     "bogus lifetime size " + section.length);
933                     }
934                     gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
935                 }
936             }
937             maybeSetupCounter(gen, Counter.DROPPED_RA);
938             gen.addJump(mCountAndDropLabel);
939             gen.defineLabel(nextFilterLabel);
940             return filterLifetime;
941         }
942     }
943 
944     // TODO: Refactor these subclasses to avoid so much repetition.
945     private abstract static class KeepalivePacket {
946         // Note that the offset starts from IP header.
947         // These must be added ether header length when generating program.
948         static final int IP_HEADER_OFFSET = 0;
949         static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
950 
951         // Append a filter for this keepalive ack to {@code gen}.
952         // Jump to drop if it matches the keepalive ack.
953         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfGenerator gen)954         abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
955     }
956 
957     // A class to hold NAT-T keepalive ack information.
958     private class NattKeepaliveResponse extends KeepalivePacket {
959         static final int UDP_LENGTH_OFFSET = 4;
960         static final int UDP_HEADER_LEN = 8;
961 
962         protected class NattKeepaliveResponseData {
963             public final byte[] srcAddress;
964             public final int srcPort;
965             public final byte[] dstAddress;
966             public final int dstPort;
967 
NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)968             NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
969                 srcAddress = sentKeepalivePacket.dstAddress;
970                 srcPort = sentKeepalivePacket.dstPort;
971                 dstAddress = sentKeepalivePacket.srcAddress;
972                 dstPort = sentKeepalivePacket.srcPort;
973             }
974         }
975 
976         protected final NattKeepaliveResponseData mPacket;
977         protected final byte[] mSrcDstAddr;
978         protected final byte[] mPortFingerprint;
979         // NAT-T keepalive packet
980         protected final byte[] mPayload = {(byte) 0xff};
981 
NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)982         NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
983             mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
984             mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress);
985             mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
986         }
987 
generatePortFingerprint(int srcPort, int dstPort)988         byte[] generatePortFingerprint(int srcPort, int dstPort) {
989             final ByteBuffer fp = ByteBuffer.allocate(4);
990             fp.order(ByteOrder.BIG_ENDIAN);
991             fp.putShort((short) srcPort);
992             fp.putShort((short) dstPort);
993             return fp.array();
994         }
995 
996         @Override
generateFilterLocked(ApfGenerator gen)997         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
998             final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked();
999 
1000             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1001             gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
1002 
1003             // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
1004             // Check payload length is 1
1005             gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1006             gen.addAdd(UDP_HEADER_LEN);
1007             gen.addSwap();
1008             gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET);
1009             gen.addNeg(Register.R1);
1010             gen.addAddR1();
1011             gen.addJumpIfR0NotEquals(1, nextFilterLabel);
1012 
1013             // Check that the ports match
1014             gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1015             gen.addAdd(ETH_HEADER_LEN);
1016             gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel);
1017 
1018             // Payload offset = R0 + UDP header length
1019             gen.addAdd(UDP_HEADER_LEN);
1020             gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel);
1021 
1022             maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE);
1023             gen.addJump(mCountAndDropLabel);
1024             gen.defineLabel(nextFilterLabel);
1025         }
1026 
toString()1027         public String toString() {
1028             try {
1029                 return String.format("%s -> %s",
1030                         NetworkStackUtils.addressAndPortToString(
1031                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1032                         NetworkStackUtils.addressAndPortToString(
1033                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
1034             } catch (UnknownHostException e) {
1035                 return "Unknown host";
1036             }
1037         }
1038     }
1039 
1040     // A class to hold TCP keepalive ack information.
1041     private abstract static class TcpKeepaliveAck extends KeepalivePacket {
1042         protected static class TcpKeepaliveAckData {
1043             public final byte[] srcAddress;
1044             public final int srcPort;
1045             public final byte[] dstAddress;
1046             public final int dstPort;
1047             public final int seq;
1048             public final int ack;
1049 
1050             // Create the characteristics of the ack packet from the sent keepalive packet.
TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1051             TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1052                 srcAddress = sentKeepalivePacket.dstAddress;
1053                 srcPort = sentKeepalivePacket.dstPort;
1054                 dstAddress = sentKeepalivePacket.srcAddress;
1055                 dstPort = sentKeepalivePacket.srcPort;
1056                 seq = sentKeepalivePacket.ack;
1057                 ack = sentKeepalivePacket.seq + 1;
1058             }
1059         }
1060 
1061         protected final TcpKeepaliveAckData mPacket;
1062         protected final byte[] mSrcDstAddr;
1063         protected final byte[] mPortSeqAckFingerprint;
1064 
TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1065         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
1066             mPacket = packet;
1067             mSrcDstAddr = srcDstAddr;
1068             mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
1069                     mPacket.dstPort, mPacket.seq, mPacket.ack);
1070         }
1071 
generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1072         static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
1073             final ByteBuffer fp = ByteBuffer.allocate(12);
1074             fp.order(ByteOrder.BIG_ENDIAN);
1075             fp.putShort((short) srcPort);
1076             fp.putShort((short) dstPort);
1077             fp.putInt(seq);
1078             fp.putInt(ack);
1079             return fp.array();
1080         }
1081 
toString()1082         public String toString() {
1083             try {
1084                 return String.format("%s -> %s , seq=%d, ack=%d",
1085                         NetworkStackUtils.addressAndPortToString(
1086                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1087                         NetworkStackUtils.addressAndPortToString(
1088                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
1089                         Integer.toUnsignedLong(mPacket.seq),
1090                         Integer.toUnsignedLong(mPacket.ack));
1091             } catch (UnknownHostException e) {
1092                 return "Unknown host";
1093             }
1094         }
1095 
1096         // Append a filter for this keepalive ack to {@code gen}.
1097         // Jump to drop if it matches the keepalive ack.
1098         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfGenerator gen)1099         abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
1100     }
1101 
1102     private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
1103 
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1104         TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1105             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1106         }
TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1107         TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
1108             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1109         }
1110 
1111         @Override
generateFilterLocked(ApfGenerator gen)1112         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1113             final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
1114 
1115             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1116             gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
1117 
1118             // Skip to the next filter if it's not zero-sized :
1119             // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
1120             // Load the IP header size into R1
1121             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1122             // Load the TCP header size into R0 (it's indexed by R1)
1123             gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
1124             // Size offset is in the top nibble, but it must be multiplied by 4, and the two
1125             // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
1126             gen.addRightShift(2);
1127             // R0 += R1 -> R0 contains TCP + IP headers length
1128             gen.addAddR1();
1129             // Load IPv4 total length
1130             gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
1131             gen.addNeg(Register.R0);
1132             gen.addAddR1();
1133             gen.addJumpIfR0NotEquals(0, nextFilterLabel);
1134             // Add IPv4 header length
1135             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1136             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
1137             gen.addAddR1();
1138             gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
1139 
1140             maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
1141             gen.addJump(mCountAndDropLabel);
1142             gen.defineLabel(nextFilterLabel);
1143         }
1144     }
1145 
1146     private class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1147         TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1148             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1149         }
TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1150         TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
1151             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1152         }
1153 
1154         @Override
generateFilterLocked(ApfGenerator gen)1155         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1156             throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
1157         }
1158     }
1159 
1160     // Maximum number of RAs to filter for.
1161     private static final int MAX_RAS = 10;
1162 
1163     @GuardedBy("this")
1164     private ArrayList<Ra> mRas = new ArrayList<>();
1165     @GuardedBy("this")
1166     private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
1167 
1168     // There is always some marginal benefit to updating the installed APF program when an RA is
1169     // seen because we can extend the program's lifetime slightly, but there is some cost to
1170     // updating the program, so don't bother unless the program is going to expire soon. This
1171     // constant defines "soon" in seconds.
1172     private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
1173     // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
1174     // see a refresh.  Using half the lifetime might be a good idea except for the fact that
1175     // packets may be dropped, so let's use 6.
1176     private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
1177 
1178     // When did we last install a filter program? In seconds since Unix Epoch.
1179     @GuardedBy("this")
1180     private long mLastTimeInstalledProgram;
1181     // How long should the last installed filter program live for? In seconds.
1182     @GuardedBy("this")
1183     private long mLastInstalledProgramMinLifetime;
1184     @GuardedBy("this")
1185     private ApfProgramEvent.Builder mLastInstallEvent;
1186 
1187     // For debugging only. The last program installed.
1188     @GuardedBy("this")
1189     private byte[] mLastInstalledProgram;
1190 
1191     /**
1192      * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
1193      *
1194      * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
1195      * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
1196      * the opcodes to access the data buffer (LDDW and STDW).
1197      */
1198     @GuardedBy("this") @Nullable
1199     private byte[] mDataSnapshot;
1200 
1201     // How many times the program was updated since we started.
1202     @GuardedBy("this")
1203     private int mNumProgramUpdates = 0;
1204     // How many times the program was updated since we started for allowing multicast traffic.
1205     @GuardedBy("this")
1206     private int mNumProgramUpdatesAllowingMulticast = 0;
1207 
1208     /**
1209      * Generate filter code to process ARP packets. Execution of this code ends in either the
1210      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1211      * Preconditions:
1212      *  - Packet being filtered is ARP
1213      */
1214     @GuardedBy("this")
generateArpFilterLocked(ApfGenerator gen)1215     private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1216         // Here's a basic summary of what the ARP filter program does:
1217         //
1218         // if not ARP IPv4
1219         //   pass
1220         // if not ARP IPv4 reply or request
1221         //   pass
1222         // if ARP reply source ip is 0.0.0.0
1223         //   drop
1224         // if unicast ARP reply
1225         //   pass
1226         // if interface has no IPv4 address
1227         //   if target ip is 0.0.0.0
1228         //      drop
1229         // else
1230         //   if target ip is not the interface ip
1231         //      drop
1232         // pass
1233 
1234         final String checkTargetIPv4 = "checkTargetIPv4";
1235 
1236         // Pass if not ARP IPv4.
1237         gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
1238         maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
1239         gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
1240 
1241         // Pass if unknown ARP opcode.
1242         gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
1243         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
1244         maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
1245         gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
1246 
1247         // Drop if ARP reply source IP is 0.0.0.0
1248         gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
1249         maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
1250         gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
1251 
1252         // Pass if unicast reply.
1253         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1254         maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
1255         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
1256 
1257         // Either a unicast request, a unicast reply, or a broadcast reply.
1258         gen.defineLabel(checkTargetIPv4);
1259         if (mIPv4Address == null) {
1260             // When there is no IPv4 address, drop GARP replies (b/29404209).
1261             gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1262             maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
1263             gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
1264         } else {
1265             // When there is an IPv4 address, drop unicast/broadcast requests
1266             // and broadcast replies with a different target IPv4 address.
1267             gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1268             maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
1269             gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
1270         }
1271 
1272         maybeSetupCounter(gen, Counter.PASSED_ARP);
1273         gen.addJump(mCountAndPassLabel);
1274     }
1275 
1276     /**
1277      * Generate filter code to process IPv4 packets. Execution of this code ends in either the
1278      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1279      * Preconditions:
1280      *  - Packet being filtered is IPv4
1281      */
1282     @GuardedBy("this")
generateIPv4FilterLocked(ApfGenerator gen)1283     private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1284         // Here's a basic summary of what the IPv4 filter program does:
1285         //
1286         // if filtering multicast (i.e. multicast lock not held):
1287         //   if it's DHCP destined to our MAC:
1288         //     pass
1289         //   if it's L2 broadcast:
1290         //     drop
1291         //   if it's IPv4 multicast:
1292         //     drop
1293         //   if it's IPv4 broadcast:
1294         //     drop
1295         // if keepalive ack
1296         //   drop
1297         // pass
1298 
1299         if (mMulticastFilter) {
1300             final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
1301 
1302             // Pass DHCP addressed to us.
1303             // Check it's UDP.
1304             gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
1305             gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
1306             // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
1307             gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
1308             gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
1309             // Check it's addressed to DHCP client port.
1310             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1311             gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
1312             gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
1313             // Check it's DHCP to our MAC address.
1314             gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
1315             // NOTE: Relies on R1 containing IPv4 header offset.
1316             gen.addAddR1();
1317             gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
1318             maybeSetupCounter(gen, Counter.PASSED_DHCP);
1319             gen.addJump(mCountAndPassLabel);
1320 
1321             // Drop all multicasts/broadcasts.
1322             gen.defineLabel(skipDhcpv4Filter);
1323 
1324             // If IPv4 destination address is in multicast range, drop.
1325             gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
1326             gen.addAnd(0xf0);
1327             maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
1328             gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
1329 
1330             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
1331             maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
1332             gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
1333             gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
1334             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
1335                 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
1336                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
1337                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
1338             }
1339 
1340             // If any TCP keepalive filter matches, drop
1341             generateV4KeepaliveFilters(gen);
1342 
1343             // If any NAT-T keepalive filter matches, drop
1344             generateV4NattKeepaliveFilters(gen);
1345 
1346             // Otherwise, this is an IPv4 unicast, pass
1347             // If L2 broadcast packet, drop.
1348             // TODO: can we invert this condition to fall through to the common pass case below?
1349             maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
1350             gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1351             gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
1352             maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
1353             gen.addJump(mCountAndDropLabel);
1354         } else {
1355             generateV4KeepaliveFilters(gen);
1356             generateV4NattKeepaliveFilters(gen);
1357         }
1358 
1359         // Otherwise, pass
1360         maybeSetupCounter(gen, Counter.PASSED_IPV4);
1361         gen.addJump(mCountAndPassLabel);
1362     }
1363 
generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto, int offset, String label)1364     private void generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto,
1365             int offset, String label) throws IllegalInstructionException {
1366         final boolean haveKeepaliveResponses = NetworkStackUtils.any(mKeepalivePackets,
1367                 ack -> filterType.isInstance(ack));
1368 
1369         // If no keepalive packets of this type
1370         if (!haveKeepaliveResponses) return;
1371 
1372         // If not the right proto, skip keepalive filters
1373         gen.addLoad8(Register.R0, offset);
1374         gen.addJumpIfR0NotEquals(proto, label);
1375 
1376         // Drop Keepalive responses
1377         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1378             final KeepalivePacket response = mKeepalivePackets.valueAt(i);
1379             if (filterType.isInstance(response)) response.generateFilterLocked(gen);
1380         }
1381 
1382         gen.defineLabel(label);
1383     }
1384 
generateV4KeepaliveFilters(ApfGenerator gen)1385     private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
1386         generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
1387                 "skip_v4_keepalive_filter");
1388     }
1389 
generateV4NattKeepaliveFilters(ApfGenerator gen)1390     private void generateV4NattKeepaliveFilters(ApfGenerator gen)
1391             throws IllegalInstructionException {
1392         generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
1393                 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, "skip_v4_nattkeepalive_filter");
1394     }
1395 
1396     /**
1397      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
1398      * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
1399      * Preconditions:
1400      *  - Packet being filtered is IPv6
1401      */
1402     @GuardedBy("this")
generateIPv6FilterLocked(ApfGenerator gen)1403     private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1404         // Here's a basic summary of what the IPv6 filter program does:
1405         //
1406         // if we're dropping multicast
1407         //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
1408         //     if it's multicast:
1409         //       drop
1410         //     pass
1411         // if it's ICMPv6 RS to any:
1412         //   drop
1413         // if it's ICMPv6 NA to ff02::1:
1414         //   drop
1415         // if keepalive ack
1416         //   drop
1417 
1418         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
1419 
1420         // Drop multicast if the multicast filter is enabled.
1421         if (mMulticastFilter) {
1422             final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
1423             final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
1424 
1425             // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
1426             // While awake, let all ICMPv6 multicasts through.
1427             if (mInDozeMode) {
1428                 // Not ICMPv6? -> Proceed to multicast filtering
1429                 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
1430 
1431                 // ICMPv6 but not ECHO? -> Skip the multicast filter.
1432                 // (ICMPv6 ECHO requests will go through the multicast filter below).
1433                 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
1434                 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
1435             } else {
1436                 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
1437             }
1438 
1439             // Drop all other packets sent to ff00::/8 (multicast prefix).
1440             gen.defineLabel(dropAllIPv6MulticastsLabel);
1441             maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
1442             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
1443             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
1444             // If any keepalive filter matches, drop
1445             generateV6KeepaliveFilters(gen);
1446             // Not multicast. Pass.
1447             maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
1448             gen.addJump(mCountAndPassLabel);
1449             gen.defineLabel(skipIPv6MulticastFilterLabel);
1450         } else {
1451             generateV6KeepaliveFilters(gen);
1452             // If not ICMPv6, pass.
1453             maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
1454             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
1455         }
1456 
1457         // If we got this far, the packet is ICMPv6.  Drop some specific types.
1458 
1459         // Add unsolicited multicast neighbor announcements filter
1460         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
1461         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
1462         // Drop all router solicitations (b/32833400)
1463         maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
1464         gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
1465         // If not neighbor announcements, skip filter.
1466         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
1467         // If to ff02::1, drop.
1468         // TODO: Drop only if they don't contain the address of on-link neighbours.
1469         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
1470         gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
1471                 skipUnsolicitedMulticastNALabel);
1472         maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
1473         gen.addJump(mCountAndDropLabel);
1474         gen.defineLabel(skipUnsolicitedMulticastNALabel);
1475     }
1476 
generateV6KeepaliveFilters(ApfGenerator gen)1477     private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
1478         generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
1479                 "skip_v6_keepalive_filter");
1480     }
1481 
1482     /**
1483      * Begin generating an APF program to:
1484      * <ul>
1485      * <li>Drop/Pass 802.3 frames (based on policy)
1486      * <li>Drop packets with EtherType within the Black List
1487      * <li>Drop ARP requests not for us, if mIPv4Address is set,
1488      * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
1489      * <li>Drop IPv4 multicast packets, if mMulticastFilter,
1490      * <li>Pass all other IPv4 packets,
1491      * <li>Drop all broadcast non-IP non-ARP packets.
1492      * <li>Pass all non-ICMPv6 IPv6 packets,
1493      * <li>Pass all non-IPv4 and non-IPv6 packets,
1494      * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
1495      * <li>Drop IPv6 ICMPv6 RSs.
1496      * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
1497      * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
1498      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
1499      *     insertion of RA filters here, or if there aren't any, just passes the packets.
1500      * </ul>
1501      */
1502     @GuardedBy("this")
emitPrologueLocked()1503     private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
1504         // This is guaranteed to succeed because of the check in maybeCreate.
1505         ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
1506 
1507         if (mApfCapabilities.hasDataAccess()) {
1508             // Increment TOTAL_PACKETS
1509             maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
1510             gen.addLoadData(Register.R0, 0);  // load counter
1511             gen.addAdd(1);
1512             gen.addStoreData(Register.R0, 0);  // write-back counter
1513         }
1514 
1515         // Here's a basic summary of what the initial program does:
1516         //
1517         // if it's a 802.3 Frame (ethtype < 0x0600):
1518         //    drop or pass based on configurations
1519         // if it has a ether-type that belongs to the black list
1520         //    drop
1521         // if it's ARP:
1522         //   insert ARP filter to drop or pass these appropriately
1523         // if it's IPv4:
1524         //   insert IPv4 filter to drop or pass these appropriately
1525         // if it's not IPv6:
1526         //   if it's broadcast:
1527         //     drop
1528         //   pass
1529         // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
1530 
1531         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1532 
1533         if (mDrop802_3Frames) {
1534             // drop 802.3 frames (ethtype < 0x0600)
1535             maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
1536             gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
1537         }
1538 
1539         // Handle ether-type black list
1540         maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
1541         for (int p : mEthTypeBlackList) {
1542             gen.addJumpIfR0Equals(p, mCountAndDropLabel);
1543         }
1544 
1545         // Add ARP filters:
1546         String skipArpFiltersLabel = "skipArpFilters";
1547         gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
1548         generateArpFilterLocked(gen);
1549         gen.defineLabel(skipArpFiltersLabel);
1550 
1551         // Add IPv4 filters:
1552         String skipIPv4FiltersLabel = "skipIPv4Filters";
1553         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
1554         // execute the ARP filter, since that filter does not fall through, but either drops or
1555         // passes.
1556         gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
1557         generateIPv4FilterLocked(gen);
1558         gen.defineLabel(skipIPv4FiltersLabel);
1559 
1560         // Check for IPv6:
1561         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
1562         // execute the ARP or IPv4 filters, since those filters do not fall through, but either
1563         // drop or pass.
1564         String ipv6FilterLabel = "IPv6Filters";
1565         gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
1566 
1567         // Drop non-IP non-ARP broadcasts, pass the rest
1568         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1569         maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
1570         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
1571         maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
1572         gen.addJump(mCountAndDropLabel);
1573 
1574         // Add IPv6 filters:
1575         gen.defineLabel(ipv6FilterLabel);
1576         generateIPv6FilterLocked(gen);
1577         return gen;
1578     }
1579 
1580     /**
1581      * Append packet counting epilogue to the APF program.
1582      *
1583      * Currently, the epilogue consists of two trampolines which count passed and dropped packets
1584      * before jumping to the actual PASS and DROP labels.
1585      */
1586     @GuardedBy("this")
emitEpilogue(ApfGenerator gen)1587     private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
1588         // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
1589         // will just fall-through to the PASS label.
1590         if (!mApfCapabilities.hasDataAccess()) return;
1591 
1592         // Execution will reach the bottom of the program if none of the filters match,
1593         // which will pass the packet to the application processor.
1594         maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
1595 
1596         // Append the count & pass trampoline, which increments the counter at the data address
1597         // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
1598         // the entire sequence inline for every counter.
1599         gen.defineLabel(mCountAndPassLabel);
1600         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
1601         gen.addAdd(1);                     // R0++
1602         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
1603         gen.addJump(gen.PASS_LABEL);
1604 
1605         // Same as above for the count & drop trampoline.
1606         gen.defineLabel(mCountAndDropLabel);
1607         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
1608         gen.addAdd(1);                     // R0++
1609         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
1610         gen.addJump(gen.DROP_LABEL);
1611     }
1612 
1613     /**
1614      * Generate and install a new filter program.
1615      */
1616     @GuardedBy("this")
1617     @VisibleForTesting
installNewProgramLocked()1618     void installNewProgramLocked() {
1619         purgeExpiredRasLocked();
1620         ArrayList<Ra> rasToFilter = new ArrayList<>();
1621         final byte[] program;
1622         long programMinLifetime = Long.MAX_VALUE;
1623         long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
1624         if (mApfCapabilities.hasDataAccess()) {
1625             // Reserve space for the counters.
1626             maximumApfProgramSize -= Counter.totalSize();
1627         }
1628 
1629         try {
1630             // Step 1: Determine how many RA filters we can fit in the program.
1631             ApfGenerator gen = emitPrologueLocked();
1632 
1633             // The epilogue normally goes after the RA filters, but add it early to include its
1634             // length when estimating the total.
1635             emitEpilogue(gen);
1636 
1637             // Can't fit the program even without any RA filters?
1638             if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
1639                 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
1640                 return;
1641             }
1642 
1643             for (Ra ra : mRas) {
1644                 ra.generateFilterLocked(gen);
1645                 // Stop if we get too big.
1646                 if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
1647                     if (VDBG) Log.d(TAG, "Past maximum program size, skipping RAs");
1648                     break;
1649                 }
1650 
1651                 rasToFilter.add(ra);
1652             }
1653 
1654             // Step 2: Actually generate the program
1655             gen = emitPrologueLocked();
1656             for (Ra ra : rasToFilter) {
1657                 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
1658             }
1659             emitEpilogue(gen);
1660             program = gen.generate();
1661         } catch (IllegalInstructionException|IllegalStateException e) {
1662             Log.e(TAG, "Failed to generate APF program.", e);
1663             return;
1664         }
1665         final long now = currentTimeSeconds();
1666         mLastTimeInstalledProgram = now;
1667         mLastInstalledProgramMinLifetime = programMinLifetime;
1668         mLastInstalledProgram = program;
1669         mNumProgramUpdates++;
1670 
1671         if (VDBG) {
1672             hexDump("Installing filter: ", program, program.length);
1673         }
1674         mIpClientCallback.installPacketFilter(program);
1675         logApfProgramEventLocked(now);
1676         mLastInstallEvent = new ApfProgramEvent.Builder()
1677                 .setLifetime(programMinLifetime)
1678                 .setFilteredRas(rasToFilter.size())
1679                 .setCurrentRas(mRas.size())
1680                 .setProgramLength(program.length)
1681                 .setFlags(mIPv4Address != null, mMulticastFilter);
1682     }
1683 
1684     @GuardedBy("this")
logApfProgramEventLocked(long now)1685     private void logApfProgramEventLocked(long now) {
1686         if (mLastInstallEvent == null) {
1687             return;
1688         }
1689         ApfProgramEvent.Builder ev = mLastInstallEvent;
1690         mLastInstallEvent = null;
1691         final long actualLifetime = now - mLastTimeInstalledProgram;
1692         ev.setActualLifetime(actualLifetime);
1693         if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
1694             return;
1695         }
1696         mMetricsLog.log(ev.build());
1697     }
1698 
1699     /**
1700      * Returns {@code true} if a new program should be installed because the current one dies soon.
1701      */
shouldInstallnewProgram()1702     private boolean shouldInstallnewProgram() {
1703         long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
1704         return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
1705     }
1706 
hexDump(String msg, byte[] packet, int length)1707     private void hexDump(String msg, byte[] packet, int length) {
1708         log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
1709     }
1710 
1711     @GuardedBy("this")
purgeExpiredRasLocked()1712     private void purgeExpiredRasLocked() {
1713         for (int i = 0; i < mRas.size();) {
1714             if (mRas.get(i).isExpired()) {
1715                 log("Expiring " + mRas.get(i));
1716                 mRas.remove(i);
1717             } else {
1718                 i++;
1719             }
1720         }
1721     }
1722 
1723     /**
1724      * Process an RA packet, updating the list of known RAs and installing a new APF program
1725      * if the current APF program should be updated.
1726      * @return a ProcessRaResult enum describing what action was performed.
1727      */
1728     @VisibleForTesting
processRa(byte[] packet, int length)1729     synchronized ProcessRaResult processRa(byte[] packet, int length) {
1730         if (VDBG) hexDump("Read packet = ", packet, length);
1731 
1732         // Have we seen this RA before?
1733         for (int i = 0; i < mRas.size(); i++) {
1734             Ra ra = mRas.get(i);
1735             if (ra.matches(packet, length)) {
1736                 if (VDBG) log("matched RA " + ra);
1737                 // Update lifetimes.
1738                 ra.mLastSeen = currentTimeSeconds();
1739                 ra.mMinLifetime = ra.minLifetime();
1740                 ra.seenCount++;
1741 
1742                 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
1743                 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
1744                 // until the filter program exceeds the maximum filter program size allowed by the
1745                 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
1746                 // filter program.
1747                 // TODO: consider sorting the RAs in order of increasing expiry time as well.
1748                 // Swap to front of array.
1749                 mRas.add(0, mRas.remove(i));
1750 
1751                 // If the current program doesn't expire for a while, don't update.
1752                 if (shouldInstallnewProgram()) {
1753                     installNewProgramLocked();
1754                     return ProcessRaResult.UPDATE_EXPIRY;
1755                 }
1756                 return ProcessRaResult.MATCH;
1757             }
1758         }
1759         purgeExpiredRasLocked();
1760         // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
1761         if (mRas.size() >= MAX_RAS) {
1762             return ProcessRaResult.DROPPED;
1763         }
1764         final Ra ra;
1765         try {
1766             ra = new Ra(packet, length);
1767         } catch (Exception e) {
1768             Log.e(TAG, "Error parsing RA", e);
1769             return ProcessRaResult.PARSE_ERROR;
1770         }
1771         // Ignore 0 lifetime RAs.
1772         if (ra.isExpired()) {
1773             return ProcessRaResult.ZERO_LIFETIME;
1774         }
1775         log("Adding " + ra);
1776         mRas.add(ra);
1777         installNewProgramLocked();
1778         return ProcessRaResult.UPDATE_NEW_RA;
1779     }
1780 
1781     /**
1782      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
1783      * filtering using APF programs.
1784      */
maybeCreate(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback)1785     public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
1786             InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) {
1787         if (context == null || config == null || ifParams == null) return null;
1788         ApfCapabilities apfCapabilities =  config.apfCapabilities;
1789         if (apfCapabilities == null) return null;
1790         if (apfCapabilities.apfVersionSupported == 0) return null;
1791         if (apfCapabilities.maximumApfProgramSize < 512) {
1792             Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
1793             return null;
1794         }
1795         // For now only support generating programs for Ethernet frames. If this restriction is
1796         // lifted:
1797         //   1. the program generator will need its offsets adjusted.
1798         //   2. the packet filter attached to our packet socket will need its offset adjusted.
1799         if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
1800         if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
1801             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
1802             return null;
1803         }
1804 
1805         return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
1806     }
1807 
shutdown()1808     public synchronized void shutdown() {
1809         if (mReceiveThread != null) {
1810             log("shutting down");
1811             mReceiveThread.halt();  // Also closes socket.
1812             mReceiveThread = null;
1813         }
1814         mRas.clear();
1815         mContext.unregisterReceiver(mDeviceIdleReceiver);
1816     }
1817 
setMulticastFilter(boolean isEnabled)1818     public synchronized void setMulticastFilter(boolean isEnabled) {
1819         if (mMulticastFilter == isEnabled) return;
1820         mMulticastFilter = isEnabled;
1821         if (!isEnabled) {
1822             mNumProgramUpdatesAllowingMulticast++;
1823         }
1824         installNewProgramLocked();
1825     }
1826 
1827     @VisibleForTesting
setDozeMode(boolean isEnabled)1828     public synchronized void setDozeMode(boolean isEnabled) {
1829         if (mInDozeMode == isEnabled) return;
1830         mInDozeMode = isEnabled;
1831         installNewProgramLocked();
1832     }
1833 
1834     /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
findIPv4LinkAddress(LinkProperties lp)1835     private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
1836         LinkAddress ipv4Address = null;
1837         for (LinkAddress address : lp.getLinkAddresses()) {
1838             if (!(address.getAddress() instanceof Inet4Address)) {
1839                 continue;
1840             }
1841             if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
1842                 // More than one IPv4 address, abort.
1843                 return null;
1844             }
1845             ipv4Address = address;
1846         }
1847         return ipv4Address;
1848     }
1849 
setLinkProperties(LinkProperties lp)1850     public synchronized void setLinkProperties(LinkProperties lp) {
1851         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
1852         final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
1853         final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
1854         final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
1855         if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
1856             return;
1857         }
1858         mIPv4Address = addr;
1859         mIPv4PrefixLength = prefix;
1860         installNewProgramLocked();
1861     }
1862 
1863     /**
1864      * Add TCP keepalive ack packet filter.
1865      * This will add a filter to drop acks to the keepalive packet passed as an argument.
1866      *
1867      * @param slot The index used to access the filter.
1868      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
1869      */
addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1870     public synchronized void addTcpKeepalivePacketFilter(final int slot,
1871             final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1872         log("Adding keepalive ack(" + slot + ")");
1873         if (null != mKeepalivePackets.get(slot)) {
1874             throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
1875         }
1876         final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
1877         mKeepalivePackets.put(slot, (ipVersion == 4)
1878                 ? new TcpKeepaliveAckV4(sentKeepalivePacket)
1879                 : new TcpKeepaliveAckV6(sentKeepalivePacket));
1880         installNewProgramLocked();
1881     }
1882 
1883     /**
1884      * Add NAT-T keepalive packet filter.
1885      * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
1886      *
1887      * @param slot The index used to access the filter.
1888      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
1889      */
addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)1890     public synchronized void addNattKeepalivePacketFilter(final int slot,
1891             final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1892         log("Adding NAT-T keepalive packet(" + slot + ")");
1893         if (null != mKeepalivePackets.get(slot)) {
1894             throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
1895         }
1896         if (sentKeepalivePacket.srcAddress.length != 4) {
1897             throw new IllegalArgumentException("NAT-T keepalive is only supported on IPv4");
1898         }
1899         mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
1900         installNewProgramLocked();
1901     }
1902 
1903     /**
1904      * Remove keepalive packet filter.
1905      *
1906      * @param slot The index used to access the filter.
1907      */
removeKeepalivePacketFilter(int slot)1908     public synchronized void removeKeepalivePacketFilter(int slot) {
1909         log("Removing keepalive packet(" + slot + ")");
1910         mKeepalivePackets.remove(slot);
1911         installNewProgramLocked();
1912     }
1913 
counterValue(byte[] data, Counter counter)1914     static public long counterValue(byte[] data, Counter counter)
1915             throws ArrayIndexOutOfBoundsException {
1916         // Follow the same wrap-around addressing scheme of the interpreter.
1917         int offset = counter.offset();
1918         if (offset < 0) {
1919             offset = data.length + offset;
1920         }
1921 
1922         // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
1923         long value = 0;
1924         for (int i = 0; i < 4; i++) {
1925             value = value << 8 | (data[offset] & 0xFF);
1926             offset++;
1927         }
1928         return value;
1929     }
1930 
dump(IndentingPrintWriter pw)1931     public synchronized void dump(IndentingPrintWriter pw) {
1932         pw.println("Capabilities: " + mApfCapabilities);
1933         pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
1934         pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
1935         pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec);
1936         try {
1937             pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
1938         } catch (UnknownHostException|NullPointerException e) {}
1939 
1940         if (mLastTimeInstalledProgram == 0) {
1941             pw.println("No program installed.");
1942             return;
1943         }
1944         pw.println("Program updates: " + mNumProgramUpdates);
1945         pw.println(String.format(
1946                 "Last program length %d, installed %ds ago, lifetime %ds",
1947                 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
1948                 mLastInstalledProgramMinLifetime));
1949 
1950         pw.println("RA filters:");
1951         pw.increaseIndent();
1952         for (Ra ra: mRas) {
1953             pw.println(ra);
1954             pw.increaseIndent();
1955             pw.println(String.format(
1956                     "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
1957             if (DBG) {
1958                 pw.println("Last match:");
1959                 pw.increaseIndent();
1960                 pw.println(ra.getLastMatchingPacket());
1961                 pw.decreaseIndent();
1962             }
1963             pw.decreaseIndent();
1964         }
1965         pw.decreaseIndent();
1966 
1967         pw.println("TCP Keepalive filters:");
1968         pw.increaseIndent();
1969         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1970             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
1971             if (keepalivePacket instanceof TcpKeepaliveAck) {
1972                 pw.print("Slot ");
1973                 pw.print(mKeepalivePackets.keyAt(i));
1974                 pw.print(": ");
1975                 pw.println(keepalivePacket);
1976             }
1977         }
1978         pw.decreaseIndent();
1979 
1980         pw.println("NAT-T Keepalive filters:");
1981         pw.increaseIndent();
1982         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1983             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
1984             if (keepalivePacket instanceof NattKeepaliveResponse) {
1985                 pw.print("Slot ");
1986                 pw.print(mKeepalivePackets.keyAt(i));
1987                 pw.print(": ");
1988                 pw.println(keepalivePacket);
1989             }
1990         }
1991         pw.decreaseIndent();
1992 
1993         if (DBG) {
1994             pw.println("Last program:");
1995             pw.increaseIndent();
1996             pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
1997             pw.decreaseIndent();
1998         }
1999 
2000         pw.println("APF packet counters: ");
2001         pw.increaseIndent();
2002         if (!mApfCapabilities.hasDataAccess()) {
2003             pw.println("APF counters not supported");
2004         } else if (mDataSnapshot == null) {
2005             pw.println("No last snapshot.");
2006         } else {
2007             try {
2008                 Counter[] counters = Counter.class.getEnumConstants();
2009                 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
2010                     long value = counterValue(mDataSnapshot, c);
2011                     // Only print non-zero counters
2012                     if (value != 0) {
2013                         pw.println(c.toString() + ": " + value);
2014                     }
2015                 }
2016             } catch (ArrayIndexOutOfBoundsException e) {
2017                 pw.println("Uh-oh: " + e);
2018             }
2019             if (VDBG) {
2020                 pw.println("Raw data dump: ");
2021                 pw.println(HexDump.dumpHexString(mDataSnapshot));
2022             }
2023         }
2024         pw.decreaseIndent();
2025     }
2026 
2027     // TODO: move to android.net.NetworkUtils
2028     @VisibleForTesting
ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)2029     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
2030         return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
2031     }
2032 
uint8(byte b)2033     private static int uint8(byte b) {
2034         return b & 0xff;
2035     }
2036 
getUint16(ByteBuffer buffer, int position)2037     private static int getUint16(ByteBuffer buffer, int position) {
2038         return buffer.getShort(position) & 0xffff;
2039     }
2040 
getUint32(ByteBuffer buffer, int position)2041     private static long getUint32(ByteBuffer buffer, int position) {
2042         return Integer.toUnsignedLong(buffer.getInt(position));
2043     }
2044 
getUint8(ByteBuffer buffer, int position)2045     private static int getUint8(ByteBuffer buffer, int position) {
2046         return uint8(buffer.get(position));
2047     }
2048 
bytesToBEInt(byte[] bytes)2049     private static int bytesToBEInt(byte[] bytes) {
2050         return (uint8(bytes[0]) << 24)
2051                 + (uint8(bytes[1]) << 16)
2052                 + (uint8(bytes[2]) << 8)
2053                 + (uint8(bytes[3]));
2054     }
2055 
concatArrays(final byte[]... arr)2056     private static byte[] concatArrays(final byte[]... arr) {
2057         int size = 0;
2058         for (byte[] a : arr) {
2059             size += a.length;
2060         }
2061         final byte[] result = new byte[size];
2062         int offset = 0;
2063         for (byte[] a : arr) {
2064             System.arraycopy(a, 0, result, offset, a.length);
2065             offset += a.length;
2066         }
2067         return result;
2068     }
2069 }
2070