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