1 /*
2  * Copyright (C) 2024 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.apf.ApfConstants.APF_MAX_ETH_TYPE_BLACK_LIST_LEN;
20 import static android.net.apf.ApfConstants.ARP_HEADER_OFFSET;
21 import static android.net.apf.ApfConstants.ARP_IPV4_HEADER;
22 import static android.net.apf.ApfConstants.ARP_OPCODE_OFFSET;
23 import static android.net.apf.ApfConstants.ARP_OPCODE_REPLY;
24 import static android.net.apf.ApfConstants.ARP_OPCODE_REQUEST;
25 import static android.net.apf.ApfConstants.ARP_SOURCE_IP_ADDRESS_OFFSET;
26 import static android.net.apf.ApfConstants.ARP_TARGET_IP_ADDRESS_OFFSET;
27 import static android.net.apf.ApfConstants.DHCP_CLIENT_MAC_OFFSET;
28 import static android.net.apf.ApfConstants.DHCP_CLIENT_PORT;
29 import static android.net.apf.ApfConstants.DHCP_SERVER_PORT;
30 import static android.net.apf.ApfConstants.ECHO_PORT;
31 import static android.net.apf.ApfConstants.ETH_DEST_ADDR_OFFSET;
32 import static android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET;
33 import static android.net.apf.ApfConstants.ETH_HEADER_LEN;
34 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V4_MAC_ADDRESS;
35 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V6_MAC_ADDRESS;
36 import static android.net.apf.ApfConstants.ETH_TYPE_MAX;
37 import static android.net.apf.ApfConstants.ETH_TYPE_MIN;
38 import static android.net.apf.ApfConstants.FIXED_ARP_REPLY_HEADER;
39 import static android.net.apf.ApfConstants.ICMP6_CHECKSUM_OFFSET;
40 import static android.net.apf.ApfConstants.ICMP6_CODE_OFFSET;
41 import static android.net.apf.ApfConstants.ICMP6_NS_OPTION_TYPE_OFFSET;
42 import static android.net.apf.ApfConstants.ICMP6_NS_TARGET_IP_OFFSET;
43 import static android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET;
44 import static android.net.apf.ApfConstants.IPPROTO_HOPOPTS;
45 import static android.net.apf.ApfConstants.IPV4_ANY_HOST_ADDRESS;
46 import static android.net.apf.ApfConstants.IPV4_BROADCAST_ADDRESS;
47 import static android.net.apf.ApfConstants.IPV4_DEST_ADDR_OFFSET;
48 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_MORE_FRAGS_MASK;
49 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_MASK;
50 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_OFFSET;
51 import static android.net.apf.ApfConstants.IPV4_PROTOCOL_OFFSET;
52 import static android.net.apf.ApfConstants.IPV4_TOTAL_LENGTH_OFFSET;
53 import static android.net.apf.ApfConstants.IPV6_ALL_NODES_ADDRESS;
54 import static android.net.apf.ApfConstants.IPV6_DEST_ADDR_OFFSET;
55 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_LEN;
56 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_OFFSET;
57 import static android.net.apf.ApfConstants.IPV6_HEADER_LEN;
58 import static android.net.apf.ApfConstants.IPV6_HOP_LIMIT_OFFSET;
59 import static android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET;
60 import static android.net.apf.ApfConstants.IPV6_PAYLOAD_LEN_OFFSET;
61 import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX;
62 import static android.net.apf.ApfConstants.IPV6_SRC_ADDR_OFFSET;
63 import static android.net.apf.ApfConstants.MDNS_PORT;
64 import static android.net.apf.ApfConstants.TCP_HEADER_SIZE_OFFSET;
65 import static android.net.apf.ApfConstants.TCP_UDP_DESTINATION_PORT_OFFSET;
66 import static android.net.apf.ApfConstants.TCP_UDP_SOURCE_PORT_OFFSET;
67 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID;
68 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST;
69 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_MULTIPLE_OPTIONS;
70 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS;
71 import static android.net.apf.BaseApfGenerator.MemorySlot;
72 import static android.net.apf.BaseApfGenerator.Register.R0;
73 import static android.net.apf.BaseApfGenerator.Register.R1;
74 import static android.net.util.SocketUtils.makePacketSocketAddress;
75 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
76 import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
77 import static android.system.OsConstants.AF_PACKET;
78 import static android.system.OsConstants.ARPHRD_ETHER;
79 import static android.system.OsConstants.ETH_P_ARP;
80 import static android.system.OsConstants.ETH_P_IP;
81 import static android.system.OsConstants.ETH_P_IPV6;
82 import static android.system.OsConstants.IFA_F_TENTATIVE;
83 import static android.system.OsConstants.IPPROTO_ICMPV6;
84 import static android.system.OsConstants.IPPROTO_TCP;
85 import static android.system.OsConstants.IPPROTO_UDP;
86 import static android.system.OsConstants.SOCK_CLOEXEC;
87 import static android.system.OsConstants.SOCK_RAW;
88 
89 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
90 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
91 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
92 import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET;
93 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
94 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN;
95 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
96 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA_LEN;
97 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
98 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
99 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
100 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
101 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN;
102 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN;
103 
104 import android.annotation.NonNull;
105 import android.annotation.Nullable;
106 import android.content.BroadcastReceiver;
107 import android.content.Context;
108 import android.content.Intent;
109 import android.content.IntentFilter;
110 import android.net.LinkAddress;
111 import android.net.LinkProperties;
112 import android.net.MacAddress;
113 import android.net.NattKeepalivePacketDataParcelable;
114 import android.net.TcpKeepalivePacketDataParcelable;
115 import android.net.apf.ApfCounterTracker.Counter;
116 import android.net.apf.BaseApfGenerator.IllegalInstructionException;
117 import android.net.ip.IpClient.IpClientCallbacksWrapper;
118 import android.os.PowerManager;
119 import android.os.SystemClock;
120 import android.stats.connectivity.NetworkQuirkEvent;
121 import android.system.ErrnoException;
122 import android.system.Os;
123 import android.text.format.DateUtils;
124 import android.util.ArraySet;
125 import android.util.Log;
126 import android.util.Pair;
127 import android.util.SparseArray;
128 
129 import com.android.internal.annotations.GuardedBy;
130 import com.android.internal.annotations.VisibleForTesting;
131 import com.android.internal.util.HexDump;
132 import com.android.internal.util.IndentingPrintWriter;
133 import com.android.internal.util.TokenBucket;
134 import com.android.modules.utils.build.SdkLevel;
135 import com.android.net.module.util.CollectionUtils;
136 import com.android.net.module.util.ConnectivityUtils;
137 import com.android.net.module.util.InterfaceParams;
138 import com.android.net.module.util.SocketUtils;
139 import com.android.networkstack.metrics.ApfSessionInfoMetrics;
140 import com.android.networkstack.metrics.IpClientRaInfoMetrics;
141 import com.android.networkstack.metrics.NetworkQuirkMetrics;
142 import com.android.networkstack.util.NetworkStackUtils;
143 
144 import java.io.FileDescriptor;
145 import java.io.IOException;
146 import java.net.Inet4Address;
147 import java.net.Inet6Address;
148 import java.net.InetAddress;
149 import java.net.SocketAddress;
150 import java.net.SocketException;
151 import java.net.UnknownHostException;
152 import java.nio.BufferUnderflowException;
153 import java.nio.ByteBuffer;
154 import java.nio.ByteOrder;
155 import java.util.ArrayList;
156 import java.util.Arrays;
157 import java.util.List;
158 import java.util.Map;
159 import java.util.Set;
160 
161 /**
162  * For networks that support packet filtering via APF programs, {@code ApfFilter}
163  * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
164  * filter out redundant duplicate ones.
165  * <p>
166  * Threading model:
167  * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
168  * know what RAs to filter for, thus generating APF programs is dependent on mRas.
169  * mRas can be accessed by multiple threads:
170  * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
171  * - callers of:
172  *    - setMulticastFilter(), which can cause an APF program to be generated.
173  *    - dump(), which dumps mRas among other things.
174  *    - shutdown(), which clears mRas.
175  * So access to mRas is synchronized.
176  *
177  * @hide
178  */
179 public class ApfFilter implements AndroidPacketFilter {
180 
181     // Helper class for specifying functional filter parameters.
182     public static class ApfConfiguration {
183         public ApfCapabilities apfCapabilities;
184         public int installableProgramSizeClamp = Integer.MAX_VALUE;
185         public boolean multicastFilter;
186         public boolean ieee802_3Filter;
187         public int[] ethTypeBlackList;
188         public int minRdnssLifetimeSec;
189         public int acceptRaMinLft;
190         public boolean shouldHandleLightDoze;
191         public long minMetricsSessionDurationMs;
192         public boolean hasClatInterface;
193         public boolean shouldHandleArpOffload;
194     }
195 
196     /** A wrapper class of {@link SystemClock} to be mocked in unit tests. */
197     public static class Clock {
198         /**
199          * @see SystemClock#elapsedRealtime
200          */
elapsedRealtime()201         public long elapsedRealtime() {
202             return SystemClock.elapsedRealtime();
203         }
204     }
205 
206     // Thread to listen for RAs.
207     @VisibleForTesting
208     public class ReceiveThread extends Thread {
209         private final byte[] mPacket = new byte[1514];
210         private final FileDescriptor mSocket;
211 
212         private volatile boolean mStopped;
213 
ReceiveThread(FileDescriptor socket)214         public ReceiveThread(FileDescriptor socket) {
215             mSocket = socket;
216         }
217 
halt()218         public void halt() {
219             mStopped = true;
220             // Interrupts the read() call the thread is blocked in.
221             SocketUtils.closeSocketQuietly(mSocket);
222         }
223 
224         @Override
run()225         public void run() {
226             log("begin monitoring");
227             while (!mStopped) {
228                 try {
229                     int length = Os.read(mSocket, mPacket, 0, mPacket.length);
230                     processRa(mPacket, length);
231                 } catch (IOException|ErrnoException e) {
232                     if (!mStopped) {
233                         Log.e(TAG, "Read error", e);
234                     }
235                 }
236             }
237         }
238     }
239 
240     private static final String TAG = "ApfFilter";
241     private static final boolean DBG = true;
242     private static final boolean VDBG = false;
243 
244     private final ApfCapabilities mApfCapabilities;
245     private final int mInstallableProgramSizeClamp;
246     private final IpClientCallbacksWrapper mIpClientCallback;
247     private final InterfaceParams mInterfaceParams;
248     private final TokenBucket mTokenBucket;
249 
250     @VisibleForTesting
251     @NonNull
252     public byte[] mHardwareAddress;
253     @VisibleForTesting
254     public ReceiveThread mReceiveThread;
255     @GuardedBy("this")
256     private long mUniqueCounter;
257     @GuardedBy("this")
258     private boolean mMulticastFilter;
259     @GuardedBy("this")
260     private boolean mInDozeMode;
261     private final boolean mDrop802_3Frames;
262     private final int[] mEthTypeBlackList;
263 
264     private final Clock mClock;
265     private final ApfCounterTracker mApfCounterTracker = new ApfCounterTracker();
266     @GuardedBy("this")
267     private final long mSessionStartMs;
268     @GuardedBy("this")
269     private int mNumParseErrorRas = 0;
270     @GuardedBy("this")
271     private int mNumZeroLifetimeRas = 0;
272     @GuardedBy("this")
273     private int mLowestRouterLifetimeSeconds = Integer.MAX_VALUE;
274     @GuardedBy("this")
275     private long mLowestPioValidLifetimeSeconds = Long.MAX_VALUE;
276     @GuardedBy("this")
277     private long mLowestRioRouteLifetimeSeconds = Long.MAX_VALUE;
278     @GuardedBy("this")
279     private long mLowestRdnssLifetimeSeconds = Long.MAX_VALUE;
280 
281     // Ignore non-zero RDNSS lifetimes below this value.
282     private final int mMinRdnssLifetimeSec;
283 
284     // Minimum session time for metrics, duration less than this time will not be logged.
285     private final long mMinMetricsSessionDurationMs;
286 
287     // Tracks the value of /proc/sys/ipv6/conf/$iface/accept_ra_min_lft which affects router, RIO,
288     // and PIO valid lifetimes.
289     private final int mAcceptRaMinLft;
290     private final boolean mShouldHandleLightDoze;
291     private final boolean mShouldHandleArpOffload;
292 
293     private final NetworkQuirkMetrics mNetworkQuirkMetrics;
294     private final IpClientRaInfoMetrics mIpClientRaInfoMetrics;
295     private final ApfSessionInfoMetrics mApfSessionInfoMetrics;
296 
isDeviceIdleModeChangedAction(Intent intent)297     private static boolean isDeviceIdleModeChangedAction(Intent intent) {
298         return ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction());
299     }
300 
isDeviceLightIdleModeChangedAction(Intent intent)301     private boolean isDeviceLightIdleModeChangedAction(Intent intent) {
302         // The ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED only exist since T. For lower platform version,
303         // the check should return false. The explicit SDK check is needed to make linter happy
304         // about accessing ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED in this function.
305         if (!SdkLevel.isAtLeastT()) {
306             return false;
307         }
308         if (!mShouldHandleLightDoze) {
309             return false;
310         }
311         return ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(intent.getAction());
312     }
313 
isDeviceLightIdleMode(@onNull PowerManager powerManager)314     private boolean isDeviceLightIdleMode(@NonNull PowerManager powerManager) {
315         // The powerManager.isDeviceLightIdleMode() only exist since T. For lower platform version,
316         // the check should return false. The explicit SDK check is needed to make linter happy
317         // about accessing powerManager.isDeviceLightIdleMode() in this function.
318         if (!SdkLevel.isAtLeastT()) {
319             return false;
320         }
321         if (!mShouldHandleLightDoze) {
322             return false;
323         }
324 
325         return powerManager.isDeviceLightIdleMode();
326     }
327 
328     // Detects doze mode state transitions.
329     private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
330         @Override
331         public void onReceive(Context context, Intent intent) {
332             final PowerManager powerManager = context.getSystemService(PowerManager.class);
333             if (isDeviceIdleModeChangedAction(intent)
334                     || isDeviceLightIdleModeChangedAction(intent)) {
335                 final boolean deviceIdle = powerManager.isDeviceIdleMode()
336                         || isDeviceLightIdleMode(powerManager);
337                 setDozeMode(deviceIdle);
338             }
339         }
340     };
341 
342     // Our IPv4 address, if we have just one, otherwise null.
343     @GuardedBy("this")
344     private byte[] mIPv4Address;
345     // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
346     @GuardedBy("this")
347     private int mIPv4PrefixLength;
348 
349     // Our IPv6 non-tentative addresses
350     @GuardedBy("this")
351     private Set<Inet6Address> mIPv6NonTentativeAddresses = new ArraySet<>();
352 
353     // Our tentative IPv6 addresses
354     @GuardedBy("this")
355     private Set<Inet6Address> mIPv6TentativeAddresses = new ArraySet<>();
356 
357     // Whether CLAT is enabled.
358     @GuardedBy("this")
359     private boolean mHasClat;
360 
361     // mIsRunning is reflects the state of the ApfFilter during integration tests. ApfFilter can be
362     // paused using "adb shell cmd apf <iface> <cmd>" commands. A paused ApfFilter will not install
363     // any new programs, but otherwise operates normally.
364     private volatile boolean mIsRunning = true;
365 
366     private final Dependencies mDependencies;
367 
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics)368     public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
369             IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics) {
370         this(context, config, ifParams, ipClientCallback, networkQuirkMetrics,
371                 new Dependencies(context), new Clock());
372     }
373 
374     @VisibleForTesting
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies)375     public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
376             IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics,
377             Dependencies dependencies) {
378         this(context, config, ifParams, ipClientCallback, networkQuirkMetrics, dependencies,
379                 new Clock());
380     }
381 
382     @VisibleForTesting
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies, Clock clock)383     public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
384             IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics,
385             Dependencies dependencies, Clock clock) {
386         mApfCapabilities = config.apfCapabilities;
387         mInstallableProgramSizeClamp = config.installableProgramSizeClamp;
388         mIpClientCallback = ipClientCallback;
389         mInterfaceParams = ifParams;
390         mMulticastFilter = config.multicastFilter;
391         mDrop802_3Frames = config.ieee802_3Filter;
392         mMinRdnssLifetimeSec = config.minRdnssLifetimeSec;
393         mAcceptRaMinLft = config.acceptRaMinLft;
394         mShouldHandleLightDoze = config.shouldHandleLightDoze;
395         mShouldHandleArpOffload = config.shouldHandleArpOffload;
396         mDependencies = dependencies;
397         mNetworkQuirkMetrics = networkQuirkMetrics;
398         mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics();
399         mApfSessionInfoMetrics = dependencies.getApfSessionInfoMetrics();
400         mClock = clock;
401         mSessionStartMs = mClock.elapsedRealtime();
402         mMinMetricsSessionDurationMs = config.minMetricsSessionDurationMs;
403         mHasClat = config.hasClatInterface;
404 
405         // Now fill the black list from the passed array
406         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
407 
408         // TokenBucket for rate limiting filter installation. APF filtering relies on the filter
409         // always being up-to-date and APF bytecode being in sync with userspace. The TokenBucket
410         // merely prevents illconfigured / abusive networks from impacting the system, so it does
411         // not need to be very restrictive.
412         // The TokenBucket starts with its full capacity of 20 tokens (= 20 filter updates). A new
413         // token is generated every 3 seconds limiting the filter update rate to at most once every
414         // 3 seconds.
415         mTokenBucket = new TokenBucket(3_000 /* deltaMs */, 20 /* capacity */, 20 /* tokens */);
416 
417         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
418         maybeStartFilter();
419 
420         // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
421         mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver, mShouldHandleLightDoze);
422 
423         mDependencies.onApfFilterCreated(this);
424         // mReceiveThread is created in maybeStartFilter() and halted in shutdown().
425         mDependencies.onThreadCreated(mReceiveThread);
426     }
427 
428     /**
429      * Dependencies class for testing.
430      */
431     @VisibleForTesting
432     public static class Dependencies {
433         private final Context mContext;
Dependencies(final Context context)434         public Dependencies(final Context context) {
435             mContext = context;
436         }
437 
438         /** Add receiver for detecting doze mode change */
addDeviceIdleReceiver(@onNull final BroadcastReceiver receiver, boolean shouldHandleLightDoze)439         public void addDeviceIdleReceiver(@NonNull final BroadcastReceiver receiver,
440                 boolean shouldHandleLightDoze) {
441             final IntentFilter intentFilter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED);
442             if (SdkLevel.isAtLeastT() && shouldHandleLightDoze) {
443                 intentFilter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
444             }
445             mContext.registerReceiver(receiver, intentFilter);
446         }
447 
448         /** Remove broadcast receiver. */
removeBroadcastReceiver(@onNull final BroadcastReceiver receiver)449         public void removeBroadcastReceiver(@NonNull final BroadcastReceiver receiver) {
450             mContext.unregisterReceiver(receiver);
451         }
452 
453         /**
454          * Get a ApfSessionInfoMetrics instance.
455          */
getApfSessionInfoMetrics()456         public ApfSessionInfoMetrics getApfSessionInfoMetrics() {
457             return new ApfSessionInfoMetrics();
458         }
459 
460         /**
461          * Get a IpClientRaInfoMetrics instance.
462          */
getIpClientRaInfoMetrics()463         public IpClientRaInfoMetrics getIpClientRaInfoMetrics() {
464             return new IpClientRaInfoMetrics();
465         }
466 
467         /**
468          * Callback to be called when an ApfFilter instance is created.
469          *
470          * This method is designed to be overridden in test classes to collect created ApfFilter
471          * instances.
472          */
onApfFilterCreated(@onNull AndroidPacketFilter apfFilter)473         public void onApfFilterCreated(@NonNull AndroidPacketFilter apfFilter) {
474         }
475 
476         /**
477          * Callback to be called when a ReceiveThread instance is created.
478          *
479          * This method is designed for overriding in test classes to collect created threads and
480          * waits for the termination.
481          */
onThreadCreated(@onNull Thread thread)482         public void onThreadCreated(@NonNull Thread thread) {
483         }
484 
485         /**
486          * Loads the existing IPv6 anycast addresses from the file `/proc/net/anycast6`.
487          */
getAnycast6Addresses(@onNull String ifname)488         public List<byte[]> getAnycast6Addresses(@NonNull String ifname) {
489             final List<Inet6Address> anycast6Addresses =
490                     ProcfsParsingUtils.getAnycast6Addresses(ifname);
491             final List<byte[]> addresses = new ArrayList<>();
492             for (Inet6Address addr : anycast6Addresses) {
493                 addresses.add(addr.getAddress());
494             }
495 
496             return addresses;
497         }
498 
499         /**
500          * Loads the existing Ethernet multicast addresses from the file
501          * `/proc/net/dev_mcast`.
502          */
getEtherMulticastAddresses(@onNull String ifname)503         public List<byte[]> getEtherMulticastAddresses(@NonNull String ifname) {
504             final List<MacAddress> etherAddresses =
505                     ProcfsParsingUtils.getEtherMulticastAddresses(ifname);
506             final List<byte[]> addresses = new ArrayList<>();
507             for (MacAddress addr : etherAddresses) {
508                 addresses.add(addr.toByteArray());
509             }
510 
511             return addresses;
512         }
513 
514         /**
515          * Loads the existing ND traffic class for the specific interface from the file
516          * /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass.
517          *
518          * If the file does not exist or the interface is not found,
519          * the function returns 0..255, 0 as default ND traffic class.
520          */
getNdTrafficClass(@onNull String ifname)521         public int getNdTrafficClass(@NonNull String ifname) {
522             return ProcfsParsingUtils.getNdTrafficClass(ifname);
523         }
524     }
525 
526     @Override
setDataSnapshot(byte[] data)527     public synchronized String setDataSnapshot(byte[] data) {
528         mDataSnapshot = data;
529         if (mIsRunning) {
530             mApfCounterTracker.updateCountersFromData(data);
531         }
532         return mApfCounterTracker.getCounters().toString();
533     }
534 
log(String s)535     private void log(String s) {
536         Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
537     }
538 
539     @GuardedBy("this")
getUniqueNumberLocked()540     private long getUniqueNumberLocked() {
541         return mUniqueCounter++;
542     }
543 
filterEthTypeBlackList(int[] ethTypeBlackList)544     private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
545         ArrayList<Integer> bl = new ArrayList<>();
546 
547         for (int p : ethTypeBlackList) {
548             // Check if the protocol is a valid ether type
549             if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
550                 continue;
551             }
552 
553             // Check if the protocol is not repeated in the passed array
554             if (bl.contains(p)) {
555                 continue;
556             }
557 
558             // Check if list reach its max size
559             if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
560                 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
561                         ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
562                 break;
563             }
564 
565             // Now add the protocol to the list
566             bl.add(p);
567         }
568 
569         return bl.stream().mapToInt(Integer::intValue).toArray();
570     }
571 
572     /**
573      * Attempt to start listening for RAs and, if RAs are received, generating and installing
574      * filters to ignore useless RAs.
575      */
576     @VisibleForTesting
maybeStartFilter()577     public void maybeStartFilter() {
578         FileDescriptor socket;
579         try {
580             mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
581             synchronized(this) {
582                 // Clear the APF memory to reset all counters upon connecting to the first AP
583                 // in an SSID. This is limited to APFv4 devices because this large write triggers
584                 // a crash on some older devices (b/78905546).
585                 if (mIsRunning && hasDataAccess(mApfCapabilities)) {
586                     byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
587                     if (!mIpClientCallback.installPacketFilter(zeroes)) {
588                         sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE);
589                     }
590                 }
591 
592                 // Install basic filters
593                 installNewProgramLocked();
594             }
595             socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0);
596             NetworkStackUtils.attachRaFilter(socket);
597             SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, mInterfaceParams.index);
598             Os.bind(socket, addr);
599         } catch(SocketException|ErrnoException e) {
600             Log.e(TAG, "Error starting filter", e);
601             return;
602         }
603         mReceiveThread = new ReceiveThread(socket);
604         mReceiveThread.start();
605     }
606 
607     // Returns seconds since device boot.
608     @VisibleForTesting
secondsSinceBoot()609     protected int secondsSinceBoot() {
610         return (int) (mClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS);
611     }
612 
613     public static class InvalidRaException extends Exception {
InvalidRaException(String m)614         public InvalidRaException(String m) {
615             super(m);
616         }
617     }
618 
619     /**
620      *  Class to keep track of a section in a packet.
621      */
622     private static class PacketSection {
623         public enum Type {
624             MATCH,     // A field that should be matched (e.g., the router IP address).
625             LIFETIME,  // A lifetime. Not matched, and counts toward minimum RA lifetime if >= min.
626         }
627 
628         /** The type of section. */
629         public final Type type;
630         /** Offset into the packet at which this section begins. */
631         public final int start;
632         /** Length of this section in bytes. */
633         public final int length;
634         /** If this is a lifetime, the lifetime value. */
635         public final long lifetime;
636         /** If this is a lifetime, the value below which the lifetime is ignored */
637         public final int min;
638 
PacketSection(int start, int length, Type type, long lifetime, int min)639         PacketSection(int start, int length, Type type, long lifetime, int min) {
640             this.start = start;
641 
642             if (type == Type.LIFETIME && length != 2 && length != 4) {
643                 throw new IllegalArgumentException("LIFETIME section length must be 2 or 4 bytes");
644             }
645             this.length = length;
646             this.type = type;
647 
648             if (type == Type.MATCH && (lifetime != 0 || min != 0)) {
649                 throw new IllegalArgumentException("lifetime, min must be 0 for MATCH sections");
650             }
651             this.lifetime = lifetime;
652 
653             // It has already been asserted that min is 0 for MATCH sections.
654             if (min < 0) {
655                 throw new IllegalArgumentException("min must be >= 0 for LIFETIME sections");
656             }
657             this.min = min;
658         }
659 
toString()660         public String toString() {
661             if (type == Type.LIFETIME) {
662                 return String.format("%s: (%d, %d) %d %d", type, start, length, lifetime, min);
663             } else {
664                 return String.format("%s: (%d, %d)", type, start, length);
665             }
666         }
667     }
668 
669     // A class to hold information about an RA.
670     @VisibleForTesting
671     public class Ra {
672         // From RFC4861:
673         private static final int ICMP6_RA_HEADER_LEN = 16;
674         private static final int ICMP6_RA_CHECKSUM_OFFSET =
675                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
676         private static final int ICMP6_RA_CHECKSUM_LEN = 2;
677         private static final int ICMP6_RA_OPTION_OFFSET =
678                 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
679         private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
680                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
681         private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
682         // Prefix information option.
683         private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
684         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
685         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
686         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
687 
688         // From RFC4861: source link-layer address
689         private static final int ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE = 1;
690         // From RFC4861: mtu size option
691         private static final int ICMP6_MTU_OPTION_TYPE = 5;
692         // From RFC6106: Recursive DNS Server option
693         private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
694         // From RFC6106: DNS Search List option
695         private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
696         // From RFC8910: Captive-Portal option
697         private static final int ICMP6_CAPTIVE_PORTAL_OPTION_TYPE = 37;
698         // From RFC8781: PREF64 option
699         private static final int ICMP6_PREF64_OPTION_TYPE = 38;
700 
701         // From RFC4191: Route Information option
702         private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
703         // Above three options all have the same format:
704         private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
705         private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
706 
707         // Note: mPacket's position() cannot be assumed to be reset.
708         private final ByteBuffer mPacket;
709 
710         // List of sections in the packet.
711         private final ArrayList<PacketSection> mPacketSections = new ArrayList<>();
712 
713         // Router lifetime in packet
714         private final int mRouterLifetime;
715         // Minimum valid lifetime of PIOs in packet, Long.MAX_VALUE means not seen.
716         private long mMinPioValidLifetime = Long.MAX_VALUE;
717         // Minimum route lifetime of RIOs in packet, Long.MAX_VALUE means not seen.
718         private long mMinRioRouteLifetime = Long.MAX_VALUE;
719         // Minimum lifetime of RDNSSs in packet, Long.MAX_VALUE means not seen.
720         private long mMinRdnssLifetime = Long.MAX_VALUE;
721         // The time in seconds in which some of the information contained in this RA expires.
722         private final int mExpirationTime;
723         // When the packet was last captured, in seconds since Unix Epoch
724         private final int mLastSeen;
725 
726         // For debugging only. Offsets into the packet where PIOs are.
727         private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
728 
729         // For debugging only. Offsets into the packet where RDNSS options are.
730         private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
731 
732         // For debugging only. Offsets into the packet where RIO options are.
733         private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>();
734 
735         // For debugging only. Returns the hex representation of the last matching packet.
getLastMatchingPacket()736         String getLastMatchingPacket() {
737             return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
738                     false /* lowercase */);
739         }
740 
741         // For debugging only. Returns the string representation of the IPv6 address starting at
742         // position pos in the packet.
IPv6AddresstoString(int pos)743         private String IPv6AddresstoString(int pos) {
744             try {
745                 byte[] array = mPacket.array();
746                 // Can't just call copyOfRange() and see if it throws, because if it reads past the
747                 // end it pads with zeros instead of throwing.
748                 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
749                     return "???";
750                 }
751                 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
752                 InetAddress address = InetAddress.getByAddress(addressBytes);
753                 return address.getHostAddress();
754             } catch (UnsupportedOperationException e) {
755                 // array() failed. Cannot happen, mPacket is array-backed and read-write.
756                 return "???";
757             } catch (ClassCastException|UnknownHostException e) {
758                 // Cannot happen.
759                 return "???";
760             }
761         }
762 
763         // Can't be static because it's in a non-static inner class.
764         // TODO: Make this static once RA is its own class.
prefixOptionToString(StringBuffer sb, int offset)765         private void prefixOptionToString(StringBuffer sb, int offset) {
766             String prefix = IPv6AddresstoString(offset + 16);
767             int length = getUint8(mPacket, offset + 2);
768             long valid = getUint32(mPacket, offset + 4);
769             long preferred = getUint32(mPacket, offset + 8);
770             sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
771         }
772 
rdnssOptionToString(StringBuffer sb, int offset)773         private void rdnssOptionToString(StringBuffer sb, int offset) {
774             int optLen = getUint8(mPacket, offset + 1) * 8;
775             if (optLen < 24) return;  // Malformed or empty.
776             long lifetime = getUint32(mPacket, offset + 4);
777             int numServers = (optLen - 8) / 16;
778             sb.append("DNS ").append(lifetime).append("s");
779             for (int server = 0; server < numServers; server++) {
780                 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
781             }
782             sb.append(" ");
783         }
784 
rioOptionToString(StringBuffer sb, int offset)785         private void rioOptionToString(StringBuffer sb, int offset) {
786             int optLen = getUint8(mPacket, offset + 1) * 8;
787             if (optLen < 8 || optLen > 24) return;  // Malformed or empty.
788             int prefixLen = getUint8(mPacket, offset + 2);
789             long lifetime = getUint32(mPacket, offset + 4);
790 
791             // This read is variable length because the prefix can be 0, 8 or 16 bytes long.
792             // We can't use any of the ByteBuffer#get methods here because they all start reading
793             // from the buffer's current position.
794             byte[] prefix = new byte[IPV6_ADDR_LEN];
795             System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8);
796             sb.append("RIO ").append(lifetime).append("s ");
797             try {
798                 InetAddress address = InetAddress.getByAddress(prefix);
799                 sb.append(address.getHostAddress());
800             } catch (UnknownHostException impossible) {
801                 sb.append("???");
802             }
803             sb.append("/").append(prefixLen).append(" ");
804         }
805 
toString()806         public String toString() {
807             try {
808                 StringBuffer sb = new StringBuffer();
809                 sb.append(String.format("RA %s -> %s %ds ",
810                         IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
811                         IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
812                         getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
813                 for (int i: mPrefixOptionOffsets) {
814                     prefixOptionToString(sb, i);
815                 }
816                 for (int i: mRdnssOptionOffsets) {
817                     rdnssOptionToString(sb, i);
818                 }
819                 for (int i: mRioOptionOffsets) {
820                     rioOptionToString(sb, i);
821                 }
822                 return sb.toString();
823             } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
824                 return "<Malformed RA>";
825             }
826         }
827 
828         /**
829          * Add a packet section that should be matched, starting from the current position.
830          * @param length the length of the section
831          */
addMatchSection(int length)832         private void addMatchSection(int length) {
833             // Don't generate JNEBS instruction for 0 bytes as they will fail the
834             // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is
835             // the number of bytes to compare) and immediately pass the packet.
836             // The code does not attempt to generate such matches, but add a safety
837             // check to prevent doing so in the presence of bugs or malformed or
838             // truncated packets.
839             if (length == 0) return;
840 
841             // we need to add a MATCH section 'from, length, MATCH, 0, 0'
842             int from = mPacket.position();
843 
844             // if possible try to increase the length of the previous match section
845             int lastIdx = mPacketSections.size() - 1;
846             if (lastIdx >= 0) {  // there had to be a previous section
847                 PacketSection prev = mPacketSections.get(lastIdx);
848                 if (prev.type == PacketSection.Type.MATCH) {  // of type match
849                     if (prev.start + prev.length == from) {  // ending where we start
850                         from -= prev.length;
851                         length += prev.length;
852                         mPacketSections.remove(lastIdx);
853                     }
854                 }
855             }
856 
857             mPacketSections.add(new PacketSection(from, length, PacketSection.Type.MATCH, 0, 0));
858             mPacket.position(from + length);
859         }
860 
861         /**
862          * Add a packet section that should be matched, starting from the current position.
863          * @param end the offset in the packet before which the section ends
864          */
addMatchUntil(int end)865         private void addMatchUntil(int end) {
866             addMatchSection(end - mPacket.position());
867         }
868 
869         /**
870          * Add a packet section that should be ignored, starting from the current position.
871          * @param length the length of the section in bytes
872          */
addIgnoreSection(int length)873         private void addIgnoreSection(int length) {
874             mPacket.position(mPacket.position() + length);
875         }
876 
877         /**
878          * Add a packet section that represents a lifetime, starting from the current position.
879          * @param length the length of the section in bytes
880          * @param lifetime the lifetime
881          * @param min the minimum acceptable lifetime
882          */
addLifetimeSection(int length, long lifetime, int min)883         private void addLifetimeSection(int length, long lifetime, int min) {
884             mPacketSections.add(
885                     new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME,
886                             lifetime, min));
887             mPacket.position(mPacket.position() + length);
888         }
889 
890         /**
891          * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option
892          * @param optionLength the length of the option in bytes
893          * @param min the minimum acceptable lifetime
894          */
add4ByteLifetimeOption(int optionLength, int min)895         private long add4ByteLifetimeOption(int optionLength, int min) {
896             addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET);
897             final long lifetime = getUint32(mPacket, mPacket.position());
898             addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, lifetime, min);
899             addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET
900                     - ICMP6_4_BYTE_LIFETIME_LEN);
901             return lifetime;
902         }
903 
904         /**
905          * Return the router lifetime of the RA
906          */
routerLifetime()907         public int routerLifetime() {
908             return mRouterLifetime;
909         }
910 
911         /**
912          * Return the minimum valid lifetime in PIOs
913          */
minPioValidLifetime()914         public long minPioValidLifetime() {
915             return mMinPioValidLifetime;
916         }
917 
918         /**
919          * Return the minimum route lifetime in RIOs
920          */
minRioRouteLifetime()921         public long minRioRouteLifetime() {
922             return mMinRioRouteLifetime;
923         }
924 
925         /**
926          * Return the minimum lifetime in RDNSSs
927          */
minRdnssLifetime()928         public long minRdnssLifetime() {
929             return mMinRdnssLifetime;
930         }
931 
932         // Note that this parses RA and may throw InvalidRaException (from
933         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
934         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
935         // specifications.
936         @VisibleForTesting
Ra(byte[] packet, int length)937         public Ra(byte[] packet, int length) throws InvalidRaException {
938             if (length < ICMP6_RA_OPTION_OFFSET) {
939                 throw new InvalidRaException("Not an ICMP6 router advertisement: too short");
940             }
941 
942             mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
943             mLastSeen = secondsSinceBoot();
944 
945             // Check packet in case a packet arrives before we attach RA filter
946             // to our packet socket. b/29586253
947             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
948                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
949                     getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
950                 throw new InvalidRaException("Not an ICMP6 router advertisement");
951             }
952 
953             // Ignore destination MAC address.
954             addIgnoreSection(6 /* Size of MAC address */);
955 
956             // Ignore the flow label and low 4 bits of traffic class.
957             addMatchUntil(IPV6_FLOW_LABEL_OFFSET);
958             addIgnoreSection(IPV6_FLOW_LABEL_LEN);
959 
960             // Ignore IPv6 destination address.
961             addMatchUntil(IPV6_DEST_ADDR_OFFSET);
962             addIgnoreSection(IPV6_ADDR_LEN);
963 
964             // Ignore checksum.
965             addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET);
966             addIgnoreSection(ICMP6_RA_CHECKSUM_LEN);
967 
968             // Parse router lifetime
969             addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET);
970             mRouterLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET);
971             addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, mRouterLifetime, mAcceptRaMinLft);
972             if (mRouterLifetime == 0) mNumZeroLifetimeRas++;
973 
974             // Add remaining fields (reachable time and retransmission timer) to match section.
975             addMatchUntil(ICMP6_RA_OPTION_OFFSET);
976 
977             while (mPacket.hasRemaining()) {
978                 final int position = mPacket.position();
979                 final int optionType = getUint8(mPacket, position);
980                 final int optionLength = getUint8(mPacket, position + 1) * 8;
981                 if (optionLength <= 0) {
982                     throw new InvalidRaException(String.format(
983                         "Invalid option length opt=%d len=%d", optionType, optionLength));
984                 }
985 
986                 long lifetime;
987                 switch (optionType) {
988                     case ICMP6_PREFIX_OPTION_TYPE:
989                         mPrefixOptionOffsets.add(position);
990 
991                         // Parse valid lifetime
992                         addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
993                         lifetime = getUint32(mPacket, mPacket.position());
994                         addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
995                                 lifetime, mAcceptRaMinLft);
996                         mMinPioValidLifetime = getMinForPositiveValue(
997                                 mMinPioValidLifetime, lifetime);
998                         if (lifetime == 0) mNumZeroLifetimeRas++;
999 
1000                         // Parse preferred lifetime
1001                         lifetime = getUint32(mPacket, mPacket.position());
1002                         // The PIO preferred lifetime is not affected by accept_ra_min_lft and
1003                         // therefore does not have a minimum.
1004                         addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN,
1005                                 lifetime, 0 /* min lifetime */);
1006 
1007                         addMatchSection(4);       // Reserved bytes
1008                         addMatchSection(IPV6_ADDR_LEN);  // The prefix itself
1009                         break;
1010                     // These three options have the same lifetime offset and size, and
1011                     // are processed with the same specialized add4ByteLifetimeOption:
1012                     case ICMP6_RDNSS_OPTION_TYPE:
1013                         mRdnssOptionOffsets.add(position);
1014                         lifetime = add4ByteLifetimeOption(optionLength, mMinRdnssLifetimeSec);
1015                         mMinRdnssLifetime = getMinForPositiveValue(mMinRdnssLifetime, lifetime);
1016                         if (lifetime == 0) mNumZeroLifetimeRas++;
1017                         break;
1018                     case ICMP6_ROUTE_INFO_OPTION_TYPE:
1019                         mRioOptionOffsets.add(position);
1020                         lifetime = add4ByteLifetimeOption(optionLength, mAcceptRaMinLft);
1021                         mMinRioRouteLifetime = getMinForPositiveValue(
1022                                 mMinRioRouteLifetime, lifetime);
1023                         if (lifetime == 0) mNumZeroLifetimeRas++;
1024                         break;
1025                     case ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE:
1026                     case ICMP6_MTU_OPTION_TYPE:
1027                     case ICMP6_PREF64_OPTION_TYPE:
1028                         addMatchSection(optionLength);
1029                         break;
1030                     case ICMP6_CAPTIVE_PORTAL_OPTION_TYPE: // unlikely to ever change.
1031                     case ICMP6_DNSSL_OPTION_TYPE: // currently unsupported in userspace.
1032                     default:
1033                         // RFC4861 section 4.2 dictates we ignore unknown options for forwards
1034                         // compatibility.
1035                         // However, make sure the option's type and length match.
1036                         addMatchSection(2); // option type & length
1037                         // optionLength is guaranteed to be >= 8.
1038                         addIgnoreSection(optionLength - 2);
1039                         break;
1040                 }
1041             }
1042             mExpirationTime = getExpirationTime();
1043         }
1044 
1045         public enum MatchType {
1046             NO_MATCH, // the RAs do not match
1047             MATCH_PASS, // the RAS match, and the APF program would pass.
1048             MATCH_DROP, // the RAs match, but the APF program would drop.
1049         }
1050 
1051         // Considering only the MATCH sections, does {@code packet} match this RA?
matches(Ra newRa)1052         MatchType matches(Ra newRa) {
1053             // Does their size match?
1054             if (newRa.mPacket.capacity() != mPacket.capacity()) return MatchType.NO_MATCH;
1055 
1056             // If the filter has expired, it cannot match the new RA.
1057             if (getRemainingFilterLft(secondsSinceBoot()) <= 0) return MatchType.NO_MATCH;
1058 
1059             // Check if all MATCH sections are byte-identical.
1060             final byte[] newPacket = newRa.mPacket.array();
1061             final byte[] oldPacket = mPacket.array();
1062             for (PacketSection section : mPacketSections) {
1063                 if (section.type != PacketSection.Type.MATCH) continue;
1064                 for (int i = section.start; i < (section.start + section.length); i++) {
1065                     if (newPacket[i] != oldPacket[i]) return MatchType.NO_MATCH;
1066                 }
1067             }
1068 
1069             // Apply APF lifetime matching to LIFETIME sections and decide whether a packet should
1070             // be processed (MATCH_PASS) or ignored (MATCH_DROP). This logic is needed to
1071             // consistently process / ignore packets no matter the current state of the APF program.
1072             // Note that userspace has no control (or knowledge) over when the APF program is
1073             // running.
1074             for (PacketSection section : mPacketSections) {
1075                 if (section.type != PacketSection.Type.LIFETIME) continue;
1076 
1077                 // the lifetime of the new RA.
1078                 long lft = 0;
1079                 switch (section.length) {
1080                     // section.length is guaranteed to be 2 or 4.
1081                     case 2: lft = getUint16(newRa.mPacket, section.start); break;
1082                     case 4: lft = getUint32(newRa.mPacket, section.start); break;
1083                 }
1084 
1085                 // WARNING: keep this in sync with Ra#generateFilterLocked()!
1086                 if (section.lifetime == 0) {
1087                     // Case 1) old lft == 0
1088                     if (section.min > 0) {
1089                         // a) in the presence of a min value.
1090                         // if lft >= min -> PASS
1091                         // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1092                         if (lft >= section.min) return MatchType.MATCH_PASS;
1093                     } else {
1094                         // b) if min is 0 / there is no min value.
1095                         // if lft > 0 -> PASS
1096                         // gen.addJumpIfR0GreaterThan(0, nextFilterLabel);
1097                         if (lft > 0) return MatchType.MATCH_PASS;
1098                     }
1099                 } else if (section.min == 0) {
1100                     // Case 2b) section is not affected by any minimum.
1101                     //
1102                     // if lft < (oldLft + 2) // 3 -> PASS
1103                     // if lft > oldLft            -> PASS
1104                     // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1105                     //        nextFilterLabel);
1106                     if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS;
1107                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1108                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1109                 } else if (section.lifetime < section.min) {
1110                     // Case 2a) 0 < old lft < min
1111                     //
1112                     // if lft == 0   -> PASS
1113                     // if lft >= min -> PASS
1114                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1115                     if (lft == 0) return MatchType.MATCH_PASS;
1116                     // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1117                     if (lft >= section.min) return MatchType.MATCH_PASS;
1118                 } else if (section.lifetime <= 3 * (long) section.min) {
1119                     // Case 3a) min <= old lft <= 3 * min
1120                     // Note that:
1121                     // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min"
1122                     //
1123                     // Essentially, in this range there is no "renumbering support", as the
1124                     // renumbering constant of 1/3 * old lft is smaller than the minimum
1125                     // lifetime accepted by the kernel / userspace.
1126                     //
1127                     // if lft == 0     -> PASS
1128                     // if lft > oldLft -> PASS
1129                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1130                     if (lft == 0) return MatchType.MATCH_PASS;
1131                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1132                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1133                 } else {
1134                     // Case 4a) otherwise
1135                     //
1136                     // if lft == 0                  -> PASS
1137                     // if lft < min                 -> CONTINUE
1138                     // if lft < (oldLft + 2) // 3   -> PASS
1139                     // if lft > oldLft              -> PASS
1140                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1141                     if (lft == 0) return MatchType.MATCH_PASS;
1142                     // gen.addJumpIfR0LessThan(section.min, continueLabel);
1143                     if (lft < section.min) continue;
1144                     // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1145                     //         nextFilterLabel);
1146                     if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS;
1147                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1148                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1149                 }
1150             }
1151 
1152             return MatchType.MATCH_DROP;
1153         }
1154 
1155         // Get the number of seconds in which some of the information contained in this RA expires.
getExpirationTime()1156         private int getExpirationTime() {
1157             // While technically most lifetimes in the RA are u32s, as far as the RA filter is
1158             // concerned, INT_MAX is still a *much* longer lifetime than any filter would ever
1159             // reasonably be active for.
1160             // Clamp expirationTime at INT_MAX.
1161             int expirationTime = Integer.MAX_VALUE;
1162             for (PacketSection section : mPacketSections) {
1163                 if (section.type != PacketSection.Type.LIFETIME) {
1164                     continue;
1165                 }
1166                 // Ignore lifetimes below section.min and always ignore 0 lifetimes.
1167                 if (section.lifetime < Math.max(section.min, 1)) {
1168                     continue;
1169                 }
1170 
1171                 expirationTime = (int) Math.min(expirationTime, section.lifetime);
1172             }
1173             return expirationTime;
1174         }
1175 
1176         // Filter for a fraction of the expiration time and adjust for the age of the RA.
getRemainingFilterLft(int currentTimeSeconds)1177         int getRemainingFilterLft(int currentTimeSeconds) {
1178             int filterLifetime = ((mExpirationTime / FRACTION_OF_LIFETIME_TO_FILTER)
1179                     - (currentTimeSeconds - mLastSeen));
1180             filterLifetime = Math.max(0, filterLifetime);
1181             // Clamp filterLifetime to <= 65535, so it fits in 2 bytes.
1182             return Math.min(65535, filterLifetime);
1183         }
1184 
1185         // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
1186         // Jump to the next filter if packet doesn't match this RA.
1187         @GuardedBy("ApfFilter.this")
generateFilterLocked(ApfV4GeneratorBase<?> gen, int timeSeconds)1188         void generateFilterLocked(ApfV4GeneratorBase<?> gen, int timeSeconds)
1189                 throws IllegalInstructionException {
1190             String nextFilterLabel = gen.getUniqueLabel();
1191             // Skip if packet is not the right size
1192             gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE);
1193             gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
1194             // Skip filter if expired
1195             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
1196             gen.addJumpIfR0GreaterThan(getRemainingFilterLft(timeSeconds), nextFilterLabel);
1197             for (PacketSection section : mPacketSections) {
1198                 // Generate code to match the packet bytes.
1199                 if (section.type == PacketSection.Type.MATCH) {
1200                     gen.addLoadImmediate(R0, section.start);
1201                     gen.addJumpIfBytesAtR0NotEqual(
1202                             Arrays.copyOfRange(mPacket.array(), section.start,
1203                                     section.start + section.length),
1204                             nextFilterLabel);
1205                 } else {
1206                     switch (section.length) {
1207                         // length asserted to be either 2 or 4 on PacketSection construction
1208                         case 2: gen.addLoad16(R0, section.start); break;
1209                         case 4: gen.addLoad32(R0, section.start); break;
1210                     }
1211 
1212                     // WARNING: keep this in sync with matches()!
1213                     // For more information on lifetime comparisons in the APF bytecode, see
1214                     // go/apf-ra-filter.
1215                     if (section.lifetime == 0) {
1216                         // Case 1) old lft == 0
1217                         if (section.min > 0) {
1218                             // a) in the presence of a min value.
1219                             // if lft >= min -> PASS
1220                             gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1221                         } else {
1222                             // b) if min is 0 / there is no min value.
1223                             // if lft > 0 -> PASS
1224                             gen.addJumpIfR0GreaterThan(0, nextFilterLabel);
1225                         }
1226                     } else if (section.min == 0) {
1227                         // Case 2b) section is not affected by any minimum.
1228                         //
1229                         // if lft < (oldLft + 2) // 3 -> PASS
1230                         // if lft > oldLft            -> PASS
1231                         gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1232                                 nextFilterLabel);
1233                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1234                     } else if (section.lifetime < section.min) {
1235                         // Case 2a) 0 < old lft < min
1236                         //
1237                         // if lft == 0   -> PASS
1238                         // if lft >= min -> PASS
1239                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1240                         gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1241                     } else if (section.lifetime <= 3 * (long) section.min) {
1242                         // Case 3a) min <= old lft <= 3 * min
1243                         // Note that:
1244                         // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min"
1245                         //
1246                         // Essentially, in this range there is no "renumbering support", as the
1247                         // renumbering constant of 1/3 * old lft is smaller than the minimum
1248                         // lifetime accepted by the kernel / userspace.
1249                         //
1250                         // if lft == 0     -> PASS
1251                         // if lft > oldLft -> PASS
1252                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1253                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1254                     } else {
1255                         final String continueLabel = gen.getUniqueLabel();
1256                         // Case 4a) otherwise
1257                         //
1258                         // if lft == 0                  -> PASS
1259                         // if lft < min                 -> CONTINUE
1260                         // if lft < (oldLft + 2) // 3   -> PASS
1261                         // if lft > oldLft              -> PASS
1262                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1263                         gen.addJumpIfR0LessThan(section.min, continueLabel);
1264                         gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1265                                 nextFilterLabel);
1266                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1267 
1268                         // CONTINUE
1269                         gen.defineLabel(continueLabel);
1270                     }
1271                 }
1272             }
1273             gen.addCountAndDrop(Counter.DROPPED_RA);
1274             gen.defineLabel(nextFilterLabel);
1275         }
1276     }
1277 
1278     // TODO: Refactor these subclasses to avoid so much repetition.
1279     private abstract static class KeepalivePacket {
1280         // Note that the offset starts from IP header.
1281         // These must be added ether header length when generating program.
1282         static final int IP_HEADER_OFFSET = 0;
1283         static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
1284 
1285         // Append a filter for this keepalive ack to {@code gen}.
1286         // Jump to drop if it matches the keepalive ack.
1287         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfV4GeneratorBase<?> gen)1288         abstract void generateFilterLocked(ApfV4GeneratorBase<?> gen)
1289                 throws IllegalInstructionException;
1290     }
1291 
1292     // A class to hold NAT-T keepalive ack information.
1293     private class NattKeepaliveResponse extends KeepalivePacket {
1294         static final int UDP_HEADER_LEN = 8;
1295 
1296         protected class NattKeepaliveResponseData {
1297             public final byte[] srcAddress;
1298             public final int srcPort;
1299             public final byte[] dstAddress;
1300             public final int dstPort;
1301 
NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1302             NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1303                 srcAddress = sentKeepalivePacket.dstAddress;
1304                 srcPort = sentKeepalivePacket.dstPort;
1305                 dstAddress = sentKeepalivePacket.srcAddress;
1306                 dstPort = sentKeepalivePacket.srcPort;
1307             }
1308         }
1309 
1310         protected final NattKeepaliveResponseData mPacket;
1311         protected final byte[] mSrcDstAddr;
1312         protected final byte[] mPortFingerprint;
1313         // NAT-T keepalive packet
1314         protected final byte[] mPayload = {(byte) 0xff};
1315 
NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1316         NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1317             mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
1318             mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress);
1319             mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
1320         }
1321 
generatePortFingerprint(int srcPort, int dstPort)1322         byte[] generatePortFingerprint(int srcPort, int dstPort) {
1323             final ByteBuffer fp = ByteBuffer.allocate(4);
1324             fp.order(ByteOrder.BIG_ENDIAN);
1325             fp.putShort((short) srcPort);
1326             fp.putShort((short) dstPort);
1327             return fp.array();
1328         }
1329 
1330         @Override
1331         @GuardedBy("ApfFilter.this")
generateFilterLocked(ApfV4GeneratorBase<?> gen)1332         void generateFilterLocked(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException {
1333             final String nextFilterLabel = gen.getUniqueLabel();
1334 
1335             gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1336             gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel);
1337 
1338             // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
1339             // Check payload length is 1
1340             gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
1341             gen.addAdd(UDP_HEADER_LEN);
1342             gen.addSwap();
1343             gen.addLoad16(R0, IPV4_TOTAL_LENGTH_OFFSET);
1344             gen.addNeg(R1);
1345             gen.addAddR1ToR0();
1346             gen.addJumpIfR0NotEquals(1, nextFilterLabel);
1347 
1348             // Check that the ports match
1349             gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
1350             gen.addAdd(ETH_HEADER_LEN);
1351             gen.addJumpIfBytesAtR0NotEqual(mPortFingerprint, nextFilterLabel);
1352 
1353             // Payload offset = R0 + UDP header length
1354             gen.addAdd(UDP_HEADER_LEN);
1355             gen.addJumpIfBytesAtR0NotEqual(mPayload, nextFilterLabel);
1356 
1357             gen.addCountAndDrop(Counter.DROPPED_IPV4_NATT_KEEPALIVE);
1358             gen.defineLabel(nextFilterLabel);
1359         }
1360 
toString()1361         public String toString() {
1362             try {
1363                 return String.format("%s -> %s",
1364                         ConnectivityUtils.addressAndPortToString(
1365                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1366                         ConnectivityUtils.addressAndPortToString(
1367                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
1368             } catch (UnknownHostException e) {
1369                 return "Unknown host";
1370             }
1371         }
1372     }
1373 
1374     // A class to hold TCP keepalive ack information.
1375     private abstract static class TcpKeepaliveAck extends KeepalivePacket {
1376         protected static class TcpKeepaliveAckData {
1377             public final byte[] srcAddress;
1378             public final int srcPort;
1379             public final byte[] dstAddress;
1380             public final int dstPort;
1381             public final int seq;
1382             public final int ack;
1383 
1384             // Create the characteristics of the ack packet from the sent keepalive packet.
TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1385             TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1386                 srcAddress = sentKeepalivePacket.dstAddress;
1387                 srcPort = sentKeepalivePacket.dstPort;
1388                 dstAddress = sentKeepalivePacket.srcAddress;
1389                 dstPort = sentKeepalivePacket.srcPort;
1390                 seq = sentKeepalivePacket.ack;
1391                 ack = sentKeepalivePacket.seq + 1;
1392             }
1393         }
1394 
1395         protected final TcpKeepaliveAckData mPacket;
1396         protected final byte[] mSrcDstAddr;
1397         protected final byte[] mPortSeqAckFingerprint;
1398 
TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1399         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
1400             mPacket = packet;
1401             mSrcDstAddr = srcDstAddr;
1402             mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
1403                     mPacket.dstPort, mPacket.seq, mPacket.ack);
1404         }
1405 
generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1406         static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
1407             final ByteBuffer fp = ByteBuffer.allocate(12);
1408             fp.order(ByteOrder.BIG_ENDIAN);
1409             fp.putShort((short) srcPort);
1410             fp.putShort((short) dstPort);
1411             fp.putInt(seq);
1412             fp.putInt(ack);
1413             return fp.array();
1414         }
1415 
toString()1416         public String toString() {
1417             try {
1418                 return String.format("%s -> %s , seq=%d, ack=%d",
1419                         ConnectivityUtils.addressAndPortToString(
1420                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1421                         ConnectivityUtils.addressAndPortToString(
1422                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
1423                         Integer.toUnsignedLong(mPacket.seq),
1424                         Integer.toUnsignedLong(mPacket.ack));
1425             } catch (UnknownHostException e) {
1426                 return "Unknown host";
1427             }
1428         }
1429 
1430         // Append a filter for this keepalive ack to {@code gen}.
1431         // Jump to drop if it matches the keepalive ack.
1432         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfV4GeneratorBase<?> gen)1433         abstract void generateFilterLocked(ApfV4GeneratorBase<?> gen)
1434                 throws IllegalInstructionException;
1435     }
1436 
1437     private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
1438 
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1439         TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1440             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1441         }
TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1442         TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
1443             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1444         }
1445 
1446         @Override
1447         @GuardedBy("ApfFilter.this")
generateFilterLocked(ApfV4GeneratorBase<?> gen)1448         void generateFilterLocked(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException {
1449             final String nextFilterLabel = gen.getUniqueLabel();
1450 
1451             gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1452             gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel);
1453 
1454             // Skip to the next filter if it's not zero-sized :
1455             // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
1456             // Load the IP header size into R1
1457             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1458             // Load the TCP header size into R0 (it's indexed by R1)
1459             gen.addLoad8Indexed(R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
1460             // Size offset is in the top nibble, but it must be multiplied by 4, and the two
1461             // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
1462             gen.addRightShift(2);
1463             // R0 += R1 -> R0 contains TCP + IP headers length
1464             gen.addAddR1ToR0();
1465             // Load IPv4 total length
1466             gen.addLoad16(R1, IPV4_TOTAL_LENGTH_OFFSET);
1467             gen.addNeg(R0);
1468             gen.addAddR1ToR0();
1469             gen.addJumpIfR0NotEquals(0, nextFilterLabel);
1470             // Add IPv4 header length
1471             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1472             gen.addLoadImmediate(R0, ETH_HEADER_LEN);
1473             gen.addAddR1ToR0();
1474             gen.addJumpIfBytesAtR0NotEqual(mPortSeqAckFingerprint, nextFilterLabel);
1475 
1476             gen.addCountAndDrop(Counter.DROPPED_IPV4_KEEPALIVE_ACK);
1477             gen.defineLabel(nextFilterLabel);
1478         }
1479     }
1480 
1481     private static class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1482         TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1483             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1484         }
TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1485         TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
1486             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1487         }
1488 
1489         @Override
generateFilterLocked(ApfV4GeneratorBase<?> gen)1490         void generateFilterLocked(ApfV4GeneratorBase<?> gen) {
1491             throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
1492         }
1493     }
1494 
1495     // Maximum number of RAs to filter for.
1496     private static final int MAX_RAS = 10;
1497 
1498     @GuardedBy("this")
1499     private final ArrayList<Ra> mRas = new ArrayList<>();
1500     @GuardedBy("this")
1501     private final SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
1502     @GuardedBy("this")
1503     // TODO: change the mMdnsAllowList to proper type for APFv6 based mDNS offload
1504     private final List<String[]> mMdnsAllowList = new ArrayList<>();
1505 
1506     // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
1507     // see a refresh.  Using half the lifetime might be a good idea except for the fact that
1508     // packets may be dropped, so let's use 6.
1509     private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
1510 
1511     // When did we last install a filter program? In seconds since Unix Epoch.
1512     @GuardedBy("this")
1513     private int mLastTimeInstalledProgram;
1514     // How long should the last installed filter program live for? In seconds.
1515     @GuardedBy("this")
1516     private int mLastInstalledProgramMinLifetime;
1517 
1518     // For debugging only. The last program installed.
1519     @GuardedBy("this")
1520     private byte[] mLastInstalledProgram;
1521 
1522     /**
1523      * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
1524      * <p>
1525      * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
1526      * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
1527      * the opcodes to access the data buffer (LDDW and STDW).
1528      */
1529     @GuardedBy("this") @Nullable
1530     private byte[] mDataSnapshot;
1531 
1532     // How many times the program was updated since we started.
1533     @GuardedBy("this")
1534     private int mNumProgramUpdates = 0;
1535     // The maximum program size that updated since we started.
1536     @GuardedBy("this")
1537     private int mMaxProgramSize = 0;
1538     // The maximum number of distinct RAs
1539     @GuardedBy("this")
1540     private int mMaxDistinctRas = 0;
1541 
tryToConvertToApfV6Generator(ApfV4GeneratorBase<?> gen)1542     private ApfV6Generator tryToConvertToApfV6Generator(ApfV4GeneratorBase<?> gen) {
1543         if (gen instanceof ApfV6Generator) {
1544             return (ApfV6Generator) gen;
1545         }
1546         return null;
1547     }
1548 
1549     /**
1550      * Generate filter code to process ARP packets. Execution of this code ends in either the
1551      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1552      * Preconditions:
1553      *  - Packet being filtered is ARP
1554      */
1555     @GuardedBy("this")
generateArpFilterLocked(ApfV4GeneratorBase<?> gen)1556     private void generateArpFilterLocked(ApfV4GeneratorBase<?> gen)
1557             throws IllegalInstructionException {
1558         // Here's a basic summary of what the ARP filter program does:
1559         //
1560         // if clat is enabled (and we're thus IPv6-only)
1561         //   drop
1562         // if not ARP IPv4
1563         //   drop
1564         // if unknown ARP opcode (ie. not reply or request)
1565         //   drop
1566         //
1567         // if ARP reply:
1568         //   if source ip is 0.0.0.0
1569         //     drop
1570         //   if unicast (or multicast)
1571         //     pass
1572         //   if interface has no IPv4 address
1573         //     if target ip is 0.0.0.0
1574         //       drop
1575         //   else
1576         //     if target ip is not the interface ip
1577         //       drop
1578         //   pass
1579         //
1580         // if ARP request:
1581         //   if interface has IPv4 address
1582         //     if target ip is not the interface ip
1583         //       drop
1584         //   pass
1585 
1586         // For IPv6 only network, drop all ARP packet.
1587         if (mHasClat) {
1588             gen.addCountAndDrop(Counter.DROPPED_ARP_V6_ONLY);
1589             return;
1590         }
1591 
1592         // Drop if not ARP IPv4.
1593         gen.addLoadImmediate(R0, ARP_HEADER_OFFSET);
1594         gen.addCountAndDropIfBytesAtR0NotEqual(ARP_IPV4_HEADER, Counter.DROPPED_ARP_NON_IPV4);
1595 
1596         final String checkArpRequest = gen.getUniqueLabel();
1597 
1598         gen.addLoad16(R0, ARP_OPCODE_OFFSET);
1599         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkArpRequest); // Skip to arp request check.
1600         // Drop if unknown ARP opcode.
1601         gen.addCountAndDropIfR0NotEquals(ARP_OPCODE_REPLY, Counter.DROPPED_ARP_UNKNOWN);
1602 
1603         /*----------  Handle ARP Replies. ----------*/
1604 
1605         // Drop if ARP reply source IP is 0.0.0.0
1606         gen.addLoad32(R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
1607         gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
1608 
1609         // Pass if non-broadcast reply.
1610         // This also accepts multicast arp, but we assume those don't exist.
1611         gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET);
1612         gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_ARP_UNICAST_REPLY);
1613 
1614         // It is a broadcast reply.
1615         if (mIPv4Address == null) {
1616             // When there is no IPv4 address, drop GARP replies (b/29404209).
1617             gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1618             gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, Counter.DROPPED_GARP_REPLY);
1619         } else {
1620             // When there is an IPv4 address, drop broadcast replies with a different target IPv4
1621             // address.
1622             gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1623             gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address),
1624                     Counter.DROPPED_ARP_OTHER_HOST);
1625         }
1626         gen.addCountAndPass(Counter.PASSED_ARP_BROADCAST_REPLY);
1627 
1628         /*----------  Handle ARP Requests. ----------*/
1629 
1630         gen.defineLabel(checkArpRequest);
1631         if (mIPv4Address != null) {
1632             // When there is an IPv4 address, drop unicast/broadcast requests with a different
1633             // target IPv4 address.
1634             gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1635             gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address),
1636                     Counter.DROPPED_ARP_OTHER_HOST);
1637 
1638             ApfV6Generator v6Gen = tryToConvertToApfV6Generator(gen);
1639             if (v6Gen != null && mShouldHandleArpOffload) {
1640                 // Ethernet requires that all packets be at least 60 bytes long
1641                 v6Gen.addAllocate(60)
1642                         .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN)
1643                         .addDataCopy(mHardwareAddress)
1644                         .addDataCopy(FIXED_ARP_REPLY_HEADER)
1645                         .addDataCopy(mHardwareAddress)
1646                         .addWrite32(mIPv4Address)
1647                         .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN)
1648                         .addPacketCopy(ARP_SOURCE_IP_ADDRESS_OFFSET, IPV4_ADDR_LEN)
1649                         .addLoadFromMemory(R0, MemorySlot.TX_BUFFER_OUTPUT_POINTER)
1650                         .addAdd(18)
1651                         .addStoreToMemory(MemorySlot.TX_BUFFER_OUTPUT_POINTER, R0)
1652                         .addTransmitWithoutChecksum()
1653                         .addCountAndDrop(Counter.DROPPED_ARP_REQUEST_REPLIED);
1654             }
1655         }
1656         // If we're not clat, and we don't have an ipv4 address, allow all ARP request to avoid
1657         // racing against DHCP.
1658         gen.addCountAndPass(Counter.PASSED_ARP_REQUEST);
1659     }
1660 
1661     /**
1662      * Generate filter code to process IPv4 packets. Execution of this code ends in either the
1663      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1664      * Preconditions:
1665      *  - Packet being filtered is IPv4
1666      */
1667     @GuardedBy("this")
generateIPv4FilterLocked(ApfV4GeneratorBase<?> gen)1668     private void generateIPv4FilterLocked(ApfV4GeneratorBase<?> gen)
1669             throws IllegalInstructionException {
1670         // Here's a basic summary of what the IPv4 filter program does:
1671         //
1672         // if the network is IPv6 only network:
1673         //   if the packet is fragmented:
1674         //     drop
1675         //   if the packet is a dhcp packet comes from server:
1676         //     pass
1677         //   else
1678         //     drop
1679         // if filtering multicast (i.e. multicast lock not held):
1680         //   if it's DHCP destined to our MAC:
1681         //     pass
1682         //   if it's L2 broadcast:
1683         //     drop
1684         //   if it's IPv4 multicast:
1685         //     drop
1686         //   if it's IPv4 broadcast:
1687         //     drop
1688         // if keepalive ack
1689         //   drop
1690         // pass
1691 
1692         if (mHasClat) {
1693             // Check 1) it's not a fragment. 2) it's UDP.
1694             // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol
1695             gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET);
1696             gen.addAnd(0x3FFF00FF);
1697             gen.addCountAndDropIfR0NotEquals(IPPROTO_UDP, Counter.DROPPED_IPV4_NON_DHCP4);
1698             // Check it's addressed to DHCP client port.
1699             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1700             gen.addLoad32Indexed(R0, TCP_UDP_SOURCE_PORT_OFFSET);
1701             gen.addCountAndDropIfR0NotEquals(DHCP_SERVER_PORT << 16 | DHCP_CLIENT_PORT,
1702                     Counter.DROPPED_IPV4_NON_DHCP4);
1703             gen.addCountAndPass(Counter.PASSED_IPV4_FROM_DHCPV4_SERVER);
1704             return;
1705         }
1706 
1707         if (mMulticastFilter) {
1708             final String skipDhcpv4Filter = gen.getUniqueLabel();
1709 
1710             // Pass DHCP addressed to us.
1711             // Check 1) it's not a fragment. 2) it's UDP.
1712             // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol
1713             gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET);
1714             gen.addAnd(0x3FFF00FF);
1715             gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
1716             // Check it's addressed to DHCP client port.
1717             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1718             gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET);
1719             gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
1720             // Check it's DHCP to our MAC address.
1721             gen.addLoadImmediate(R0, DHCP_CLIENT_MAC_OFFSET);
1722             // NOTE: Relies on R1 containing IPv4 header offset.
1723             gen.addAddR1ToR0();
1724             gen.addJumpIfBytesAtR0NotEqual(mHardwareAddress, skipDhcpv4Filter);
1725             gen.addCountAndPass(Counter.PASSED_DHCP);
1726 
1727             // Drop all multicasts/broadcasts.
1728             gen.defineLabel(skipDhcpv4Filter);
1729 
1730             // If IPv4 destination address is in multicast range, drop.
1731             gen.addLoad8(R0, IPV4_DEST_ADDR_OFFSET);
1732             gen.addAnd(0xf0);
1733             gen.addCountAndDropIfR0Equals(0xe0, Counter.DROPPED_IPV4_MULTICAST);
1734 
1735             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
1736             gen.addLoad32(R0, IPV4_DEST_ADDR_OFFSET);
1737             gen.addCountAndDropIfR0Equals(IPV4_BROADCAST_ADDRESS,
1738                     Counter.DROPPED_IPV4_BROADCAST_ADDR);
1739             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
1740                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
1741                 gen.addCountAndDropIfR0Equals(broadcastAddr, Counter.DROPPED_IPV4_BROADCAST_NET);
1742             }
1743         }
1744 
1745         // If any TCP keepalive filter matches, drop
1746         generateV4KeepaliveFilters(gen);
1747 
1748         // If any NAT-T keepalive filter matches, drop
1749         generateV4NattKeepaliveFilters(gen);
1750 
1751         // If TCP unicast on port 7, drop
1752         generateV4TcpPort7FilterLocked(gen);
1753 
1754         if (mMulticastFilter) {
1755             // Otherwise, this is an IPv4 unicast, pass
1756             // If L2 broadcast packet, drop.
1757             // TODO: can we invert this condition to fall through to the common pass case below?
1758             gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET);
1759             gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_IPV4_UNICAST);
1760             gen.addCountAndDrop(Counter.DROPPED_IPV4_L2_BROADCAST);
1761         }
1762 
1763         // Otherwise, pass
1764         gen.addCountAndPass(Counter.PASSED_IPV4);
1765     }
1766 
1767     @GuardedBy("this")
generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, int offset, String label)1768     private void generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto,
1769             int offset, String label) throws IllegalInstructionException {
1770         final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets,
1771                 filterType::isInstance);
1772 
1773         // If no keepalive packets of this type
1774         if (!haveKeepaliveResponses) return;
1775 
1776         // If not the right proto, skip keepalive filters
1777         gen.addLoad8(R0, offset);
1778         gen.addJumpIfR0NotEquals(proto, label);
1779 
1780         // Drop Keepalive responses
1781         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1782             final KeepalivePacket response = mKeepalivePackets.valueAt(i);
1783             if (filterType.isInstance(response)) response.generateFilterLocked(gen);
1784         }
1785 
1786         gen.defineLabel(label);
1787     }
1788 
1789     @GuardedBy("this")
generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)1790     private void generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)
1791             throws IllegalInstructionException {
1792         generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
1793                 gen.getUniqueLabel());
1794     }
1795 
1796     @GuardedBy("this")
generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)1797     private void generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)
1798             throws IllegalInstructionException {
1799         generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
1800                 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, gen.getUniqueLabel());
1801     }
1802 
getSolicitedNodeMcastAddressSuffix( @onNull List<byte[]> ipv6Addresses)1803     private List<byte[]> getSolicitedNodeMcastAddressSuffix(
1804             @NonNull List<byte[]> ipv6Addresses) {
1805         final List<byte[]> suffixes = new ArrayList<>();
1806         for (byte[] addr: ipv6Addresses) {
1807             suffixes.add(Arrays.copyOfRange(addr, 13,  16));
1808         }
1809         return suffixes;
1810     }
1811 
1812     @GuardedBy("this")
getIpv6Addresses( boolean includeNonTentative, boolean includeTentative, boolean includeAnycast)1813     private List<byte[]> getIpv6Addresses(
1814             boolean includeNonTentative, boolean includeTentative, boolean includeAnycast) {
1815         final List<byte[]> addresses = new ArrayList<>();
1816         if (includeNonTentative) {
1817             for (Inet6Address addr : mIPv6NonTentativeAddresses) {
1818                 addresses.add(addr.getAddress());
1819             }
1820         }
1821 
1822         if (includeTentative) {
1823             for (Inet6Address addr : mIPv6TentativeAddresses) {
1824                 addresses.add(addr.getAddress());
1825             }
1826         }
1827 
1828         if (includeAnycast) {
1829             addresses.addAll(mDependencies.getAnycast6Addresses(mInterfaceParams.name));
1830         }
1831         return addresses;
1832     }
1833 
1834     @GuardedBy("this")
getKnownMacAddresses()1835     private List<byte[]> getKnownMacAddresses() {
1836         final List<byte[]> addresses = new ArrayList<>();
1837         addresses.addAll(mDependencies.getEtherMulticastAddresses(mInterfaceParams.name));
1838         addresses.add(mHardwareAddress);
1839         addresses.add(ETHER_BROADCAST);
1840         return addresses;
1841     }
1842 
1843     /**
1844      * Generate allocate and transmit code to send ICMPv6 non-DAD NA packets.
1845      */
1846     @GuardedBy("this")
generateNonDadNaTransmitLocked(ApfV6GeneratorBase<?> gen)1847     private void generateNonDadNaTransmitLocked(ApfV6GeneratorBase<?> gen)
1848             throws IllegalInstructionException {
1849         final int ipv6PayloadLen = ICMPV6_NA_HEADER_LEN + ICMPV6_ND_OPTION_TLLA_LEN;
1850         final int pktLen = ETH_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLen;
1851 
1852         gen.addAllocate(pktLen);
1853 
1854         // Ethernet Header
1855         gen.addPacketCopy(ICMP6_NS_OPTION_TYPE_OFFSET + 2, ETHER_ADDR_LEN)  // dst MAC address
1856                 .addDataCopy(mHardwareAddress)  // src MAC address
1857                 .addWriteU16(ETH_P_IPV6);  // IPv6 type
1858 
1859         int tclass = mDependencies.getNdTrafficClass(mInterfaceParams.name);
1860         int vtf = (0x60000000 | (tclass << 20));
1861         // IPv6 header
1862         gen.addWrite32(vtf)  // IPv6 Header: version, traffic class, flowlabel
1863                 // payload length (2 bytes) | next header: ICMPv6 (1 byte) | hop limit (1 byte)
1864                 .addWrite32((ipv6PayloadLen << 16) | ((IPPROTO_ICMPV6 << 8) | 255))
1865                 // target ip is guaranteed to be non-tentative as we already check before
1866                 // we call transmit, but the link local ip can potentially be tentative.
1867                 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN)  // src ip
1868                 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN);  // dst ip
1869 
1870         // ICMPv6 header and payload
1871         // ICMPv6 type: NA (1 byte) | code: 0 (1 byte) | checksum: set to payload size (2 bytes)
1872         gen.addWrite32((ICMPV6_NEIGHBOR_ADVERTISEMENT << 24) | ipv6PayloadLen)
1873                 // Always set Router flag to prevent host deleting routes point at the router
1874                 // Always set Override flag to update neighbor's cache
1875                 // Solicited flag set to 1 if non DAD, refer to RFC4861#7.2.4
1876                 .addWrite32(0xe0000000) // flags: R=1, S=1, O=1
1877                 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // target address
1878                 // lla option: type (1 byte) | lla option: length (1 byte)
1879                 .addWriteU16((ICMPV6_ND_OPTION_TLLA << 8) | 1)
1880                 .addDataCopy(mHardwareAddress);  // lla option: link layer address
1881 
1882         gen.addTransmitL4(
1883                 ETHER_HEADER_LEN,   // ip_ofs
1884                 ICMP6_CHECKSUM_OFFSET,  // csum_ofs
1885                 IPV6_SRC_ADDR_OFFSET,   // csum_start
1886                 IPPROTO_ICMPV6, // partial_sum
1887                 false   // udp
1888         );
1889     }
1890 
1891     @GuardedBy("this")
generateNsFilterLocked(ApfV6Generator v6Gen)1892     private void generateNsFilterLocked(ApfV6Generator v6Gen)
1893             throws IllegalInstructionException {
1894         final List<byte[]> allIPv6Addrs = getIpv6Addresses(
1895                 true /* includeNonTentative */,
1896                 true /* includeTentative */,
1897                 true /* includeAnycast */);
1898         if (allIPv6Addrs.isEmpty()) {
1899             // If there is no IPv6 link local address, allow all NS packets to avoid racing
1900             // against RS.
1901             v6Gen.addCountAndPass(PASSED_IPV6_NS_NO_ADDRESS);
1902             return;
1903         }
1904 
1905         // Warning: APF program may temporarily filter NS packets targeted for anycast addresses
1906         // used by processes other than clatd. This is because APF cannot reliably detect signal
1907         // on when IPV6_{JOIN,LEAVE}_ANYCAST is triggered.
1908         final List<byte[]> allMACs = getKnownMacAddresses();
1909         v6Gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET)
1910                 .addCountAndDropIfBytesAtR0EqualsNoneOf(allMACs, DROPPED_IPV6_NS_OTHER_HOST);
1911 
1912         // Dst IPv6 address check:
1913         final List<byte[]> allSuffixes = getSolicitedNodeMcastAddressSuffix(allIPv6Addrs);
1914         final String notIpV6SolicitedNodeMcast = v6Gen.getUniqueLabel();
1915         final String endOfIpV6DstCheck = v6Gen.getUniqueLabel();
1916         v6Gen.addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET)
1917                 .addJumpIfBytesAtR0NotEqual(IPV6_SOLICITED_NODES_PREFIX, notIpV6SolicitedNodeMcast)
1918                 .addAdd(13)
1919                 .addCountAndDropIfBytesAtR0EqualsNoneOf(allSuffixes, DROPPED_IPV6_NS_OTHER_HOST)
1920                 .addJump(endOfIpV6DstCheck)
1921                 .defineLabel(notIpV6SolicitedNodeMcast)
1922                 .addCountAndDropIfBytesAtR0EqualsNoneOf(allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST)
1923                 .defineLabel(endOfIpV6DstCheck);
1924 
1925         // Hop limit not 255, NS requires hop limit to be 255 -> drop
1926         v6Gen.addLoad8(R0, IPV6_HOP_LIMIT_OFFSET)
1927                 .addCountAndDropIfR0NotEquals(255, DROPPED_IPV6_NS_INVALID);
1928 
1929         // payload length < 24 (8 bytes ICMP6 header + 16 bytes target address) -> drop
1930         v6Gen.addLoad16(R0, IPV6_PAYLOAD_LEN_OFFSET)
1931                 .addCountAndDropIfR0LessThan(24, DROPPED_IPV6_NS_INVALID);
1932 
1933         // ICMPv6 code not 0 -> drop
1934         v6Gen.addLoad8(R0, ICMP6_CODE_OFFSET)
1935                 .addCountAndDropIfR0NotEquals(0, DROPPED_IPV6_NS_INVALID);
1936 
1937         // target address (ICMPv6 NS/NA payload) is not interface addresses -> drop
1938         v6Gen.addLoadImmediate(R0, ICMP6_NS_TARGET_IP_OFFSET)
1939                 .addCountAndDropIfBytesAtR0EqualsNoneOf(allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST);
1940 
1941         // Only offload the following cases:
1942         //   1) NS packet with no options.
1943         //   2) NS packet with only one option: nonce.
1944         //   3) NS packet with only one option: SLLA.
1945         // For packets containing more than one option,
1946         // pass the packet to the CPU for processing.
1947         // payload length > 32
1948         //   (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option) -> pass
1949         v6Gen.addLoad16(R0, IPV6_PAYLOAD_LEN_OFFSET)
1950                 .addCountAndPassIfR0GreaterThan(32, PASSED_IPV6_NS_MULTIPLE_OPTIONS);
1951 
1952         v6Gen.addCountAndPass(Counter.PASSED_IPV6_ICMP);
1953     }
1954 
1955     /**
1956      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
1957      * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
1958      * Preconditions:
1959      *  - Packet being filtered is IPv6
1960      */
1961     @GuardedBy("this")
generateIPv6FilterLocked(ApfV4GeneratorBase<?> gen)1962     private void generateIPv6FilterLocked(ApfV4GeneratorBase<?> gen)
1963             throws IllegalInstructionException {
1964         // Here's a basic summary of what the IPv6 filter program does:
1965         //
1966         // if there is a hop-by-hop option present (e.g. MLD query)
1967         //   pass
1968         // if we're dropping multicast
1969         //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
1970         //     if it's multicast:
1971         //       drop
1972         //     pass
1973         // (APFv6+ specific logic) if it's ICMPv6 NS:
1974         //   if there are no IPv6 addresses (including link local address) on the interface:
1975         //     pass
1976         //   if MAC dst is none of known {unicast, multicast, broadcast} MAC addresses
1977         //     drop
1978         //   if IPv6 dst prefix is "ff02::1:ff00:0/104" but is none of solicited-node multicast
1979         //   IPv6 addresses:
1980         //     drop
1981         //   else if IPv6 dst is none of interface unicast IPv6 addresses (incl. anycast):
1982         //     drop
1983         //   if hop limit is not 255 (NS requires hop limit to be 255):
1984         //     drop
1985         //   if payload len < 24 (8 bytes ICMP6 header + 16 bytes target address):
1986         //     drop
1987         //   if ICMPv6 code is not 0:
1988         //     drop
1989         //   if target IP is none of interface unicast IPv6 addresses (incl. anycast):
1990         //     drop
1991         //   if payload len > 32 (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option):
1992         //     pass
1993         // if it's ICMPv6 RS to any:
1994         //   drop
1995         // if it's ICMPv6 NA to anything in ff02::/120
1996         //   drop
1997         // if keepalive ack
1998         //   drop
1999 
2000         gen.addLoad8(R0, IPV6_NEXT_HEADER_OFFSET);
2001 
2002         // MLD packets set the router-alert hop-by-hop option.
2003         // TODO: be smarter about not blindly passing every packet with HBH options.
2004         gen.addCountAndPassIfR0Equals(IPPROTO_HOPOPTS, Counter.PASSED_MLD);
2005 
2006         // Drop multicast if the multicast filter is enabled.
2007         if (mMulticastFilter) {
2008             final String skipIPv6MulticastFilterLabel = gen.getUniqueLabel();
2009             final String dropAllIPv6MulticastsLabel = gen.getUniqueLabel();
2010 
2011             // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
2012             // While awake, let all ICMPv6 multicasts through.
2013             if (mInDozeMode) {
2014                 // Not ICMPv6? -> Proceed to multicast filtering
2015                 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
2016 
2017                 // ICMPv6 but not ECHO? -> Skip the multicast filter.
2018                 // (ICMPv6 ECHO requests will go through the multicast filter below).
2019                 gen.addLoad8(R0, ICMP6_TYPE_OFFSET);
2020                 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
2021             } else {
2022                 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
2023             }
2024 
2025             // Drop all other packets sent to ff00::/8 (multicast prefix).
2026             gen.defineLabel(dropAllIPv6MulticastsLabel);
2027             gen.addLoad8(R0, IPV6_DEST_ADDR_OFFSET);
2028             gen.addCountAndDropIfR0Equals(0xff, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
2029             // If any keepalive filter matches, drop
2030             generateV6KeepaliveFilters(gen);
2031             // Not multicast. Pass.
2032             gen.addCountAndPass(Counter.PASSED_IPV6_UNICAST_NON_ICMP);
2033             gen.defineLabel(skipIPv6MulticastFilterLabel);
2034         } else {
2035             generateV6KeepaliveFilters(gen);
2036             // If not ICMPv6, pass.
2037             gen.addCountAndPassIfR0NotEquals(IPPROTO_ICMPV6, Counter.PASSED_IPV6_NON_ICMP);
2038         }
2039 
2040         // If we got this far, the packet is ICMPv6.  Drop some specific types.
2041         // Not ICMPv6 NS -> skip.
2042         gen.addLoad8(R0, ICMP6_TYPE_OFFSET); // warning: also used further below.
2043         final ApfV6Generator v6Gen = tryToConvertToApfV6Generator(gen);
2044         if (v6Gen != null) {
2045             final String skipNsPacketFilter = v6Gen.getUniqueLabel();
2046             v6Gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_SOLICITATION, skipNsPacketFilter);
2047             generateNsFilterLocked(v6Gen);
2048             // End of NS filter. generateNsFilterLocked() method is terminal, so NS packet will be
2049             // either dropped or passed inside generateNsFilterLocked().
2050             v6Gen.defineLabel(skipNsPacketFilter);
2051         }
2052 
2053         // Add unsolicited multicast neighbor announcements filter
2054         String skipUnsolicitedMulticastNALabel = gen.getUniqueLabel();
2055         // Drop all router solicitations (b/32833400)
2056         gen.addCountAndDropIfR0Equals(ICMPV6_ROUTER_SOLICITATION,
2057                 Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
2058         // If not neighbor announcements, skip filter.
2059         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
2060         // Drop all multicast NA to ff02::/120.
2061         // This is a way to cover ff02::1 and ff02::2 with a single JNEBS.
2062         // TODO: Drop only if they don't contain the address of on-link neighbours.
2063         final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15);
2064         gen.addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET);
2065         gen.addJumpIfBytesAtR0NotEqual(unsolicitedNaDropPrefix, skipUnsolicitedMulticastNALabel);
2066 
2067         gen.addCountAndDrop(Counter.DROPPED_IPV6_MULTICAST_NA);
2068         gen.defineLabel(skipUnsolicitedMulticastNALabel);
2069     }
2070 
2071     /**
2072      * Generate filter code to process mDNS packets. Execution of this code ends in * DROP_LABEL
2073      * or PASS_LABEL if the packet is mDNS packets. Otherwise, skip this check.
2074      */
2075     @GuardedBy("this")
generateMdnsFilterLocked(ApfV4GeneratorBase<?> gen)2076     private void generateMdnsFilterLocked(ApfV4GeneratorBase<?> gen)
2077             throws IllegalInstructionException {
2078         final String skipMdnsv4Filter = gen.getUniqueLabel();
2079         final String skipMdnsFilter = gen.getUniqueLabel();
2080         final String checkMdnsUdpPort = gen.getUniqueLabel();
2081 
2082         // Only turn on the filter if multicast filter is on and the qname allowlist is non-empty.
2083         if (!mMulticastFilter || mMdnsAllowList.isEmpty()) {
2084             return;
2085         }
2086 
2087         // Here's a basic summary of what the mDNS filter program does:
2088         //
2089         // A packet is considered as a multicast mDNS packet if it matches all the following
2090         // conditions
2091         //   1. its destination MAC address matches 01:00:5E:00:00:FB or 33:33:00:00:00:FB, for
2092         //   v4 and v6 respectively.
2093         //   2. it is an IPv4/IPv6 packet
2094         //   3. it is a UDP packet with port 5353
2095 
2096         // Check it's L2 mDNS multicast address.
2097         gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET);
2098         gen.addJumpIfBytesAtR0NotEqual(ETH_MULTICAST_MDNS_V4_MAC_ADDRESS, skipMdnsv4Filter);
2099 
2100         // Checks it's IPv4.
2101         gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET);
2102         gen.addJumpIfR0NotEquals(ETH_P_IP, skipMdnsFilter);
2103 
2104         // Check it's not a fragment.
2105         gen.addLoad16(R0, IPV4_FRAGMENT_OFFSET_OFFSET);
2106         gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK,
2107                 skipMdnsFilter);
2108 
2109         // Checks it's UDP.
2110         gen.addLoad8(R0, IPV4_PROTOCOL_OFFSET);
2111         gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter);
2112 
2113         // Set R1 to IPv4 header.
2114         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
2115         gen.addJump(checkMdnsUdpPort);
2116 
2117         gen.defineLabel(skipMdnsv4Filter);
2118 
2119         // Checks it's L2 mDNS multicast address.
2120         // Relies on R0 containing the ethernet destination mac address offset.
2121         gen.addJumpIfBytesAtR0NotEqual(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS, skipMdnsFilter);
2122 
2123         // Checks it's IPv6.
2124         gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET);
2125         gen.addJumpIfR0NotEquals(ETH_P_IPV6, skipMdnsFilter);
2126 
2127         // Checks it's UDP.
2128         gen.addLoad8(R0, IPV6_NEXT_HEADER_OFFSET);
2129         gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter);
2130 
2131         // Set R1 to IPv6 header.
2132         gen.addLoadImmediate(R1, IPV6_HEADER_LEN);
2133 
2134         // Checks it's mDNS UDP port
2135         gen.defineLabel(checkMdnsUdpPort);
2136         gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET);
2137         gen.addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter);
2138 
2139         // TODO: implement APFv6 mDNS offload
2140 
2141         // end of mDNS filter
2142         gen.defineLabel(skipMdnsFilter);
2143     }
2144 
2145     /**
2146      * Generate filter code to drop IPv4 TCP packets on port 7.
2147      * <p>
2148      * On entry, we know it is IPv4 ethertype, but don't know anything else.
2149      * R0/R1 have nothing useful in them, and can be clobbered.
2150      */
2151     @GuardedBy("this")
generateV4TcpPort7FilterLocked(ApfV4GeneratorBase<?> gen)2152     private void generateV4TcpPort7FilterLocked(ApfV4GeneratorBase<?> gen)
2153             throws IllegalInstructionException {
2154         final String skipPort7V4Filter = gen.getUniqueLabel();
2155 
2156         // Check it's TCP.
2157         gen.addLoad8(R0, IPV4_PROTOCOL_OFFSET);
2158         gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipPort7V4Filter);
2159 
2160         // Check it's not a fragment or is the initial fragment.
2161         gen.addLoad16(R0, IPV4_FRAGMENT_OFFSET_OFFSET);
2162         gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipPort7V4Filter);
2163 
2164         // Check it's destination port 7.
2165         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
2166         gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET);
2167         gen.addJumpIfR0NotEquals(ECHO_PORT, skipPort7V4Filter);
2168 
2169         // Drop it.
2170         gen.addCountAndDrop(Counter.DROPPED_IPV4_TCP_PORT7_UNICAST);
2171 
2172         // Skip label.
2173         gen.defineLabel(skipPort7V4Filter);
2174     }
2175 
2176     @GuardedBy("this")
generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)2177     private void generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)
2178             throws IllegalInstructionException {
2179         generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
2180                 gen.getUniqueLabel());
2181     }
2182 
2183     /**
2184      * Begin generating an APF program to:
2185      * <ul>
2186      * <li>Drop/Pass 802.3 frames (based on policy)
2187      * <li>Drop packets with EtherType within the Black List
2188      * <li>Drop ARP requests not for us, if mIPv4Address is set,
2189      * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
2190      * <li>Drop IPv4 multicast packets, if mMulticastFilter,
2191      * <li>Pass all other IPv4 packets,
2192      * <li>Drop all broadcast non-IP non-ARP packets.
2193      * <li>Pass all non-ICMPv6 IPv6 packets,
2194      * <li>Pass all non-IPv4 and non-IPv6 packets,
2195      * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120.
2196      * <li>Drop IPv6 ICMPv6 RSs.
2197      * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
2198      * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
2199      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
2200      *     insertion of RA filters here, or if there aren't any, just passes the packets.
2201      * </ul>
2202      */
2203     @GuardedBy("this")
2204     @VisibleForTesting
emitPrologueLocked()2205     protected ApfV4GeneratorBase<?> emitPrologueLocked() throws IllegalInstructionException {
2206         // This is guaranteed to succeed because of the check in maybeCreate.
2207         ApfV4GeneratorBase<?> gen;
2208         if (SdkLevel.isAtLeastV()
2209                 && ApfV6Generator.supportsVersion(mApfCapabilities.apfVersionSupported)) {
2210             gen = new ApfV6Generator(mApfCapabilities.maximumApfProgramSize);
2211         } else {
2212             gen = new ApfV4Generator(mApfCapabilities.apfVersionSupported);
2213         }
2214 
2215         if (hasDataAccess(mApfCapabilities)) {
2216             if (gen instanceof ApfV4Generator) {
2217                 // Increment TOTAL_PACKETS.
2218                 // Only needed in APFv4.
2219                 // In APFv6, the interpreter will increase the counter on packet receive.
2220                 gen.addIncrementCounter(Counter.TOTAL_PACKETS);
2221             }
2222 
2223             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
2224             gen.addStoreCounter(Counter.FILTER_AGE_SECONDS, R0);
2225 
2226             // requires a new enough APFv5+ interpreter, otherwise will be 0
2227             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_16384THS);
2228             gen.addStoreCounter(Counter.FILTER_AGE_16384THS, R0);
2229 
2230             // requires a new enough APFv5+ interpreter, otherwise will be 0
2231             gen.addLoadFromMemory(R0, MemorySlot.APF_VERSION);
2232             gen.addStoreCounter(Counter.APF_VERSION, R0);
2233 
2234             // store this program's sequential id, for later comparison
2235             gen.addLoadImmediate(R0, mNumProgramUpdates);
2236             gen.addStoreCounter(Counter.APF_PROGRAM_ID, R0);
2237         }
2238 
2239         // Here's a basic summary of what the initial program does:
2240         //
2241         // if it's a 802.3 Frame (ethtype < 0x0600):
2242         //    drop or pass based on configurations
2243         // if it has a ether-type that belongs to the black list
2244         //    drop
2245         // if it's ARP:
2246         //   insert ARP filter to drop or pass these appropriately
2247         // if it's IPv4:
2248         //   insert IPv4 filter to drop or pass these appropriately
2249         // if it's not IPv6:
2250         //   if it's broadcast:
2251         //     drop
2252         //   pass
2253         // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
2254 
2255         gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET);
2256         if (SdkLevel.isAtLeastV()) {
2257             // IPv4, ARP, IPv6, EAPOL, WAPI
2258             gen.addCountAndDropIfR0IsNoneOf(Set.of(0x0800L, 0x0806L, 0x86DDL, 0x888EL, 0x88B4L),
2259                     Counter.DROPPED_ETHERTYPE_NOT_ALLOWED);
2260         } else  {
2261             if (mDrop802_3Frames) {
2262                 // drop 802.3 frames (ethtype < 0x0600)
2263                 gen.addCountAndDropIfR0LessThan(ETH_TYPE_MIN, Counter.DROPPED_802_3_FRAME);
2264             }
2265             // Handle ether-type black list
2266             if (mEthTypeBlackList.length > 0) {
2267                 final Set<Long> deniedEtherTypes = new ArraySet<>();
2268                 for (int p : mEthTypeBlackList) {
2269                     deniedEtherTypes.add((long) p);
2270                 }
2271                 gen.addCountAndDropIfR0IsOneOf(deniedEtherTypes,
2272                         Counter.DROPPED_ETHERTYPE_NOT_ALLOWED);
2273             }
2274         }
2275 
2276         // Add ARP filters:
2277         String skipArpFiltersLabel = gen.getUniqueLabel();
2278         gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
2279         generateArpFilterLocked(gen);
2280         gen.defineLabel(skipArpFiltersLabel);
2281 
2282         // Add mDNS filter:
2283         generateMdnsFilterLocked(gen);
2284         gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET);
2285 
2286         // Add IPv4 filters:
2287         String skipIPv4FiltersLabel = gen.getUniqueLabel();
2288         gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
2289         generateIPv4FilterLocked(gen);
2290         gen.defineLabel(skipIPv4FiltersLabel);
2291 
2292         // Check for IPv6:
2293         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did
2294         // not execute the IPv4 filter, since this filter do not fall through, but either drop or
2295         // pass.
2296         String ipv6FilterLabel = gen.getUniqueLabel();
2297         gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
2298 
2299         // Drop non-IP non-ARP broadcasts, pass the rest
2300         gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET);
2301         gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_NON_IP_UNICAST);
2302         gen.addCountAndDrop(Counter.DROPPED_ETH_BROADCAST);
2303 
2304         // Add IPv6 filters:
2305         gen.defineLabel(ipv6FilterLabel);
2306         generateIPv6FilterLocked(gen);
2307         return gen;
2308     }
2309 
2310     /**
2311      * Append packet counting epilogue to the APF program.
2312      * <p>
2313      * Currently, the epilogue consists of two trampolines which count passed and dropped packets
2314      * before jumping to the actual PASS and DROP labels.
2315      */
2316     @GuardedBy("this")
emitEpilogue(ApfV4GeneratorBase<?> gen)2317     private void emitEpilogue(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException {
2318         // Execution will reach here if none of the filters match, which will pass the packet to
2319         // the application processor.
2320         gen.addCountAndPass(Counter.PASSED_IPV6_ICMP);
2321 
2322         // TODO: merge the addCountTrampoline() into generate() method
2323         gen.addCountTrampoline();
2324     }
2325 
2326     /**
2327      * Generate and install a new filter program.
2328      */
2329     @GuardedBy("this")
2330     @SuppressWarnings("GuardedBy") // errorprone false positive on ra#generateFilterLocked
2331     @VisibleForTesting
installNewProgramLocked()2332     public void installNewProgramLocked() {
2333         ArrayList<Ra> rasToFilter = new ArrayList<>();
2334         final byte[] program;
2335         int programMinLft = Integer.MAX_VALUE;
2336         int maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
2337         if (hasDataAccess(mApfCapabilities)) {
2338             // Reserve space for the counters.
2339             maximumApfProgramSize -= Counter.totalSize();
2340         }
2341 
2342         // Prevent generating (and thus installing) larger programs
2343         if (maximumApfProgramSize > mInstallableProgramSizeClamp) {
2344             maximumApfProgramSize = mInstallableProgramSizeClamp;
2345         }
2346 
2347         // Ensure the entire APF program uses the same time base.
2348         int timeSeconds = secondsSinceBoot();
2349         try {
2350             // Step 1: Determine how many RA filters we can fit in the program.
2351             ApfV4GeneratorBase<?> gen = emitPrologueLocked();
2352 
2353             // The epilogue normally goes after the RA filters, but add it early to include its
2354             // length when estimating the total.
2355             emitEpilogue(gen);
2356 
2357             // Can't fit the program even without any RA filters?
2358             if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
2359                 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
2360                 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
2361                 return;
2362             }
2363 
2364             for (Ra ra : mRas) {
2365                 // skip filter if it has expired.
2366                 if (ra.getRemainingFilterLft(timeSeconds) <= 0) continue;
2367                 ra.generateFilterLocked(gen, timeSeconds);
2368                 // Stop if we get too big.
2369                 if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
2370                     if (VDBG) Log.d(TAG, "Past maximum program size, skipping RAs");
2371                     sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
2372                     break;
2373                 }
2374 
2375                 rasToFilter.add(ra);
2376             }
2377 
2378             // Step 2: Actually generate the program
2379             gen = emitPrologueLocked();
2380             for (Ra ra : rasToFilter) {
2381                 ra.generateFilterLocked(gen, timeSeconds);
2382                 programMinLft = Math.min(programMinLft, ra.getRemainingFilterLft(timeSeconds));
2383             }
2384             emitEpilogue(gen);
2385             program = gen.generate();
2386         } catch (IllegalInstructionException | IllegalStateException | IllegalArgumentException e) {
2387             Log.wtf(TAG, "Failed to generate APF program.", e);
2388             sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_GENERATE_FILTER_EXCEPTION);
2389             return;
2390         }
2391         if (mIsRunning) {
2392             // Update data snapshot every time we install a new program
2393             mIpClientCallback.startReadPacketFilter("new program install");
2394             if (!mIpClientCallback.installPacketFilter(program)) {
2395                 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE);
2396             }
2397         }
2398         mLastTimeInstalledProgram = timeSeconds;
2399         mLastInstalledProgramMinLifetime = programMinLft;
2400         mLastInstalledProgram = program;
2401         mNumProgramUpdates++;
2402         mMaxProgramSize = Math.max(mMaxProgramSize, program.length);
2403 
2404         if (VDBG) {
2405             hexDump("Installing filter: ", program, program.length);
2406         }
2407     }
2408 
hexDump(String msg, byte[] packet, int length)2409     private void hexDump(String msg, byte[] packet, int length) {
2410         log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
2411     }
2412 
2413     // Get the minimum value excludes zero. This is used for calculating the lowest lifetime values
2414     // in RA packets. Zero lifetimes are excluded because we want to detect whether there is any
2415     // unusually small lifetimes but zero lifetime is actually valid (cease to be a default router
2416     // or the option is no longer be used). Number of zero lifetime RAs is collected in a different
2417     // Metrics.
getMinForPositiveValue(long oldMinValue, long value)2418     private long getMinForPositiveValue(long oldMinValue, long value) {
2419         if (value < 1) return oldMinValue;
2420         return Math.min(oldMinValue, value);
2421     }
2422 
getMinForPositiveValue(int oldMinValue, int value)2423     private int getMinForPositiveValue(int oldMinValue, int value) {
2424         return (int) getMinForPositiveValue((long) oldMinValue, (long) value);
2425     }
2426 
2427     /**
2428      * Process an RA packet, updating the list of known RAs and installing a new APF program
2429      * if the current APF program should be updated.
2430      */
2431     @VisibleForTesting
processRa(byte[] packet, int length)2432     public synchronized void processRa(byte[] packet, int length) {
2433         if (VDBG) hexDump("Read packet = ", packet, length);
2434 
2435         final Ra ra;
2436         try {
2437             ra = new Ra(packet, length);
2438         } catch (Exception e) {
2439             Log.e(TAG, "Error parsing RA", e);
2440             mNumParseErrorRas++;
2441             return;
2442         }
2443 
2444         // Update info for Metrics
2445         mLowestRouterLifetimeSeconds = getMinForPositiveValue(
2446                 mLowestRouterLifetimeSeconds, ra.routerLifetime());
2447         mLowestPioValidLifetimeSeconds = getMinForPositiveValue(
2448                 mLowestPioValidLifetimeSeconds, ra.minPioValidLifetime());
2449         mLowestRioRouteLifetimeSeconds = getMinForPositiveValue(
2450                 mLowestRioRouteLifetimeSeconds, ra.minRioRouteLifetime());
2451         mLowestRdnssLifetimeSeconds = getMinForPositiveValue(
2452                 mLowestRdnssLifetimeSeconds, ra.minRdnssLifetime());
2453 
2454         // Remove all expired RA filters before trying to match the new RA.
2455         // TODO: matches() still checks that the old RA filter has not expired. Consider removing
2456         // that check.
2457         final int now = secondsSinceBoot();
2458         mRas.removeIf(item -> item.getRemainingFilterLft(now) <= 0);
2459 
2460         // Have we seen this RA before?
2461         for (int i = 0; i < mRas.size(); i++) {
2462             final Ra oldRa = mRas.get(i);
2463             final Ra.MatchType result = oldRa.matches(ra);
2464             if (result == Ra.MatchType.MATCH_PASS) {
2465                 log("Updating RA from " + oldRa + " to " + ra);
2466 
2467                 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
2468                 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
2469                 // until the filter program exceeds the maximum filter program size allowed by the
2470                 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
2471                 // filter program.
2472                 // TODO: consider sorting the RAs in order of increasing expiry time as well.
2473                 // Swap to front of array.
2474                 mRas.remove(i);
2475                 mRas.add(0, ra);
2476 
2477                 // Rate limit program installation
2478                 if (mTokenBucket.get()) {
2479                     installNewProgramLocked();
2480                 } else {
2481                     Log.e(TAG, "Failed to install prog for tracked RA, too many updates. " + ra);
2482                 }
2483                 return;
2484             } else if (result == Ra.MatchType.MATCH_DROP) {
2485                 log("Ignoring RA " + ra + " which matches " + oldRa);
2486                 return;
2487             }
2488         }
2489         mMaxDistinctRas = Math.max(mMaxDistinctRas, mRas.size() + 1);
2490         if (mRas.size() >= MAX_RAS) {
2491             // Remove the last (i.e. oldest) RA.
2492             mRas.remove(mRas.size() - 1);
2493         }
2494         log("Adding " + ra);
2495         mRas.add(0, ra);
2496         // Rate limit program installation
2497         if (mTokenBucket.get()) {
2498             installNewProgramLocked();
2499         } else {
2500             Log.e(TAG, "Failed to install prog for new RA, too many updates. " + ra);
2501         }
2502     }
2503 
2504     /**
2505      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
2506      * filtering using APF programs.
2507      */
maybeCreate(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics)2508     public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
2509             InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback,
2510             NetworkQuirkMetrics networkQuirkMetrics) {
2511         if (context == null || config == null || ifParams == null) return null;
2512         ApfCapabilities apfCapabilities =  config.apfCapabilities;
2513         if (apfCapabilities == null) return null;
2514         if (apfCapabilities.apfVersionSupported < 2) return null;
2515         if (apfCapabilities.maximumApfProgramSize < 512) {
2516             Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
2517             return null;
2518         }
2519         // For now only support generating programs for Ethernet frames. If this restriction is
2520         // lifted the program generator will need its offsets adjusted.
2521         if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
2522         if (!ApfV4Generator.supportsVersion(apfCapabilities.apfVersionSupported)) {
2523             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
2524             return null;
2525         }
2526 
2527         return new ApfFilter(context, config, ifParams, ipClientCallback, networkQuirkMetrics);
2528     }
2529 
collectAndSendMetrics()2530     private synchronized void collectAndSendMetrics() {
2531         if (mIpClientRaInfoMetrics == null || mApfSessionInfoMetrics == null) return;
2532         final long sessionDurationMs = mClock.elapsedRealtime() - mSessionStartMs;
2533         if (sessionDurationMs < mMinMetricsSessionDurationMs) return;
2534 
2535         // Collect and send IpClientRaInfoMetrics.
2536         mIpClientRaInfoMetrics.setMaxNumberOfDistinctRas(mMaxDistinctRas);
2537         mIpClientRaInfoMetrics.setNumberOfZeroLifetimeRas(mNumZeroLifetimeRas);
2538         mIpClientRaInfoMetrics.setNumberOfParsingErrorRas(mNumParseErrorRas);
2539         mIpClientRaInfoMetrics.setLowestRouterLifetimeSeconds(mLowestRouterLifetimeSeconds);
2540         mIpClientRaInfoMetrics.setLowestPioValidLifetimeSeconds(mLowestPioValidLifetimeSeconds);
2541         mIpClientRaInfoMetrics.setLowestRioRouteLifetimeSeconds(mLowestRioRouteLifetimeSeconds);
2542         mIpClientRaInfoMetrics.setLowestRdnssLifetimeSeconds(mLowestRdnssLifetimeSeconds);
2543         mIpClientRaInfoMetrics.statsWrite();
2544 
2545         // Collect and send ApfSessionInfoMetrics.
2546         mApfSessionInfoMetrics.setVersion(mApfCapabilities.apfVersionSupported);
2547         mApfSessionInfoMetrics.setMemorySize(mApfCapabilities.maximumApfProgramSize);
2548         mApfSessionInfoMetrics.setApfSessionDurationSeconds(
2549                 (int) (sessionDurationMs / DateUtils.SECOND_IN_MILLIS));
2550         mApfSessionInfoMetrics.setNumOfTimesApfProgramUpdated(mNumProgramUpdates);
2551         mApfSessionInfoMetrics.setMaxProgramSize(mMaxProgramSize);
2552         for (Map.Entry<Counter, Long> entry : mApfCounterTracker.getCounters().entrySet()) {
2553             if (entry.getValue() > 0) {
2554                 mApfSessionInfoMetrics.addApfCounter(entry.getKey(), entry.getValue());
2555             }
2556         }
2557         mApfSessionInfoMetrics.statsWrite();
2558     }
2559 
shutdown()2560     public synchronized void shutdown() {
2561         collectAndSendMetrics();
2562         if (mReceiveThread != null) {
2563             log("shutting down");
2564             mReceiveThread.halt();  // Also closes socket.
2565             mReceiveThread = null;
2566         }
2567         mRas.clear();
2568         mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver);
2569     }
2570 
setMulticastFilter(boolean isEnabled)2571     public synchronized void setMulticastFilter(boolean isEnabled) {
2572         if (mMulticastFilter == isEnabled) return;
2573         mMulticastFilter = isEnabled;
2574         installNewProgramLocked();
2575     }
2576 
2577     @VisibleForTesting
setDozeMode(boolean isEnabled)2578     public synchronized void setDozeMode(boolean isEnabled) {
2579         if (mInDozeMode == isEnabled) return;
2580         mInDozeMode = isEnabled;
2581         installNewProgramLocked();
2582     }
2583 
2584     @VisibleForTesting
isInDozeMode()2585     public synchronized boolean isInDozeMode() {
2586         return mInDozeMode;
2587     }
2588 
2589     /** Retrieve the single IPv4 LinkAddress if there is one, otherwise return null. */
retrieveIPv4LinkAddress(LinkProperties lp)2590     private static LinkAddress retrieveIPv4LinkAddress(LinkProperties lp) {
2591         LinkAddress ipv4Address = null;
2592         for (LinkAddress address : lp.getLinkAddresses()) {
2593             if (!(address.getAddress() instanceof Inet4Address)) {
2594                 continue;
2595             }
2596             if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
2597                 // More than one IPv4 address, abort.
2598                 return null;
2599             }
2600             ipv4Address = address;
2601         }
2602         return ipv4Address;
2603     }
2604 
2605     /** Retrieve the pair of IPv6 Inet6Address set, otherwise return pair with two empty set.
2606      *  The first element is a set containing tentative IPv6 addresses,
2607      *  the second element is a set containing non-tentative IPv6 addresses
2608      *  */
2609     private static Pair<Set<Inet6Address>, Set<Inet6Address>>
retrieveIPv6LinkAddress(LinkProperties lp)2610             retrieveIPv6LinkAddress(LinkProperties lp) {
2611         final Set<Inet6Address> tentativeAddrs = new ArraySet<>();
2612         final Set<Inet6Address> nonTentativeAddrs = new ArraySet<>();
2613         for (LinkAddress address : lp.getLinkAddresses()) {
2614             if (!(address.getAddress() instanceof Inet6Address)) {
2615                 continue;
2616             }
2617 
2618             if ((address.getFlags() & IFA_F_TENTATIVE) == IFA_F_TENTATIVE) {
2619                 tentativeAddrs.add((Inet6Address) address.getAddress());
2620             } else {
2621                 nonTentativeAddrs.add((Inet6Address) address.getAddress());
2622             }
2623         }
2624 
2625 
2626         return new Pair<>(tentativeAddrs, nonTentativeAddrs);
2627     }
2628 
setLinkProperties(LinkProperties lp)2629     public synchronized void setLinkProperties(LinkProperties lp) {
2630         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
2631         final LinkAddress ipv4Address = retrieveIPv4LinkAddress(lp);
2632         final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
2633         final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
2634         final Pair<Set<Inet6Address>, Set<Inet6Address>>
2635                 ipv6Addresses = retrieveIPv6LinkAddress(lp);
2636 
2637         if ((prefix == mIPv4PrefixLength)
2638                 && Arrays.equals(addr, mIPv4Address)
2639                 && ipv6Addresses.first.equals(mIPv6TentativeAddresses)
2640                 && ipv6Addresses.second.equals(mIPv6NonTentativeAddresses)
2641         ) {
2642             return;
2643         }
2644         mIPv4Address = addr;
2645         mIPv4PrefixLength = prefix;
2646         mIPv6TentativeAddresses = ipv6Addresses.first;
2647         mIPv6NonTentativeAddresses = ipv6Addresses.second;
2648 
2649         installNewProgramLocked();
2650     }
2651 
2652     @Override
updateClatInterfaceState(boolean add)2653     public synchronized void updateClatInterfaceState(boolean add) {
2654         if (mHasClat == add) {
2655             return;
2656         }
2657         mHasClat = add;
2658         installNewProgramLocked();
2659     }
2660 
2661     /**
2662      * Add TCP keepalive ack packet filter.
2663      * This will add a filter to drop acks to the keepalive packet passed as an argument.
2664      *
2665      * @param slot The index used to access the filter.
2666      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
2667      */
addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)2668     public synchronized void addTcpKeepalivePacketFilter(final int slot,
2669             final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
2670         log("Adding keepalive ack(" + slot + ")");
2671         if (null != mKeepalivePackets.get(slot)) {
2672             throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
2673         }
2674         final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
2675         mKeepalivePackets.put(slot, (ipVersion == 4)
2676                 ? new TcpKeepaliveAckV4(sentKeepalivePacket)
2677                 : new TcpKeepaliveAckV6(sentKeepalivePacket));
2678         installNewProgramLocked();
2679     }
2680 
2681     /**
2682      * Add NAT-T keepalive packet filter.
2683      * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
2684      *
2685      * @param slot The index used to access the filter.
2686      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
2687      */
addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)2688     public synchronized void addNattKeepalivePacketFilter(final int slot,
2689             final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
2690         log("Adding NAT-T keepalive packet(" + slot + ")");
2691         if (null != mKeepalivePackets.get(slot)) {
2692             throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
2693         }
2694 
2695         // TODO : update ApfFilter to support dropping v6 keepalives
2696         if (sentKeepalivePacket.srcAddress.length != 4) {
2697             return;
2698         }
2699 
2700         mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
2701         installNewProgramLocked();
2702     }
2703 
2704     /**
2705      * Remove keepalive packet filter.
2706      *
2707      * @param slot The index used to access the filter.
2708      */
removeKeepalivePacketFilter(int slot)2709     public synchronized void removeKeepalivePacketFilter(int slot) {
2710         log("Removing keepalive packet(" + slot + ")");
2711         mKeepalivePackets.remove(slot);
2712         installNewProgramLocked();
2713     }
2714 
dump(IndentingPrintWriter pw)2715     public synchronized void dump(IndentingPrintWriter pw) {
2716         pw.println("Capabilities: " + mApfCapabilities);
2717         pw.println("InstallableProgramSizeClamp: " + mInstallableProgramSizeClamp);
2718         pw.println("Filter update status: " + (mIsRunning ? "RUNNING" : "PAUSED"));
2719         pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
2720         pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
2721         pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec);
2722         try {
2723             pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
2724             pw.println("IPv6 addresses: ");
2725             pw.increaseIndent();
2726             for (Inet6Address addr: mIPv6NonTentativeAddresses) {
2727                 pw.println(addr.getHostAddress());
2728             }
2729             pw.decreaseIndent();
2730         } catch (UnknownHostException|NullPointerException e) {}
2731 
2732         if (mLastTimeInstalledProgram == 0) {
2733             pw.println("No program installed.");
2734             return;
2735         }
2736         pw.println("Program updates: " + mNumProgramUpdates);
2737         pw.println(String.format(
2738                 "Last program length %d, installed %ds ago, lifetime %ds",
2739                 mLastInstalledProgram.length, secondsSinceBoot() - mLastTimeInstalledProgram,
2740                 mLastInstalledProgramMinLifetime));
2741 
2742         pw.print("Denylisted Ethertypes:");
2743         for (int p : mEthTypeBlackList) {
2744             pw.print(String.format(" %04x", p));
2745         }
2746         pw.println();
2747         pw.println("RA filters:");
2748         pw.increaseIndent();
2749         for (Ra ra: mRas) {
2750             pw.println(ra);
2751             pw.increaseIndent();
2752             pw.println(String.format(
2753                     "Last seen %ds ago", secondsSinceBoot() - ra.mLastSeen));
2754             if (DBG) {
2755                 pw.println("Last match:");
2756                 pw.increaseIndent();
2757                 pw.println(ra.getLastMatchingPacket());
2758                 pw.decreaseIndent();
2759             }
2760             pw.decreaseIndent();
2761         }
2762         pw.decreaseIndent();
2763 
2764         pw.println("TCP Keepalive filters:");
2765         pw.increaseIndent();
2766         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
2767             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
2768             if (keepalivePacket instanceof TcpKeepaliveAck) {
2769                 pw.print("Slot ");
2770                 pw.print(mKeepalivePackets.keyAt(i));
2771                 pw.print(": ");
2772                 pw.println(keepalivePacket);
2773             }
2774         }
2775         pw.decreaseIndent();
2776 
2777         pw.println("NAT-T Keepalive filters:");
2778         pw.increaseIndent();
2779         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
2780             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
2781             if (keepalivePacket instanceof NattKeepaliveResponse) {
2782                 pw.print("Slot ");
2783                 pw.print(mKeepalivePackets.keyAt(i));
2784                 pw.print(": ");
2785                 pw.println(keepalivePacket);
2786             }
2787         }
2788         pw.decreaseIndent();
2789 
2790         if (DBG) {
2791             pw.println("Last program:");
2792             pw.increaseIndent();
2793             pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
2794             pw.decreaseIndent();
2795         }
2796 
2797         pw.println("APF packet counters: ");
2798         pw.increaseIndent();
2799         if (!hasDataAccess(mApfCapabilities)) {
2800             pw.println("APF counters not supported");
2801         } else if (mDataSnapshot == null) {
2802             pw.println("No last snapshot.");
2803         } else {
2804             try {
2805                 Counter[] counters = Counter.class.getEnumConstants();
2806                 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
2807                     long value = ApfCounterTracker.getCounterValue(mDataSnapshot, c);
2808                     // Only print non-zero counters
2809                     if (value != 0) {
2810                         pw.println(c.toString() + ": " + value);
2811                     }
2812 
2813                     // If the counter's value decreases, it may have been cleaned up or there may be
2814                     // a bug.
2815                     if (value < mApfCounterTracker.getCounters().getOrDefault(c, 0L)) {
2816                         Log.e(TAG, "Error: Counter value unexpectedly decreased.");
2817                     }
2818                 }
2819             } catch (ArrayIndexOutOfBoundsException e) {
2820                 pw.println("Uh-oh: " + e);
2821             }
2822             if (VDBG) {
2823                 pw.println("Raw data dump: ");
2824                 pw.println(HexDump.dumpHexString(mDataSnapshot));
2825             }
2826         }
2827         pw.decreaseIndent();
2828     }
2829 
2830     /** Return ApfFilter update status for testing purposes. */
isRunning()2831     public boolean isRunning() {
2832         return mIsRunning;
2833     }
2834 
2835     /** Pause ApfFilter updates for testing purposes. */
pause()2836     public void pause() {
2837         mIsRunning = false;
2838     }
2839 
2840     /** Resume ApfFilter updates for testing purposes. */
resume()2841     public void resume() {
2842         mIsRunning = true;
2843     }
2844 
2845     /** Return data snapshot as hex string for testing purposes. */
getDataSnapshotHexString()2846     public synchronized @Nullable String getDataSnapshotHexString() {
2847         if (mDataSnapshot == null) {
2848             return null;
2849         }
2850         return HexDump.toHexString(mDataSnapshot, 0, mDataSnapshot.length, false /* lowercase */);
2851     }
2852 
2853     // TODO: move to android.net.NetworkUtils
2854     @VisibleForTesting
ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)2855     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
2856         return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
2857     }
2858 
uint8(byte b)2859     private static int uint8(byte b) {
2860         return b & 0xff;
2861     }
2862 
getUint16(ByteBuffer buffer, int position)2863     private static int getUint16(ByteBuffer buffer, int position) {
2864         return buffer.getShort(position) & 0xffff;
2865     }
2866 
getUint32(ByteBuffer buffer, int position)2867     private static long getUint32(ByteBuffer buffer, int position) {
2868         return Integer.toUnsignedLong(buffer.getInt(position));
2869     }
2870 
getUint8(ByteBuffer buffer, int position)2871     private static int getUint8(ByteBuffer buffer, int position) {
2872         return uint8(buffer.get(position));
2873     }
2874 
bytesToBEInt(byte[] bytes)2875     private static int bytesToBEInt(byte[] bytes) {
2876         return (uint8(bytes[0]) << 24)
2877                 + (uint8(bytes[1]) << 16)
2878                 + (uint8(bytes[2]) << 8)
2879                 + (uint8(bytes[3]));
2880     }
2881 
concatArrays(final byte[]... arr)2882     private static byte[] concatArrays(final byte[]... arr) {
2883         int size = 0;
2884         for (byte[] a : arr) {
2885             size += a.length;
2886         }
2887         final byte[] result = new byte[size];
2888         int offset = 0;
2889         for (byte[] a : arr) {
2890             System.arraycopy(a, 0, result, offset, a.length);
2891             offset += a.length;
2892         }
2893         return result;
2894     }
2895 
sendNetworkQuirkMetrics(final NetworkQuirkEvent event)2896     private void sendNetworkQuirkMetrics(final NetworkQuirkEvent event) {
2897         if (mNetworkQuirkMetrics == null) return;
2898         mNetworkQuirkMetrics.setEvent(event);
2899         mNetworkQuirkMetrics.statsWrite();
2900     }
2901 }
2902