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