• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.apf;
18 
19 import static android.net.apf.ApfConstants.APF_MAX_ETH_TYPE_BLACK_LIST_LEN;
20 import static android.net.apf.ApfConstants.ARP_HEADER_OFFSET;
21 import static android.net.apf.ApfConstants.ARP_IPV4_HEADER;
22 import static android.net.apf.ApfConstants.ARP_OPCODE_OFFSET;
23 import static android.net.apf.ApfConstants.ARP_OPCODE_REPLY;
24 import static android.net.apf.ApfConstants.ARP_OPCODE_REQUEST;
25 import static android.net.apf.ApfConstants.ARP_SOURCE_IP_ADDRESS_OFFSET;
26 import static android.net.apf.ApfConstants.ARP_TARGET_IP_ADDRESS_OFFSET;
27 import static android.net.apf.ApfConstants.DHCP_CLIENT_MAC_OFFSET;
28 import static android.net.apf.ApfConstants.DHCP_CLIENT_PORT;
29 import static android.net.apf.ApfConstants.DHCP_SERVER_PORT;
30 import static android.net.apf.ApfConstants.DNS_HEADER_LEN;
31 import static android.net.apf.ApfConstants.ECHO_PORT;
32 import static android.net.apf.ApfConstants.ETH_DEST_ADDR_OFFSET;
33 import static android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET;
34 import static android.net.apf.ApfConstants.ETH_HEADER_LEN;
35 import static android.net.apf.ApfConstants.ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS;
36 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V4_MAC_ADDRESS;
37 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V6_MAC_ADDRESS;
38 import static android.net.apf.ApfConstants.ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS;
39 import static android.net.apf.ApfConstants.ETH_TYPE_MAX;
40 import static android.net.apf.ApfConstants.ETH_TYPE_MIN;
41 import static android.net.apf.ApfConstants.FIXED_ARP_REPLY_HEADER;
42 import static android.net.apf.ApfConstants.ICMP4_CHECKSUM_NO_OPTIONS_OFFSET;
43 import static android.net.apf.ApfConstants.ICMP4_CONTENT_NO_OPTIONS_OFFSET;
44 import static android.net.apf.ApfConstants.ICMP4_TYPE_NO_OPTIONS_OFFSET;
45 import static android.net.apf.ApfConstants.ICMP6_4_BYTE_LIFETIME_LEN;
46 import static android.net.apf.ApfConstants.ICMP6_4_BYTE_LIFETIME_OFFSET;
47 import static android.net.apf.ApfConstants.ICMP6_CAPTIVE_PORTAL_OPTION_TYPE;
48 import static android.net.apf.ApfConstants.ICMP6_CHECKSUM_OFFSET;
49 import static android.net.apf.ApfConstants.ICMP6_CODE_OFFSET;
50 import static android.net.apf.ApfConstants.ICMP6_CONTENT_OFFSET;
51 import static android.net.apf.ApfConstants.ICMP6_DNSSL_OPTION_TYPE;
52 import static android.net.apf.ApfConstants.ICMP6_ECHO_REQUEST_HEADER_LEN;
53 import static android.net.apf.ApfConstants.ICMP6_MTU_OPTION_TYPE;
54 import static android.net.apf.ApfConstants.ICMP6_NS_OPTION_TYPE_OFFSET;
55 import static android.net.apf.ApfConstants.ICMP6_NS_TARGET_IP_OFFSET;
56 import static android.net.apf.ApfConstants.ICMP6_PREF64_OPTION_TYPE;
57 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN;
58 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_TYPE;
59 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN;
60 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET;
61 import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_LEN;
62 import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_OFFSET;
63 import static android.net.apf.ApfConstants.ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE;
64 import static android.net.apf.ApfConstants.ICMP6_RA_OPTION_OFFSET;
65 import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_LEN;
66 import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_OFFSET;
67 import static android.net.apf.ApfConstants.ICMP6_RDNSS_OPTION_TYPE;
68 import static android.net.apf.ApfConstants.ICMP6_ROUTE_INFO_OPTION_TYPE;
69 import static android.net.apf.ApfConstants.ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE;
70 import static android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET;
71 import static android.net.apf.ApfConstants.IGMPV2_REPORT_FROM_IPV4_OPTION_TO_IGMP_CHECKSUM;
72 import static android.net.apf.ApfConstants.IGMPV3_MODE_IS_EXCLUDE;
73 import static android.net.apf.ApfConstants.IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET;
74 import static android.net.apf.ApfConstants.IGMP_MAX_RESP_TIME_OFFSET;
75 import static android.net.apf.ApfConstants.IGMP_MULTICAST_ADDRESS_OFFSET;
76 import static android.net.apf.ApfConstants.IGMP_TYPE_REPORTS;
77 import static android.net.apf.ApfConstants.IPPROTO_HOPOPTS;
78 import static android.net.apf.ApfConstants.IPV4_ALL_HOSTS_ADDRESS_IN_LONG;
79 import static android.net.apf.ApfConstants.IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS;
80 import static android.net.apf.ApfConstants.IPV4_ANY_HOST_ADDRESS;
81 import static android.net.apf.ApfConstants.IPV4_BROADCAST_ADDRESS;
82 import static android.net.apf.ApfConstants.IPV4_DEST_ADDR_OFFSET;
83 import static android.net.apf.ApfConstants.IPV4_DNS_QDCOUNT_NO_OPTIONS_OFFSET;
84 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_MORE_FRAGS_MASK;
85 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_MASK;
86 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_OFFSET;
87 import static android.net.apf.ApfConstants.IPV4_IGMP_TYPE_QUERY;
88 import static android.net.apf.ApfConstants.IPV4_PROTOCOL_OFFSET;
89 import static android.net.apf.ApfConstants.IPV4_SRC_ADDR_OFFSET;
90 import static android.net.apf.ApfConstants.IPV4_ROUTER_ALERT_OPTION;
91 import static android.net.apf.ApfConstants.IPV4_ROUTER_ALERT_OPTION_LEN;
92 import static android.net.apf.ApfConstants.IPV4_TOTAL_LENGTH_OFFSET;
93 import static android.net.apf.ApfConstants.IPV4_UDP_DESTINATION_CHECKSUM_NO_OPTIONS_OFFSET;
94 import static android.net.apf.ApfConstants.IPV4_UDP_DESTINATION_PORT_NO_OPTIONS_OFFSET;
95 import static android.net.apf.ApfConstants.IPV4_UDP_PAYLOAD_NO_OPTIONS_OFFSET;
96 import static android.net.apf.ApfConstants.IPV6_ALL_NODES_ADDRESS;
97 import static android.net.apf.ApfConstants.IPV6_DEST_ADDR_OFFSET;
98 import static android.net.apf.ApfConstants.IPV6_DNS_QDCOUNT_OFFSET;
99 import static android.net.apf.ApfConstants.IPV6_EXT_HEADER_OFFSET;
100 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_LEN;
101 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_OFFSET;
102 import static android.net.apf.ApfConstants.IPV6_HEADER_LEN;
103 import static android.net.apf.ApfConstants.IPV6_HOP_LIMIT_OFFSET;
104 import static android.net.apf.ApfConstants.IPV6_MLD_CHECKSUM_OFFSET;
105 import static android.net.apf.ApfConstants.IPV6_MLD_HOPOPTS;
106 import static android.net.apf.ApfConstants.IPV6_MLD_MESSAGE_MIN_SIZE;
107 import static android.net.apf.ApfConstants.IPV6_MLD_MIN_SIZE;
108 import static android.net.apf.ApfConstants.IPV6_MLD_MULTICAST_ADDR_OFFSET;
109 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_OFFSET;
110 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_QUERY;
111 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_REPORTS;
112 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_V1_REPORT;
113 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_V2_REPORT;
114 import static android.net.apf.ApfConstants.IPV6_MLD_V1_MESSAGE_SIZE;
115 import static android.net.apf.ApfConstants.IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS;
116 import static android.net.apf.ApfConstants.IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE;
117 import static android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET;
118 import static android.net.apf.ApfConstants.IPV6_PAYLOAD_LEN_OFFSET;
119 import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX;
120 import static android.net.apf.ApfConstants.IPV6_SRC_ADDR_OFFSET;
121 import static android.net.apf.ApfConstants.IPV6_UDP_DESTINATION_CHECKSUM_OFFSET;
122 import static android.net.apf.ApfConstants.IPV6_UDP_DESTINATION_PORT_OFFSET;
123 import static android.net.apf.ApfConstants.IPV6_UNSPECIFIED_ADDRESS;
124 import static android.net.apf.ApfConstants.MLD2_MODE_IS_EXCLUDE;
125 import static android.net.apf.ApfConstants.TCP_HEADER_SIZE_OFFSET;
126 import static android.net.apf.ApfConstants.TCP_UDP_DESTINATION_PORT_OFFSET;
127 import static android.net.apf.ApfConstants.TCP_UDP_SOURCE_PORT_OFFSET;
128 import static android.net.apf.ApfCounterTracker.Counter.APF_PROGRAM_ID;
129 import static android.net.apf.ApfCounterTracker.Counter.APF_VERSION;
130 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_802_3_FRAME;
131 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_NON_IPV4;
132 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_OTHER_HOST;
133 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REPLY_SPA_NO_HOST;
134 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REQUEST_REPLIED;
135 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_UNKNOWN;
136 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_V6_ONLY;
137 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHERTYPE_NOT_ALLOWED;
138 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHER_OUR_SRC_MAC;
139 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETH_BROADCAST;
140 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_GARP_REPLY;
141 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_ADDR;
142 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_NET;
143 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IGMP_INVALID;
144 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IGMP_REPORT;
145 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_ICMP_INVALID;
146 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_KEEPALIVE_ACK;
147 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_L2_BROADCAST;
148 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_MULTICAST;
149 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NATT_KEEPALIVE;
150 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4;
151 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_PING_REQUEST_REPLIED;
152 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_TCP_PORT7_UNICAST;
153 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ICMP6_ECHO_REQUEST_INVALID;
154 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ICMP6_ECHO_REQUEST_REPLIED;
155 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_INVALID;
156 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_REPORT;
157 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_V1_GENERAL_QUERY_REPLIED;
158 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_V2_GENERAL_QUERY_REPLIED;
159 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MULTICAST_NA;
160 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NON_ICMP_MULTICAST;
161 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID;
162 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST;
163 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_REPLIED_NON_DAD;
164 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ROUTER_SOLICITATION;
165 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_MDNS;
166 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_NON_UNICAST_TDLS;
167 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_RA;
168 import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_16384THS;
169 import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_SECONDS;
170 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_BROADCAST_REPLY;
171 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_REQUEST;
172 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_UNICAST_REPLY;
173 import static android.net.apf.ApfCounterTracker.Counter.PASSED_DHCP;
174 import static android.net.apf.ApfConstants.IPv6_UDP_PAYLOAD_OFFSET;
175 import static android.net.apf.ApfConstants.MDNS_IPV4_ADDR;
176 import static android.net.apf.ApfConstants.MDNS_IPV4_ADDR_IN_LONG;
177 import static android.net.apf.ApfConstants.MDNS_IPV6_ADDR;
178 import static android.net.apf.ApfConstants.MDNS_PORT;
179 import static android.net.apf.ApfConstants.UDP_HEADER_LEN;
180 import static android.net.apf.ApfConstants.MDNS_PORT_IN_BYTES;
181 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ETHER_OUR_SRC_MAC;
182 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4;
183 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_FROM_DHCPV4_SERVER;
184 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_UNICAST;
185 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_HOPOPTS;
186 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_ICMP;
187 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NON_ICMP;
188 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_UNICAST_NON_ICMP;
189 import static android.net.apf.ApfCounterTracker.Counter.PASSED_MDNS;
190 import static android.net.apf.ApfCounterTracker.Counter.PASSED_NON_IP_UNICAST;
191 import static android.net.apf.ApfCounterTracker.Counter.TOTAL_PACKETS;
192 import static android.net.apf.ApfCounterTracker.getCounterValue;
193 import static android.net.apf.BaseApfGenerator.MemorySlot;
194 import static android.net.apf.BaseApfGenerator.Register.R0;
195 import static android.net.apf.BaseApfGenerator.Register.R1;
196 import static android.net.util.SocketUtils.makePacketSocketAddress;
197 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
198 import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
199 import static android.system.OsConstants.AF_PACKET;
200 import static android.system.OsConstants.ETH_P_ALL;
201 import static android.system.OsConstants.ETH_P_ARP;
202 import static android.system.OsConstants.ETH_P_IP;
203 import static android.system.OsConstants.ETH_P_IPV6;
204 import static android.system.OsConstants.ICMP6_ECHO_REPLY;
205 import static android.system.OsConstants.ICMP_ECHO;
206 import static android.system.OsConstants.ICMP_ECHOREPLY;
207 import static android.system.OsConstants.IFA_F_TENTATIVE;
208 import static android.system.OsConstants.IPPROTO_ICMP;
209 import static android.system.OsConstants.IPPROTO_ICMPV6;
210 import static android.system.OsConstants.IPPROTO_TCP;
211 import static android.system.OsConstants.IPPROTO_UDP;
212 import static android.system.OsConstants.SOCK_CLOEXEC;
213 import static android.system.OsConstants.SOCK_NONBLOCK;
214 import static android.system.OsConstants.SOCK_RAW;
215 
216 import static com.android.net.module.util.CollectionUtils.concatArrays;
217 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
218 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
219 import static com.android.net.module.util.NetworkStackConstants.ETHER_DST_ADDR_OFFSET;
220 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
221 import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET;
222 import static com.android.net.module.util.NetworkStackConstants.ICMP_HEADER_LEN;
223 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
224 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN;
225 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
226 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
227 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA_LEN;
228 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
229 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
230 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
231 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
232 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL_HOST_MULTICAST;
233 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN;
234 import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
235 import static com.android.net.module.util.NetworkStackConstants.IPV4_FLAG_DF;
236 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_GROUP_RECORD_SIZE;
237 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_MIN_SIZE;
238 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_TYPE_V3_REPORT;
239 import static com.android.net.module.util.NetworkStackConstants.IPV4_PROTOCOL_IGMP;
240 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST;
241 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY;
242 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN;
243 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST;
244 
245 import android.annotation.ChecksSdkIntAtLeast;
246 import android.annotation.NonNull;
247 import android.annotation.Nullable;
248 import android.content.BroadcastReceiver;
249 import android.content.Context;
250 import android.content.Intent;
251 import android.content.IntentFilter;
252 import android.net.LinkAddress;
253 import android.net.LinkProperties;
254 import android.net.MacAddress;
255 import android.net.NattKeepalivePacketDataParcelable;
256 import android.net.TcpKeepalivePacketDataParcelable;
257 import android.net.apf.ApfCounterTracker.Counter;
258 import android.net.apf.BaseApfGenerator.IllegalInstructionException;
259 import android.net.ip.MulticastReportMonitor;
260 import android.net.nsd.NsdManager;
261 import android.os.Handler;
262 import android.os.PowerManager;
263 import android.os.SystemClock;
264 import android.stats.connectivity.NetworkQuirkEvent;
265 import android.system.ErrnoException;
266 import android.system.Os;
267 import android.text.format.DateUtils;
268 import android.util.ArraySet;
269 import android.util.Log;
270 import android.util.Pair;
271 import android.util.SparseArray;
272 
273 import com.android.internal.annotations.VisibleForTesting;
274 import com.android.internal.util.HexDump;
275 import com.android.internal.util.IndentingPrintWriter;
276 import com.android.internal.util.TokenBucket;
277 import com.android.modules.utils.build.SdkLevel;
278 import com.android.net.module.util.CollectionUtils;
279 import com.android.net.module.util.ConnectivityUtils;
280 import com.android.net.module.util.InterfaceParams;
281 import com.android.net.module.util.PacketReader;
282 import com.android.networkstack.metrics.ApfSessionInfoMetrics;
283 import com.android.networkstack.metrics.IpClientRaInfoMetrics;
284 import com.android.networkstack.metrics.NetworkQuirkMetrics;
285 import com.android.networkstack.util.NetworkStackUtils;
286 
287 import java.io.FileDescriptor;
288 import java.net.Inet4Address;
289 import java.net.Inet6Address;
290 import java.net.InetAddress;
291 import java.net.SocketAddress;
292 import java.net.SocketException;
293 import java.net.UnknownHostException;
294 import java.nio.BufferUnderflowException;
295 import java.nio.ByteBuffer;
296 import java.nio.ByteOrder;
297 import java.util.ArrayList;
298 import java.util.Arrays;
299 import java.util.List;
300 import java.util.Map;
301 import java.util.Set;
302 
303 /**
304  * For networks that support packet filtering via APF programs, {@code ApfFilter}
305  * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
306  * filter out redundant duplicate ones.
307  * <p>
308  * Threading model: this class is not thread-safe and can only be accessed from IpClient's
309  * handler thread.
310  *
311  * @hide
312  */
313 public class ApfFilter {
314 
315     /**
316      * Defines the communication API between the ApfFilter and the APF interpreter
317      * residing within the Wi-Fi/Ethernet firmware.
318      */
319     public interface IApfController {
320         /**
321          * Install the APF program to firmware.
322          */
installPacketFilter(@onNull byte[] filter, @NonNull String filterConfig)323         boolean installPacketFilter(@NonNull byte[] filter, @NonNull String filterConfig);
324 
325         /**
326          * Read the APF RAM from firmware.
327          */
readPacketFilterRam(@onNull String event)328         void readPacketFilterRam(@NonNull String event);
329     }
330 
331     // Helper class for specifying functional filter parameters.
332     public static class ApfConfiguration {
333         public int apfVersionSupported;
334         public int apfRamSize;
335         public int installableProgramSizeClamp = Integer.MAX_VALUE;
336         public boolean multicastFilter;
337         public boolean ieee802_3Filter;
338         public int[] ethTypeBlackList;
339         public int minRdnssLifetimeSec;
340         public int acceptRaMinLft;
341         public long minMetricsSessionDurationMs;
342         public boolean hasClatInterface;
343         public boolean handleArpOffload;
344         public boolean handleNdOffload;
345         public boolean handleMdnsOffload;
346         public boolean handleIgmpOffload;
347         public boolean handleMldOffload;
348         public boolean handleIpv4PingOffload;
349         public boolean handleIpv6PingOffload;
350     }
351 
352 
353     private class RaPacketReader extends PacketReader {
354         private static final int RECEIVE_BUFFER_SIZE = 1514;
355         private final int mIfIndex;
356 
RaPacketReader(Handler handler, int ifIndex)357         RaPacketReader(Handler handler, int ifIndex) {
358             super(handler, RECEIVE_BUFFER_SIZE);
359             mIfIndex = ifIndex;
360         }
361 
362         @Override
createFd()363         protected FileDescriptor createFd() {
364             return mDependencies.createPacketReaderSocket(mIfIndex);
365         }
366 
367         @Override
handlePacket(byte[] recvbuf, int length)368         protected void handlePacket(byte[] recvbuf, int length) {
369             processRa(recvbuf, length);
370         }
371     }
372 
373     private static final String TAG = "ApfFilter";
374 
375     private final int mApfRamSize;
376     private final int mMaximumApfProgramSize;
377     private final int mInstallableProgramSizeClamp;
378     private final IApfController mApfController;
379     private final InterfaceParams mInterfaceParams;
380     private final TokenBucket mTokenBucket;
381 
382     @VisibleForTesting
383     public final int mApfVersionSupported;
384     @VisibleForTesting
385     @NonNull
386     public final byte[] mHardwareAddress;
387     private final RaPacketReader mRaPacketReader;
388     private final Handler mHandler;
389     private boolean mMulticastFilter;
390     private boolean mInDozeMode;
391     private final boolean mDrop802_3Frames;
392     private final int[] mEthTypeBlackList;
393 
394     private final ApfCounterTracker mApfCounterTracker = new ApfCounterTracker();
395     private final long mSessionStartMs;
396     private int mNumParseErrorRas = 0;
397     private int mNumZeroLifetimeRas = 0;
398     private int mLowestRouterLifetimeSeconds = Integer.MAX_VALUE;
399     private long mLowestPioValidLifetimeSeconds = Long.MAX_VALUE;
400     private long mLowestRioRouteLifetimeSeconds = Long.MAX_VALUE;
401     private long mLowestRdnssLifetimeSeconds = Long.MAX_VALUE;
402 
403     // Ignore non-zero RDNSS lifetimes below this value.
404     private final int mMinRdnssLifetimeSec;
405 
406     // Minimum session time for metrics, duration less than this time will not be logged.
407     private final long mMinMetricsSessionDurationMs;
408 
409     // Tracks the value of /proc/sys/ipv6/conf/$iface/accept_ra_min_lft which affects router, RIO,
410     // and PIO valid lifetimes.
411     private final int mAcceptRaMinLft;
412     private final boolean mHandleArpOffload;
413     private final boolean mHandleNdOffload;
414     private final boolean mHandleMdnsOffload;
415     private final boolean mHandleIgmpOffload;
416     private final boolean mHandleMldOffload;
417     private final boolean mHandleIpv4PingOffload;
418     private final boolean mHandleIpv6PingOffload;
419 
420     private final NetworkQuirkMetrics mNetworkQuirkMetrics;
421     private final IpClientRaInfoMetrics mIpClientRaInfoMetrics;
422     private final ApfSessionInfoMetrics mApfSessionInfoMetrics;
423     private final NsdManager mNsdManager;
424     private final MulticastReportMonitor mMulticastReportMonitor;
425     private final ApfMdnsOffloadEngine mApfMdnsOffloadEngine;
426     private final List<MdnsOffloadRule> mOffloadRules = new ArrayList<>();
427     // The number of mDNS rules requiring APF to transmit a reply and drop the query packet. A
428     // value of -1 means all mDNS query packets should be passed; no mDNS query packets will trigger
429     // the transmit and reply logic.
430     private int mNumOfMdnsRuleToOffload = -1;
431 
432     private int mOverEstimatedProgramSize = 0;
433 
isDeviceIdleModeChangedAction(Intent intent)434     private static boolean isDeviceIdleModeChangedAction(Intent intent) {
435         return ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction());
436     }
437 
isDeviceLightIdleModeChangedAction(Intent intent)438     private boolean isDeviceLightIdleModeChangedAction(Intent intent) {
439         // The ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED only exist since T. For lower platform version,
440         // the check should return false. The explicit SDK check is needed to make linter happy
441         // about accessing ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED in this function.
442         if (!SdkLevel.isAtLeastT()) {
443             return false;
444         }
445         return ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(intent.getAction());
446     }
447 
isDeviceLightIdleMode(@onNull PowerManager powerManager)448     private boolean isDeviceLightIdleMode(@NonNull PowerManager powerManager) {
449         // The powerManager.isDeviceLightIdleMode() only exist since T. For lower platform version,
450         // the check should return false. The explicit SDK check is needed to make linter happy
451         // about accessing powerManager.isDeviceLightIdleMode() in this function.
452         if (!SdkLevel.isAtLeastT()) {
453             return false;
454         }
455 
456         return powerManager.isDeviceLightIdleMode();
457     }
458 
459     // Detects doze mode state transitions.
460     private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
461         @Override
462         public void onReceive(Context context, Intent intent) {
463             mHandler.post(() -> {
464                 if (mIsApfShutdown) return;
465                 final PowerManager powerManager = context.getSystemService(PowerManager.class);
466                 if (isDeviceIdleModeChangedAction(intent)
467                         || isDeviceLightIdleModeChangedAction(intent)) {
468                     final boolean deviceIdle = powerManager.isDeviceIdleMode()
469                             || isDeviceLightIdleMode(powerManager);
470                     setDozeMode(deviceIdle);
471                 }
472             });
473         }
474     };
475 
476     private boolean mIsApfShutdown;
477 
478     // Our IPv4 address, if we have just one, otherwise null.
479     private byte[] mIPv4Address;
480     // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
481     private int mIPv4PrefixLength;
482 
483     // Our IPv6 non-tentative addresses
484     private Set<Inet6Address> mIPv6NonTentativeAddresses = new ArraySet<>();
485 
486     // Our tentative IPv6 addresses
487     private Set<Inet6Address> mIPv6TentativeAddresses = new ArraySet<>();
488 
489     // Our link-local IPv6 address
490     private Inet6Address mIPv6LinkLocalAddress;
491 
492     // Our joined IPv4 multicast addresses
493     @VisibleForTesting
494     final Set<Inet4Address> mIPv4MulticastAddresses = new ArraySet<>();
495 
496     // Our joined IPv4 multicast address exclude all all host multicast (224.0.0.1)
497     @VisibleForTesting
498     final Set<Inet4Address> mIPv4McastAddrsExcludeAllHost = new ArraySet<>();
499 
500     // Our joined IPv6 multicast addresses
501     @VisibleForTesting
502     final Set<Inet6Address> mIPv6MulticastAddresses = new ArraySet<>();
503 
504     // Our joined IPv6 multicast address exclude ff02::1, ff01::1
505     @VisibleForTesting
506     final Set<Inet6Address> mIPv6McastAddrsExcludeAllHost = new ArraySet<>();
507 
508     // Whether CLAT is enabled.
509     private boolean mHasClat;
510 
511     // mIsRunning is reflects the state of the ApfFilter during integration tests. ApfFilter can be
512     // paused using "adb shell cmd apf <iface> <cmd>" commands. A paused ApfFilter will not install
513     // any new programs, but otherwise operates normally.
514     private volatile boolean mIsRunning = true;
515 
516     private final Dependencies mDependencies;
517 
ApfFilter(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics)518     public ApfFilter(Handler handler, Context context, ApfConfiguration config,
519             InterfaceParams ifParams, IApfController apfController,
520             NetworkQuirkMetrics networkQuirkMetrics) {
521         this(handler, context, config, ifParams, apfController, networkQuirkMetrics,
522                 new Dependencies(context));
523     }
524 
maybeCleanUpApfRam()525     private void maybeCleanUpApfRam() {
526         // Clear the APF memory to reset all counters upon connecting to the first AP
527         // in an SSID. This is limited to APFv3 devices because this large write triggers
528         // a crash on some older devices (b/78905546).
529         if (hasDataAccess(mApfVersionSupported)) {
530             installPacketFilter(new byte[mApfRamSize], getApfConfigMessage() + " (cleanup)");
531         }
532     }
533 
534     @VisibleForTesting
ApfFilter(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies)535     public ApfFilter(Handler handler, Context context, ApfConfiguration config,
536             InterfaceParams ifParams, IApfController apfController,
537             NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies) {
538         mHandler = handler;
539         mApfVersionSupported = config.apfVersionSupported;
540         mApfRamSize = config.apfRamSize;
541         mInstallableProgramSizeClamp = config.installableProgramSizeClamp;
542         int maximumApfProgramSize = mApfRamSize;
543         if (hasDataAccess(mApfVersionSupported)) {
544             // Reserve space for the counters.
545             maximumApfProgramSize -= Counter.totalSize();
546         }
547         // Prevent generating (and thus installing) larger programs
548         if (maximumApfProgramSize > mInstallableProgramSizeClamp) {
549             maximumApfProgramSize = mInstallableProgramSizeClamp;
550         }
551         mMaximumApfProgramSize = Math.max(0, maximumApfProgramSize);
552         mApfController = apfController;
553         mInterfaceParams = ifParams;
554         mMulticastFilter = config.multicastFilter;
555         mDrop802_3Frames = config.ieee802_3Filter;
556         mMinRdnssLifetimeSec = config.minRdnssLifetimeSec;
557         mAcceptRaMinLft = config.acceptRaMinLft;
558         mHandleArpOffload = config.handleArpOffload;
559         mHandleNdOffload = config.handleNdOffload;
560         mHandleMdnsOffload = config.handleMdnsOffload;
561         mHandleIgmpOffload = config.handleIgmpOffload;
562         mHandleMldOffload = config.handleMldOffload;
563         mHandleIpv4PingOffload = config.handleIpv4PingOffload;
564         mHandleIpv6PingOffload = config.handleIpv6PingOffload;
565         mDependencies = dependencies;
566         mNetworkQuirkMetrics = networkQuirkMetrics;
567         mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics();
568         mApfSessionInfoMetrics = dependencies.getApfSessionInfoMetrics();
569         mSessionStartMs = dependencies.elapsedRealtime();
570         mMinMetricsSessionDurationMs = config.minMetricsSessionDurationMs;
571         mHasClat = config.hasClatInterface;
572 
573         mIsApfShutdown = false;
574 
575         // Now fill the black list from the passed array
576         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
577 
578         // TokenBucket for rate limiting filter installation. APF filtering relies on the filter
579         // always being up-to-date and APF bytecode being in sync with userspace. The TokenBucket
580         // merely prevents illconfigured / abusive networks from impacting the system, so it does
581         // not need to be very restrictive.
582         // The TokenBucket starts with its full capacity of 20 tokens (= 20 filter updates). A new
583         // token is generated every 3 seconds limiting the filter update rate to at most once every
584         // 3 seconds.
585         mTokenBucket = new TokenBucket(3_000 /* deltaMs */, 20 /* capacity */, 20 /* tokens */);
586 
587         mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
588         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
589         maybeCleanUpApfRam();
590         // Install basic filters
591         installNewProgram();
592 
593         mRaPacketReader = new RaPacketReader(mHandler, mInterfaceParams.index);
594         // The class constructor must be called from the IpClient's handler thread
595         if (!mRaPacketReader.start()) {
596             Log.wtf(TAG, "Failed to start RaPacketReader");
597         }
598 
599         mMulticastReportMonitor = createMulticastReportMonitor();
600         if (mMulticastReportMonitor != null) {
601             mMulticastReportMonitor.start();
602         }
603 
604         // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
605         mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver);
606 
607         mNsdManager = context.getSystemService(NsdManager.class);
608         if (enableOffloadEngineRegistration()) {
609             mApfMdnsOffloadEngine = new ApfMdnsOffloadEngine(mInterfaceParams.name, mHandler,
610                     mNsdManager,
611                     allRules -> {
612                         mOffloadRules.clear();
613                         mOffloadRules.addAll(allRules);
614                         installNewProgram();
615                     });
616             mApfMdnsOffloadEngine.registerOffloadEngine();
617         } else {
618             mApfMdnsOffloadEngine = null;
619         }
620 
621         mIPv4MulticastAddresses.addAll(
622                 mDependencies.getIPv4MulticastAddresses(mInterfaceParams.name));
623         mIPv4McastAddrsExcludeAllHost.addAll(mIPv4MulticastAddresses);
624         mIPv4McastAddrsExcludeAllHost.remove((IPV4_ADDR_ALL_HOST_MULTICAST));
625 
626         mIPv6MulticastAddresses.addAll(
627                 mDependencies.getIPv6MulticastAddresses(mInterfaceParams.name));
628         mIPv6McastAddrsExcludeAllHost.addAll(mIPv6MulticastAddresses);
629         mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_ALL_NODES_MULTICAST);
630         mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST);
631     }
632 
633     /**
634      * Dependencies class for testing.
635      */
636     @VisibleForTesting
637     public static class Dependencies {
638         private final Context mContext;
Dependencies(final Context context)639         public Dependencies(final Context context) {
640             mContext = context;
641         }
642 
643         /**
644          * Create a socket to read RAs.
645          */
646         @Nullable
createPacketReaderSocket(int ifIndex)647         public FileDescriptor createPacketReaderSocket(int ifIndex) {
648             FileDescriptor socket;
649             try {
650                 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
651                 NetworkStackUtils.attachRaFilter(socket);
652                 SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, ifIndex);
653                 Os.bind(socket, addr);
654             } catch (SocketException | ErrnoException e) {
655                 Log.wtf(TAG, "Error starting filter", e);
656                 return null;
657             }
658             return socket;
659         }
660 
661         /**
662          * Create a socket to read egress IGMPv2/v3 reports.
663          */
664         @Nullable
createEgressIgmpReportsReaderSocket(int ifIndex)665         public FileDescriptor createEgressIgmpReportsReaderSocket(int ifIndex) {
666             FileDescriptor socket;
667             try {
668                 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
669                 NetworkStackUtils.attachEgressIgmpReportFilter(socket);
670                 Os.bind(socket, makePacketSocketAddress(ETH_P_ALL, ifIndex));
671             } catch (SocketException | ErrnoException e) {
672                 Log.wtf(TAG, "Error starting filter", e);
673                 return null;
674             }
675 
676             return socket;
677         }
678 
679         /**
680          * Create a socket to read egress IGMPv2/v3, MLDv1/v2 reports.
681          */
682         @Nullable
createEgressMulticastReportsReaderSocket(int ifIndex)683         public FileDescriptor createEgressMulticastReportsReaderSocket(int ifIndex) {
684             FileDescriptor socket;
685             try {
686                 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
687                 NetworkStackUtils.attachEgressMulticastReportFilter(socket);
688                 Os.bind(socket, makePacketSocketAddress(ETH_P_ALL, ifIndex));
689             } catch (SocketException | ErrnoException e) {
690                 Log.wtf(TAG, "Error starting filter", e);
691                 return null;
692             }
693 
694             return socket;
695         }
696 
697         /**
698          * Get elapsedRealtime.
699          */
elapsedRealtime()700         public long elapsedRealtime() {
701             return SystemClock.elapsedRealtime();
702         }
703 
704         /** Add receiver for detecting doze mode change */
addDeviceIdleReceiver(@onNull final BroadcastReceiver receiver)705         public void addDeviceIdleReceiver(@NonNull final BroadcastReceiver receiver) {
706             final IntentFilter intentFilter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED);
707             if (SdkLevel.isAtLeastT()) {
708                 intentFilter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
709             }
710             mContext.registerReceiver(receiver, intentFilter);
711         }
712 
713         /** Remove broadcast receiver. */
removeBroadcastReceiver(@onNull final BroadcastReceiver receiver)714         public void removeBroadcastReceiver(@NonNull final BroadcastReceiver receiver) {
715             mContext.unregisterReceiver(receiver);
716         }
717 
718         /**
719          * Get a ApfSessionInfoMetrics instance.
720          */
getApfSessionInfoMetrics()721         public ApfSessionInfoMetrics getApfSessionInfoMetrics() {
722             return new ApfSessionInfoMetrics();
723         }
724 
725         /**
726          * Get a IpClientRaInfoMetrics instance.
727          */
getIpClientRaInfoMetrics()728         public IpClientRaInfoMetrics getIpClientRaInfoMetrics() {
729             return new IpClientRaInfoMetrics();
730         }
731 
732         /**
733          * Callback to be called when an ApfFilter instance is created.
734          *
735          * This method is designed to be overridden in test classes to collect created ApfFilter
736          * instances.
737          */
onApfFilterCreated(@onNull ApfFilter apfFilter)738         public void onApfFilterCreated(@NonNull ApfFilter apfFilter) {
739         }
740 
741         /**
742          * Callback to be called when a ReceiveThread instance is created.
743          *
744          * This method is designed for overriding in test classes to collect created threads and
745          * waits for the termination.
746          */
onThreadCreated(@onNull Thread thread)747         public void onThreadCreated(@NonNull Thread thread) {
748         }
749 
750         /**
751          * Loads the existing IPv6 anycast addresses from the file `/proc/net/anycast6`.
752          */
getAnycast6Addresses(@onNull String ifname)753         public List<byte[]> getAnycast6Addresses(@NonNull String ifname) {
754             final List<Inet6Address> anycast6Addresses =
755                     ProcfsParsingUtils.getAnycast6Addresses(ifname);
756             final List<byte[]> addresses = new ArrayList<>();
757             for (Inet6Address addr : anycast6Addresses) {
758                 addresses.add(addr.getAddress());
759             }
760 
761             return addresses;
762         }
763 
764         /**
765          * Loads the existing Ethernet multicast addresses from the file
766          * `/proc/net/dev_mcast`.
767          */
getEtherMulticastAddresses(@onNull String ifname)768         public List<byte[]> getEtherMulticastAddresses(@NonNull String ifname) {
769             final List<MacAddress> etherAddresses =
770                     ProcfsParsingUtils.getEtherMulticastAddresses(ifname);
771             final List<byte[]> addresses = new ArrayList<>();
772             for (MacAddress addr : etherAddresses) {
773                 addresses.add(addr.toByteArray());
774             }
775 
776             return addresses;
777         }
778 
779         /**
780          * Loads the existing ND traffic class for the specific interface from the file
781          * /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass.
782          *
783          * If the file does not exist or the interface is not found,
784          * the function returns 0..255, 0 as default ND traffic class.
785          */
getNdTrafficClass(@onNull String ifname)786         public int getNdTrafficClass(@NonNull String ifname) {
787             return ProcfsParsingUtils.getNdTrafficClass(ifname);
788         }
789 
790         /**
791          * Returns the default TTL value for IPv4 packets from '/proc/sys/net/ipv4/ip_default_ttl'.
792          */
getIpv4DefaultTtl()793         public int getIpv4DefaultTtl() {
794             return ProcfsParsingUtils.getIpv4DefaultTtl();
795         }
796 
797         /**
798          * Returns the default HopLimit value for IPv6 packets.
799          */
getIpv6DefaultHopLimit(@onNull String ifname)800         public int getIpv6DefaultHopLimit(@NonNull String ifname) {
801             return ProcfsParsingUtils.getIpv6DefaultHopLimit(ifname);
802         }
803 
804         /**
805          * Loads the existing IPv4 multicast addresses from the file
806          * `/proc/net/igmp`.
807          */
getIPv4MulticastAddresses(@onNull String ifname)808         public List<Inet4Address> getIPv4MulticastAddresses(@NonNull String ifname) {
809             return ProcfsParsingUtils.getIPv4MulticastAddresses(ifname);
810         }
811 
812         /**
813          * Loads the existing IPv6 multicast addresses from the file `/proc/net/igmp6`.
814          */
getIPv6MulticastAddresses(@onNull String ifname)815         public List<Inet6Address> getIPv6MulticastAddresses(@NonNull String ifname) {
816             return ProcfsParsingUtils.getIpv6MulticastAddresses(ifname);
817         }
818     }
819 
getApfController()820     public IApfController getApfController() {
821         return mApfController;
822     }
823 
setDataSnapshot(byte[] data)824     public String setDataSnapshot(byte[] data) {
825         mDataSnapshot = data;
826         if (mIsRunning) {
827             mApfCounterTracker.updateCountersFromData(data);
828         }
829         return mApfCounterTracker.getCounters().toString();
830     }
831 
createMulticastReportMonitor()832     private MulticastReportMonitor createMulticastReportMonitor() {
833         FileDescriptor socketFd = null;
834 
835         // Check if MLD report monitor is enabled first, it includes the IGMP report monitor.
836         if (enableMldReportsMonitor()) {
837             socketFd =
838                 mDependencies.createEgressMulticastReportsReaderSocket(mInterfaceParams.index);
839         } else if (enableIgmpReportsMonitor()) {
840             socketFd =
841                 mDependencies.createEgressIgmpReportsReaderSocket(mInterfaceParams.index);
842         }
843 
844         return socketFd != null ? new MulticastReportMonitor(
845                 mHandler,
846                 mInterfaceParams,
847                 this::updateMulticastAddrs,
848                 socketFd
849         ) : null;
850     }
851 
log(String s)852     private void log(String s) {
853         Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
854     }
855 
filterEthTypeBlackList(int[] ethTypeBlackList)856     private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
857         ArrayList<Integer> bl = new ArrayList<>();
858 
859         for (int p : ethTypeBlackList) {
860             // Check if the protocol is a valid ether type
861             if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
862                 continue;
863             }
864 
865             // Check if the protocol is not repeated in the passed array
866             if (bl.contains(p)) {
867                 continue;
868             }
869 
870             // Check if list reach its max size
871             if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
872                 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
873                         ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
874                 break;
875             }
876 
877             // Now add the protocol to the list
878             bl.add(p);
879         }
880 
881         return bl.stream().mapToInt(Integer::intValue).toArray();
882     }
883 
884     // Returns seconds since device boot.
secondsSinceBoot()885     private int secondsSinceBoot() {
886         return (int) (mDependencies.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS);
887     }
888 
889     public static class InvalidRaException extends Exception {
InvalidRaException(String m)890         public InvalidRaException(String m) {
891             super(m);
892         }
893     }
894 
895     /**
896      *  Class to keep track of a section in a packet.
897      */
898     private static class PacketSection {
899         public enum Type {
900             MATCH,     // A field that should be matched (e.g., the router IP address).
901             LIFETIME,  // A lifetime. Not matched, and counts toward minimum RA lifetime if >= min.
902         }
903 
904         /** The type of section. */
905         public final Type type;
906         /** Offset into the packet at which this section begins. */
907         public final int start;
908         /** Length of this section in bytes. */
909         public final int length;
910         /** If this is a lifetime, the lifetime value. */
911         public final long lifetime;
912         /** If this is a lifetime, the value below which the lifetime is ignored */
913         public final int min;
914 
PacketSection(int start, int length, Type type, long lifetime, int min)915         PacketSection(int start, int length, Type type, long lifetime, int min) {
916             this.start = start;
917 
918             if (type == Type.LIFETIME && length != 2 && length != 4) {
919                 throw new IllegalArgumentException("LIFETIME section length must be 2 or 4 bytes");
920             }
921             this.length = length;
922             this.type = type;
923 
924             if (type == Type.MATCH && (lifetime != 0 || min != 0)) {
925                 throw new IllegalArgumentException("lifetime, min must be 0 for MATCH sections");
926             }
927             this.lifetime = lifetime;
928 
929             // It has already been asserted that min is 0 for MATCH sections.
930             if (min < 0) {
931                 throw new IllegalArgumentException("min must be >= 0 for LIFETIME sections");
932             }
933             this.min = min;
934         }
935 
936         @Override
toString()937         public String toString() {
938             if (type == Type.LIFETIME) {
939                 return String.format("%s: (%d, %d) %d %d", type, start, length, lifetime, min);
940             } else {
941                 return String.format("%s: (%d, %d)", type, start, length);
942             }
943         }
944     }
945 
946     // A class to hold information about an RA.
947     @VisibleForTesting
948     public class Ra {
949         // Note: mPacket's position() cannot be assumed to be reset.
950         private final ByteBuffer mPacket;
951 
952         // List of sections in the packet.
953         private final ArrayList<PacketSection> mPacketSections = new ArrayList<>();
954 
955         // Router lifetime in packet
956         private final int mRouterLifetime;
957         // Minimum valid lifetime of PIOs in packet, Long.MAX_VALUE means not seen.
958         private final long mMinPioValidLifetime;
959         // Minimum route lifetime of RIOs in packet, Long.MAX_VALUE means not seen.
960         private final long mMinRioRouteLifetime;
961         // Minimum lifetime of RDNSSs in packet, Long.MAX_VALUE means not seen.
962         private final long mMinRdnssLifetime;
963         // The time in seconds in which some of the information contained in this RA expires.
964         private final int mExpirationTime;
965         // When the packet was last captured, in seconds since Unix Epoch
966         private final int mLastSeen;
967 
968         // For debugging only. Offsets into the packet where PIOs are.
969         private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
970 
971         // For debugging only. Offsets into the packet where RDNSS options are.
972         private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
973 
974         // For debugging only. Offsets into the packet where RIO options are.
975         private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>();
976 
977         // For debugging only. Returns the hex representation of the last matching packet.
getLastMatchingPacket()978         String getLastMatchingPacket() {
979             return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
980                     false /* lowercase */);
981         }
982 
983         // For debugging only. Returns the string representation of the IPv6 address starting at
984         // position pos in the packet.
IPv6AddresstoString(int pos)985         private String IPv6AddresstoString(int pos) {
986             try {
987                 byte[] array = mPacket.array();
988                 // Can't just call copyOfRange() and see if it throws, because if it reads past the
989                 // end it pads with zeros instead of throwing.
990                 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
991                     return "???";
992                 }
993                 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
994                 InetAddress address = InetAddress.getByAddress(addressBytes);
995                 return address.getHostAddress();
996             } catch (UnsupportedOperationException e) {
997                 // array() failed. Cannot happen, mPacket is array-backed and read-write.
998                 return "???";
999             } catch (ClassCastException|UnknownHostException e) {
1000                 // Cannot happen.
1001                 return "???";
1002             }
1003         }
1004 
1005         // Can't be static because it's in a non-static inner class.
1006         // TODO: Make this static once RA is its own class.
prefixOptionToString(StringBuffer sb, int offset)1007         private void prefixOptionToString(StringBuffer sb, int offset) {
1008             String prefix = IPv6AddresstoString(offset + 16);
1009             int length = getUint8(mPacket, offset + 2);
1010             long valid = getUint32(mPacket, offset + 4);
1011             long preferred = getUint32(mPacket, offset + 8);
1012             sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
1013         }
1014 
rdnssOptionToString(StringBuffer sb, int offset)1015         private void rdnssOptionToString(StringBuffer sb, int offset) {
1016             int optLen = getUint8(mPacket, offset + 1) * 8;
1017             if (optLen < 24) return;  // Malformed or empty.
1018             long lifetime = getUint32(mPacket, offset + 4);
1019             int numServers = (optLen - 8) / 16;
1020             sb.append("DNS ").append(lifetime).append("s");
1021             for (int server = 0; server < numServers; server++) {
1022                 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
1023             }
1024             sb.append(" ");
1025         }
1026 
rioOptionToString(StringBuffer sb, int offset)1027         private void rioOptionToString(StringBuffer sb, int offset) {
1028             int optLen = getUint8(mPacket, offset + 1) * 8;
1029             if (optLen < 8 || optLen > 24) return;  // Malformed or empty.
1030             int prefixLen = getUint8(mPacket, offset + 2);
1031             long lifetime = getUint32(mPacket, offset + 4);
1032 
1033             // This read is variable length because the prefix can be 0, 8 or 16 bytes long.
1034             // We can't use any of the ByteBuffer#get methods here because they all start reading
1035             // from the buffer's current position.
1036             byte[] prefix = new byte[IPV6_ADDR_LEN];
1037             System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8);
1038             sb.append("RIO ").append(lifetime).append("s ");
1039             try {
1040                 InetAddress address = InetAddress.getByAddress(prefix);
1041                 sb.append(address.getHostAddress());
1042             } catch (UnknownHostException impossible) {
1043                 sb.append("???");
1044             }
1045             sb.append("/").append(prefixLen).append(" ");
1046         }
1047 
1048         @Override
toString()1049         public String toString() {
1050             try {
1051                 StringBuffer sb = new StringBuffer();
1052                 sb.append(String.format("RA %s -> %s %ds ",
1053                         IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
1054                         IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
1055                         getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
1056                 for (int i: mPrefixOptionOffsets) {
1057                     prefixOptionToString(sb, i);
1058                 }
1059                 for (int i: mRdnssOptionOffsets) {
1060                     rdnssOptionToString(sb, i);
1061                 }
1062                 for (int i: mRioOptionOffsets) {
1063                     rioOptionToString(sb, i);
1064                 }
1065                 return sb.toString();
1066             } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
1067                 return "<Malformed RA>";
1068             }
1069         }
1070 
1071         /**
1072          * Add a packet section that should be matched, starting from the current position.
1073          * @param length the length of the section
1074          */
addMatchSection(int length)1075         private void addMatchSection(int length) {
1076             // Don't generate JNEBS instruction for 0 bytes as they will fail the
1077             // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is
1078             // the number of bytes to compare) and immediately pass the packet.
1079             // The code does not attempt to generate such matches, but add a safety
1080             // check to prevent doing so in the presence of bugs or malformed or
1081             // truncated packets.
1082             if (length == 0) return;
1083 
1084             // we need to add a MATCH section 'from, length, MATCH, 0, 0'
1085             int from = mPacket.position();
1086 
1087             // if possible try to increase the length of the previous match section
1088             int lastIdx = mPacketSections.size() - 1;
1089             if (lastIdx >= 0) {  // there had to be a previous section
1090                 PacketSection prev = mPacketSections.get(lastIdx);
1091                 if (prev.type == PacketSection.Type.MATCH) {  // of type match
1092                     if (prev.start + prev.length == from) {  // ending where we start
1093                         from -= prev.length;
1094                         length += prev.length;
1095                         mPacketSections.remove(lastIdx);
1096                     }
1097                 }
1098             }
1099 
1100             mPacketSections.add(new PacketSection(from, length, PacketSection.Type.MATCH, 0, 0));
1101             mPacket.position(from + length);
1102         }
1103 
1104         /**
1105          * Add a packet section that should be matched, starting from the current position.
1106          * @param end the offset in the packet before which the section ends
1107          */
addMatchUntil(int end)1108         private void addMatchUntil(int end) {
1109             addMatchSection(end - mPacket.position());
1110         }
1111 
1112         /**
1113          * Add a packet section that should be ignored, starting from the current position.
1114          * @param length the length of the section in bytes
1115          */
addIgnoreSection(int length)1116         private void addIgnoreSection(int length) {
1117             mPacket.position(mPacket.position() + length);
1118         }
1119 
1120         /**
1121          * Add a packet section that represents a lifetime, starting from the current position.
1122          * @param length the length of the section in bytes
1123          * @param lifetime the lifetime
1124          * @param min the minimum acceptable lifetime
1125          */
addLifetimeSection(int length, long lifetime, int min)1126         private void addLifetimeSection(int length, long lifetime, int min) {
1127             mPacketSections.add(
1128                     new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME,
1129                             lifetime, min));
1130             mPacket.position(mPacket.position() + length);
1131         }
1132 
1133         /**
1134          * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option
1135          * @param optionLength the length of the option in bytes
1136          * @param min the minimum acceptable lifetime
1137          * @param isRdnss true iff this is an RDNSS option
1138          */
add4ByteLifetimeOption(int optionLength, int min, boolean isRdnss)1139         private long add4ByteLifetimeOption(int optionLength, int min, boolean isRdnss) {
1140             if (isRdnss) {
1141                 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET - 2);
1142                 addIgnoreSection(2);  // reserved, but observed non-zero
1143             } else {
1144                 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET);
1145             }
1146             final long lifetime = getUint32(mPacket, mPacket.position());
1147             addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, lifetime, min);
1148             addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET
1149                     - ICMP6_4_BYTE_LIFETIME_LEN);
1150             return lifetime;
1151         }
1152 
1153         // Note that this parses RA and may throw InvalidRaException (from
1154         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
1155         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
1156         // specifications.
1157         @VisibleForTesting
Ra(byte[] packet, int length)1158         public Ra(byte[] packet, int length) throws InvalidRaException {
1159             if (length < ICMP6_RA_OPTION_OFFSET) {
1160                 throw new InvalidRaException("Not an ICMP6 router advertisement: too short");
1161             }
1162 
1163             mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
1164             mLastSeen = secondsSinceBoot();
1165 
1166             // Check packet in case a packet arrives before we attach RA filter
1167             // to our packet socket. b/29586253
1168             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
1169                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
1170                     getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
1171                 throw new InvalidRaException("Not an ICMP6 router advertisement");
1172             }
1173 
1174             // Ignore destination MAC address.
1175             addIgnoreSection(6 /* Size of MAC address */);
1176 
1177             // Ignore the flow label and low 4 bits of traffic class.
1178             addMatchUntil(IPV6_FLOW_LABEL_OFFSET);
1179             addIgnoreSection(IPV6_FLOW_LABEL_LEN);
1180 
1181             // Ignore IPv6 destination address.
1182             addMatchUntil(IPV6_DEST_ADDR_OFFSET);
1183             addIgnoreSection(IPV6_ADDR_LEN);
1184 
1185             // Ignore checksum.
1186             addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET);
1187             addIgnoreSection(ICMP6_RA_CHECKSUM_LEN);
1188 
1189             // Parse router lifetime
1190             addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET);
1191             mRouterLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET);
1192             addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, mRouterLifetime, mAcceptRaMinLft);
1193             if (mRouterLifetime == 0) mNumZeroLifetimeRas++;
1194 
1195             // Add remaining fields (reachable time and retransmission timer) to match section.
1196             addMatchUntil(ICMP6_RA_OPTION_OFFSET);
1197 
1198             long minPioValidLifetime = Long.MAX_VALUE;
1199             long minRioRouteLifetime = Long.MAX_VALUE;
1200             long minRdnssLifetime = Long.MAX_VALUE;
1201 
1202             while (mPacket.hasRemaining()) {
1203                 final int position = mPacket.position();
1204                 final int optionType = getUint8(mPacket, position);
1205                 final int optionLength = getUint8(mPacket, position + 1) * 8;
1206                 if (optionLength <= 0) {
1207                     throw new InvalidRaException(String.format(
1208                         "Invalid option length opt=%d len=%d", optionType, optionLength));
1209                 }
1210 
1211                 long lifetime;
1212                 switch (optionType) {
1213                     case ICMP6_PREFIX_OPTION_TYPE:
1214                         mPrefixOptionOffsets.add(position);
1215 
1216                         // Parse valid lifetime
1217                         addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
1218                         lifetime = getUint32(mPacket, mPacket.position());
1219                         addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
1220                                 lifetime, mAcceptRaMinLft);
1221                         minPioValidLifetime = getMinForPositiveValue(
1222                                 minPioValidLifetime, lifetime);
1223                         if (lifetime == 0) mNumZeroLifetimeRas++;
1224 
1225                         // Parse preferred lifetime
1226                         lifetime = getUint32(mPacket, mPacket.position());
1227                         // The PIO preferred lifetime is not affected by accept_ra_min_lft and
1228                         // therefore does not have a minimum.
1229                         addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN,
1230                                 lifetime, 0 /* min lifetime */);
1231 
1232                         addMatchSection(4);       // Reserved bytes
1233                         addMatchSection(IPV6_ADDR_LEN);  // The prefix itself
1234                         break;
1235                     // These three options have the same lifetime offset and size, and
1236                     // are processed with the same specialized add4ByteLifetimeOption:
1237                     case ICMP6_RDNSS_OPTION_TYPE:
1238                         mRdnssOptionOffsets.add(position);
1239                         lifetime = add4ByteLifetimeOption(optionLength, mMinRdnssLifetimeSec, true);
1240                         minRdnssLifetime = getMinForPositiveValue(minRdnssLifetime, lifetime);
1241                         if (lifetime == 0) mNumZeroLifetimeRas++;
1242                         break;
1243                     case ICMP6_ROUTE_INFO_OPTION_TYPE:
1244                         mRioOptionOffsets.add(position);
1245                         lifetime = add4ByteLifetimeOption(optionLength, mAcceptRaMinLft, false);
1246                         minRioRouteLifetime = getMinForPositiveValue(
1247                                 minRioRouteLifetime, lifetime);
1248                         if (lifetime == 0) mNumZeroLifetimeRas++;
1249                         break;
1250                     case ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE:
1251                     case ICMP6_MTU_OPTION_TYPE:
1252                     case ICMP6_PREF64_OPTION_TYPE:
1253                     case ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE:
1254                         addMatchSection(optionLength);
1255                         break;
1256                     case ICMP6_CAPTIVE_PORTAL_OPTION_TYPE: // unlikely to ever change.
1257                     case ICMP6_DNSSL_OPTION_TYPE: // currently unsupported in userspace.
1258                     default:
1259                         // RFC4861 section 4.2 dictates we ignore unknown options for forwards
1260                         // compatibility.
1261                         // However, make sure the option's type and length match.
1262                         addMatchSection(2); // option type & length
1263                         // optionLength is guaranteed to be >= 8.
1264                         addIgnoreSection(optionLength - 2);
1265                         break;
1266                 }
1267             }
1268 
1269             mMinPioValidLifetime = minPioValidLifetime;
1270             mMinRioRouteLifetime = minRioRouteLifetime;
1271             mMinRdnssLifetime = minRdnssLifetime;
1272             mExpirationTime = getExpirationTime();
1273         }
1274 
1275         public enum MatchType {
1276             NO_MATCH, // the RAs do not match
1277             MATCH_PASS, // the RAS match, and the APF program would pass.
1278             MATCH_DROP, // the RAs match, but the APF program would drop.
1279         }
1280 
1281         // Considering only the MATCH sections, does {@code packet} match this RA?
matches(Ra newRa)1282         MatchType matches(Ra newRa) {
1283             // Does their size match?
1284             if (newRa.mPacket.capacity() != mPacket.capacity()) return MatchType.NO_MATCH;
1285 
1286             // If the filter has expired, it cannot match the new RA.
1287             if (getRemainingFilterLft(secondsSinceBoot()) <= 0) return MatchType.NO_MATCH;
1288 
1289             // Check if all MATCH sections are byte-identical.
1290             final byte[] newPacket = newRa.mPacket.array();
1291             final byte[] oldPacket = mPacket.array();
1292             for (PacketSection section : mPacketSections) {
1293                 if (section.type != PacketSection.Type.MATCH) continue;
1294                 for (int i = section.start; i < (section.start + section.length); i++) {
1295                     if (newPacket[i] != oldPacket[i]) return MatchType.NO_MATCH;
1296                 }
1297             }
1298 
1299             // Apply APF lifetime matching to LIFETIME sections and decide whether a packet should
1300             // be processed (MATCH_PASS) or ignored (MATCH_DROP). This logic is needed to
1301             // consistently process / ignore packets no matter the current state of the APF program.
1302             // Note that userspace has no control (or knowledge) over when the APF program is
1303             // running.
1304             for (PacketSection section : mPacketSections) {
1305                 if (section.type != PacketSection.Type.LIFETIME) continue;
1306 
1307                 // the lifetime of the new RA.
1308                 long lft = 0;
1309                 switch (section.length) {
1310                     // section.length is guaranteed to be 2 or 4.
1311                     case 2: lft = getUint16(newRa.mPacket, section.start); break;
1312                     case 4: lft = getUint32(newRa.mPacket, section.start); break;
1313                 }
1314 
1315                 // WARNING: keep this in sync with Ra#generateFilter()!
1316                 if (section.lifetime == 0) {
1317                     // Case 1) old lft == 0
1318                     if (section.min > 0) {
1319                         // a) in the presence of a min value.
1320                         // if lft >= min -> PASS
1321                         // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1322                         if (lft >= section.min) return MatchType.MATCH_PASS;
1323                     } else {
1324                         // b) if min is 0 / there is no min value.
1325                         // if lft > 0 -> PASS
1326                         // gen.addJumpIfR0GreaterThan(0, nextFilterLabel);
1327                         if (lft > 0) return MatchType.MATCH_PASS;
1328                     }
1329                 } else if (section.min == 0) {
1330                     // Case 2b) section is not affected by any minimum.
1331                     //
1332                     // if lft < (oldLft + 2) // 3 -> PASS
1333                     // if lft > oldLft            -> PASS
1334                     // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1335                     //        nextFilterLabel);
1336                     if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS;
1337                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1338                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1339                 } else if (section.lifetime < section.min) {
1340                     // Case 2a) 0 < old lft < min
1341                     //
1342                     // if lft == 0   -> PASS
1343                     // if lft >= min -> PASS
1344                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1345                     if (lft == 0) return MatchType.MATCH_PASS;
1346                     // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1347                     if (lft >= section.min) return MatchType.MATCH_PASS;
1348                 } else if (section.lifetime <= 3 * (long) section.min) {
1349                     // Case 3a) min <= old lft <= 3 * min
1350                     // Note that:
1351                     // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min"
1352                     //
1353                     // Essentially, in this range there is no "renumbering support", as the
1354                     // renumbering constant of 1/3 * old lft is smaller than the minimum
1355                     // lifetime accepted by the kernel / userspace.
1356                     //
1357                     // if lft == 0     -> PASS
1358                     // if lft > oldLft -> PASS
1359                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1360                     if (lft == 0) return MatchType.MATCH_PASS;
1361                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1362                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1363                 } else {
1364                     // Case 4a) otherwise
1365                     //
1366                     // if lft == 0                  -> PASS
1367                     // if lft < min                 -> CONTINUE
1368                     // if lft < (oldLft + 2) // 3   -> PASS
1369                     // if lft > oldLft              -> PASS
1370                     // gen.addJumpIfR0Equals(0, nextFilterLabel);
1371                     if (lft == 0) return MatchType.MATCH_PASS;
1372                     // gen.addJumpIfR0LessThan(section.min, continueLabel);
1373                     if (lft < section.min) continue;
1374                     // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1375                     //         nextFilterLabel);
1376                     if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS;
1377                     // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1378                     if (lft > section.lifetime) return MatchType.MATCH_PASS;
1379                 }
1380             }
1381 
1382             return MatchType.MATCH_DROP;
1383         }
1384 
1385         // Get the number of seconds in which some of the information contained in this RA expires.
getExpirationTime()1386         private int getExpirationTime() {
1387             // While technically most lifetimes in the RA are u32s, as far as the RA filter is
1388             // concerned, INT_MAX is still a *much* longer lifetime than any filter would ever
1389             // reasonably be active for.
1390             // Clamp expirationTime at INT_MAX.
1391             int expirationTime = Integer.MAX_VALUE;
1392             for (PacketSection section : mPacketSections) {
1393                 if (section.type != PacketSection.Type.LIFETIME) {
1394                     continue;
1395                 }
1396                 // Ignore lifetimes below section.min and always ignore 0 lifetimes.
1397                 if (section.lifetime < Math.max(section.min, 1)) {
1398                     continue;
1399                 }
1400 
1401                 expirationTime = (int) Math.min(expirationTime, section.lifetime);
1402             }
1403             return expirationTime;
1404         }
1405 
1406         // Filter for a fraction of the expiration time and adjust for the age of the RA.
getRemainingFilterLft(int currentTimeSeconds)1407         int getRemainingFilterLft(int currentTimeSeconds) {
1408             int filterLifetime = ((mExpirationTime / FRACTION_OF_LIFETIME_TO_FILTER)
1409                     - (currentTimeSeconds - mLastSeen));
1410             filterLifetime = Math.max(0, filterLifetime);
1411             // Clamp filterLifetime to <= 65535, so it fits in 2 bytes.
1412             return Math.min(65535, filterLifetime);
1413         }
1414 
getRaProgramLengthOverEstimate(int timeSeconds)1415         int getRaProgramLengthOverEstimate(int timeSeconds) throws IllegalInstructionException {
1416             final ApfV4GeneratorBase<?> gen = createApfGenerator();
1417             generateFilter(gen, timeSeconds);
1418             return gen.programLengthOverEstimate() - gen.getBaseProgramSize();
1419         }
1420 
1421         // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
1422         // Jump to the next filter if packet doesn't match this RA.
generateFilter(ApfV4GeneratorBase<?> gen, int timeSeconds)1423         void generateFilter(ApfV4GeneratorBase<?> gen, int timeSeconds)
1424                 throws IllegalInstructionException {
1425             short nextFilterLabel = gen.getUniqueLabel();
1426             // Skip if packet is not the right size
1427             gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE);
1428             gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
1429             // Skip filter if expired
1430             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
1431             gen.addJumpIfR0GreaterThan(getRemainingFilterLft(timeSeconds), nextFilterLabel);
1432             for (PacketSection section : mPacketSections) {
1433                 // Generate code to match the packet bytes.
1434                 if (section.type == PacketSection.Type.MATCH) {
1435                     gen.addLoadImmediate(R0, section.start);
1436                     gen.addJumpIfBytesAtR0NotEqual(
1437                             Arrays.copyOfRange(mPacket.array(), section.start,
1438                                     section.start + section.length),
1439                             nextFilterLabel);
1440                 } else {
1441                     switch (section.length) {
1442                         // length asserted to be either 2 or 4 on PacketSection construction
1443                         case 2: gen.addLoad16intoR0(section.start); break;
1444                         case 4: gen.addLoad32intoR0(section.start); break;
1445                     }
1446 
1447                     // WARNING: keep this in sync with matches()!
1448                     // For more information on lifetime comparisons in the APF bytecode, see
1449                     // go/apf-ra-filter.
1450                     if (section.lifetime == 0) {
1451                         // Case 1) old lft == 0
1452                         if (section.min > 0) {
1453                             // a) in the presence of a min value.
1454                             // if lft >= min -> PASS
1455                             gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1456                         } else {
1457                             // b) if min is 0 / there is no min value.
1458                             // if lft > 0 -> PASS
1459                             gen.addJumpIfR0GreaterThan(0, nextFilterLabel);
1460                         }
1461                     } else if (section.min == 0) {
1462                         // Case 2b) section is not affected by any minimum.
1463                         //
1464                         // if lft < (oldLft + 2) // 3 -> PASS
1465                         // if lft > oldLft            -> PASS
1466                         gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1467                                 nextFilterLabel);
1468                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1469                     } else if (section.lifetime < section.min) {
1470                         // Case 2a) 0 < old lft < min
1471                         //
1472                         // if lft == 0   -> PASS
1473                         // if lft >= min -> PASS
1474                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1475                         gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel);
1476                     } else if (section.lifetime <= 3 * (long) section.min) {
1477                         // Case 3a) min <= old lft <= 3 * min
1478                         // Note that:
1479                         // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min"
1480                         //
1481                         // Essentially, in this range there is no "renumbering support", as the
1482                         // renumbering constant of 1/3 * old lft is smaller than the minimum
1483                         // lifetime accepted by the kernel / userspace.
1484                         //
1485                         // if lft == 0     -> PASS
1486                         // if lft > oldLft -> PASS
1487                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1488                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1489                     } else {
1490                         final short continueLabel = gen.getUniqueLabel();
1491                         // Case 4a) otherwise
1492                         //
1493                         // if lft == 0                  -> PASS
1494                         // if lft < min                 -> CONTINUE
1495                         // if lft < (oldLft + 2) // 3   -> PASS
1496                         // if lft > oldLft              -> PASS
1497                         gen.addJumpIfR0Equals(0, nextFilterLabel);
1498                         gen.addJumpIfR0LessThan(section.min, continueLabel);
1499                         gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3),
1500                                 nextFilterLabel);
1501                         gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel);
1502 
1503                         // CONTINUE
1504                         gen.defineLabel(continueLabel);
1505                     }
1506                 }
1507             }
1508             gen.addCountAndDrop(DROPPED_RA);
1509             gen.defineLabel(nextFilterLabel);
1510         }
1511     }
1512 
1513     // TODO: Refactor these subclasses to avoid so much repetition.
1514     private abstract static class KeepalivePacket {
1515         // Note that the offset starts from IP header.
1516         // These must be added ether header length when generating program.
1517         static final int IP_HEADER_OFFSET = 0;
1518         static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
1519 
1520         // Append a filter for this keepalive ack to {@code gen}.
1521         // Jump to drop if it matches the keepalive ack.
1522         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilter(ApfV4GeneratorBase<?> gen)1523         abstract void generateFilter(ApfV4GeneratorBase<?> gen)
1524                 throws IllegalInstructionException;
1525     }
1526 
1527     // A class to hold NAT-T keepalive ack information.
1528     private class NattKeepaliveResponse extends KeepalivePacket {
1529         static final int UDP_HEADER_LEN = 8;
1530 
1531         protected class NattKeepaliveResponseData {
1532             public final byte[] srcAddress;
1533             public final int srcPort;
1534             public final byte[] dstAddress;
1535             public final int dstPort;
1536 
NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1537             NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1538                 srcAddress = sentKeepalivePacket.dstAddress;
1539                 srcPort = sentKeepalivePacket.dstPort;
1540                 dstAddress = sentKeepalivePacket.srcAddress;
1541                 dstPort = sentKeepalivePacket.srcPort;
1542             }
1543         }
1544 
1545         protected final NattKeepaliveResponseData mPacket;
1546         protected final byte[] mSrcDstAddr;
1547         protected final byte[] mPortFingerprint;
1548         // NAT-T keepalive packet
1549         protected final byte[] mPayload = {(byte) 0xff};
1550 
NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1551         NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1552             mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
1553             mSrcDstAddr = CollectionUtils.concatArrays(mPacket.srcAddress, mPacket.dstAddress);
1554             mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
1555         }
1556 
generatePortFingerprint(int srcPort, int dstPort)1557         byte[] generatePortFingerprint(int srcPort, int dstPort) {
1558             final ByteBuffer fp = ByteBuffer.allocate(4);
1559             fp.order(ByteOrder.BIG_ENDIAN);
1560             fp.putShort((short) srcPort);
1561             fp.putShort((short) dstPort);
1562             return fp.array();
1563         }
1564 
1565         @Override
generateFilter(ApfV4GeneratorBase<?> gen)1566         void generateFilter(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException {
1567             final short nextFilterLabel = gen.getUniqueLabel();
1568 
1569             gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1570             gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel);
1571 
1572             // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
1573             // Check payload length is 1
1574             gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
1575             gen.addAdd(UDP_HEADER_LEN);
1576             gen.addSwap();
1577             gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET);
1578             gen.addNeg(R1);
1579             gen.addAddR1ToR0();
1580             gen.addJumpIfR0NotEquals(1, nextFilterLabel);
1581 
1582             // Check that the ports match
1583             gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE);
1584             gen.addAdd(ETH_HEADER_LEN);
1585             gen.addJumpIfBytesAtR0NotEqual(mPortFingerprint, nextFilterLabel);
1586 
1587             // Payload offset = R0 + UDP header length
1588             gen.addAdd(UDP_HEADER_LEN);
1589             gen.addJumpIfBytesAtR0NotEqual(mPayload, nextFilterLabel);
1590 
1591             gen.addCountAndDrop(DROPPED_IPV4_NATT_KEEPALIVE);
1592             gen.defineLabel(nextFilterLabel);
1593         }
1594 
1595         @Override
toString()1596         public String toString() {
1597             try {
1598                 return String.format("%s -> %s",
1599                         ConnectivityUtils.addressAndPortToString(
1600                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1601                         ConnectivityUtils.addressAndPortToString(
1602                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
1603             } catch (UnknownHostException e) {
1604                 return "Unknown host";
1605             }
1606         }
1607     }
1608 
1609     // A class to hold TCP keepalive ack information.
1610     private abstract static class TcpKeepaliveAck extends KeepalivePacket {
1611         protected static class TcpKeepaliveAckData {
1612             public final byte[] srcAddress;
1613             public final int srcPort;
1614             public final byte[] dstAddress;
1615             public final int dstPort;
1616             public final int seq;
1617             public final int ack;
1618 
1619             // Create the characteristics of the ack packet from the sent keepalive packet.
TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1620             TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1621                 srcAddress = sentKeepalivePacket.dstAddress;
1622                 srcPort = sentKeepalivePacket.dstPort;
1623                 dstAddress = sentKeepalivePacket.srcAddress;
1624                 dstPort = sentKeepalivePacket.srcPort;
1625                 seq = sentKeepalivePacket.ack;
1626                 ack = sentKeepalivePacket.seq + 1;
1627             }
1628         }
1629 
1630         protected final TcpKeepaliveAckData mPacket;
1631         protected final byte[] mSrcDstAddr;
1632         protected final byte[] mPortSeqAckFingerprint;
1633 
TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1634         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
1635             mPacket = packet;
1636             mSrcDstAddr = srcDstAddr;
1637             mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
1638                     mPacket.dstPort, mPacket.seq, mPacket.ack);
1639         }
1640 
generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1641         static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
1642             final ByteBuffer fp = ByteBuffer.allocate(12);
1643             fp.order(ByteOrder.BIG_ENDIAN);
1644             fp.putShort((short) srcPort);
1645             fp.putShort((short) dstPort);
1646             fp.putInt(seq);
1647             fp.putInt(ack);
1648             return fp.array();
1649         }
1650 
1651         @Override
toString()1652         public String toString() {
1653             try {
1654                 return String.format("%s -> %s , seq=%d, ack=%d",
1655                         ConnectivityUtils.addressAndPortToString(
1656                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1657                         ConnectivityUtils.addressAndPortToString(
1658                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
1659                         Integer.toUnsignedLong(mPacket.seq),
1660                         Integer.toUnsignedLong(mPacket.ack));
1661             } catch (UnknownHostException e) {
1662                 return "Unknown host";
1663             }
1664         }
1665 
1666         // Append a filter for this keepalive ack to {@code gen}.
1667         // Jump to drop if it matches the keepalive ack.
1668         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilter(ApfV4GeneratorBase<?> gen)1669         abstract void generateFilter(ApfV4GeneratorBase<?> gen)
1670                 throws IllegalInstructionException;
1671     }
1672 
1673     private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
1674 
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1675         TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1676             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1677         }
TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1678         TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
1679             super(packet, CollectionUtils.concatArrays(packet.srcAddress,
1680                     packet.dstAddress) /* srcDstAddr */);
1681         }
1682 
1683         @Override
generateFilter(ApfV4GeneratorBase<?> gen)1684         void generateFilter(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException {
1685             final short nextFilterLabel = gen.getUniqueLabel();
1686 
1687             gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1688             gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel);
1689 
1690             // Skip to the next filter if it's not zero-sized :
1691             // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
1692             // Load the IP header size into R1
1693             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1694             // Load the TCP header size into R0 (it's indexed by R1)
1695             gen.addLoad8R1IndexedIntoR0(ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
1696             // Size offset is in the top nibble, bottom nibble is reserved,
1697             // but not necessarily zero.  Thus we need to >> 4 then << 2,
1698             // achieve this by >> 2 and masking with 0b00111100.
1699             gen.addRightShift(2);
1700             gen.addAnd(0x3C);
1701             // R0 += R1 -> R0 contains TCP + IP headers length
1702             gen.addAddR1ToR0();
1703             // Load IPv4 total length
1704             gen.addSwap();
1705             gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET);
1706             gen.addNeg(R1);
1707             gen.addAddR1ToR0();
1708             gen.addJumpIfR0NotEquals(0, nextFilterLabel);
1709             // Add IPv4 header length
1710             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
1711             gen.addLoadImmediate(R0, ETH_HEADER_LEN);
1712             gen.addAddR1ToR0();
1713             gen.addJumpIfBytesAtR0NotEqual(mPortSeqAckFingerprint, nextFilterLabel);
1714 
1715             gen.addCountAndDrop(DROPPED_IPV4_KEEPALIVE_ACK);
1716             gen.defineLabel(nextFilterLabel);
1717         }
1718     }
1719 
1720     private static class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1721         TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1722             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1723         }
TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1724         TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
1725             super(packet, CollectionUtils.concatArrays(packet.srcAddress,
1726                     packet.dstAddress) /* srcDstAddr */);
1727         }
1728 
1729         @Override
generateFilter(ApfV4GeneratorBase<?> gen)1730         void generateFilter(ApfV4GeneratorBase<?> gen) {
1731             throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
1732         }
1733     }
1734 
1735     // Maximum number of RAs to filter for.
1736     private static final int MAX_RAS = 10;
1737 
1738     private final ArrayList<Ra> mRas = new ArrayList<>();
1739     private int mNumFilteredRas = 0;
1740     private final SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
1741 
1742     // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
1743     // see a refresh.  Using half the lifetime might be a good idea except for the fact that
1744     // packets may be dropped, so let's use 6.
1745     private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
1746 
1747     // When did we last install a filter program? In seconds since Unix Epoch.
1748     private int mLastTimeInstalledProgram;
1749     // How long should the last installed filter program live for? In seconds.
1750     private int mLastInstalledProgramMinLifetime;
1751 
1752     // For debugging only. The last program installed.
1753     private byte[] mLastInstalledProgram;
1754 
1755     /**
1756      * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
1757      * <p>
1758      * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
1759      * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
1760      * the opcodes to access the data buffer (LDDW and STDW).
1761      */
1762     @Nullable
1763     private byte[] mDataSnapshot;
1764 
1765     // How many times the program was updated since we started.
1766     private int mNumProgramUpdates = 0;
1767     // The maximum program size that updated since we started.
1768     private int mMaxProgramSize = 0;
1769     // The maximum number of distinct RAs
1770     private int mMaxDistinctRas = 0;
1771 
1772     /**
1773      * Generate filter code to process ARP packets. Execution of this code ends in either the
1774      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1775      * Preconditions:
1776      *  - Packet being filtered is ARP
1777      */
generateArpFilter(ApfV4GeneratorBase<?> gen)1778     private void generateArpFilter(ApfV4GeneratorBase<?> gen)
1779             throws IllegalInstructionException {
1780         // Here's a basic summary of what the ARP filter program does:
1781         //
1782         // if clat is enabled (and we're thus IPv6-only)
1783         //   drop
1784         // if not ARP IPv4
1785         //   drop
1786         // if unknown ARP opcode (ie. not reply or request)
1787         //   drop
1788         //
1789         // if ARP reply:
1790         //   if source ip is 0.0.0.0
1791         //     drop
1792         //   if unicast (or multicast)
1793         //     pass
1794         //   if interface has no IPv4 address
1795         //     if target ip is 0.0.0.0
1796         //       drop
1797         //   else
1798         //     if target ip is not the interface ip
1799         //       drop
1800         //   pass
1801         //
1802         // if ARP request:
1803         //   if interface has IPv4 address
1804         //     if target ip is not the interface ip
1805         //       drop
1806         //   pass
1807 
1808         // For IPv6 only network, drop all ARP packet.
1809         if (mHasClat) {
1810             gen.addCountAndDrop(DROPPED_ARP_V6_ONLY);
1811             return;
1812         }
1813 
1814         // Drop if not ARP IPv4.
1815         gen.addCountAndDropIfBytesAtOffsetNotEqual(ARP_HEADER_OFFSET, ARP_IPV4_HEADER,
1816                 DROPPED_ARP_NON_IPV4);
1817 
1818         final short checkArpRequest = gen.getUniqueLabel();
1819 
1820         gen.addLoad16intoR0(ARP_OPCODE_OFFSET);
1821         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkArpRequest); // Skip to arp request check.
1822         // Drop if unknown ARP opcode.
1823         gen.addCountAndDropIfR0NotEquals(ARP_OPCODE_REPLY, DROPPED_ARP_UNKNOWN);
1824 
1825         /*----------  Handle ARP Replies. ----------*/
1826 
1827         // Drop if ARP reply source IP is 0.0.0.0
1828         gen.addLoad32intoR0(ARP_SOURCE_IP_ADDRESS_OFFSET);
1829         gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, DROPPED_ARP_REPLY_SPA_NO_HOST);
1830 
1831         // Pass if non-broadcast reply.
1832         // This also accepts multicast arp, but we assume those don't exist.
1833         gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST,
1834                 PASSED_ARP_UNICAST_REPLY);
1835 
1836         // It is a broadcast reply.
1837         if (mIPv4Address == null) {
1838             // When there is no IPv4 address, drop GARP replies (b/29404209).
1839             gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET);
1840             gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, DROPPED_GARP_REPLY);
1841         } else {
1842             // When there is an IPv4 address, drop broadcast replies with a different target IPv4
1843             // address.
1844             gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET);
1845             gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), DROPPED_ARP_OTHER_HOST);
1846         }
1847         gen.addCountAndPass(PASSED_ARP_BROADCAST_REPLY);
1848 
1849         /*----------  Handle ARP Requests. ----------*/
1850 
1851         gen.defineLabel(checkArpRequest);
1852         if (mIPv4Address != null) {
1853             // When there is an IPv4 address, drop unicast/broadcast requests with a different
1854             // target IPv4 address.
1855             gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET);
1856             gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), DROPPED_ARP_OTHER_HOST);
1857 
1858             if (enableArpOffload()) {
1859                 ApfV6GeneratorBase<?> v6Gen = (ApfV6GeneratorBase<?>) gen;
1860                 // Ethernet requires that all packets be at least 60 bytes long
1861                 v6Gen.addAllocate(60)
1862                         .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN)
1863                         .addDataCopy(mHardwareAddress)
1864                         .addDataCopy(FIXED_ARP_REPLY_HEADER)
1865                         .addDataCopy(mHardwareAddress)
1866                         .addWrite32(mIPv4Address)
1867                         .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN)
1868                         .addPacketCopy(ARP_SOURCE_IP_ADDRESS_OFFSET, IPV4_ADDR_LEN)
1869                         .addLoadFromMemory(R0, MemorySlot.TX_BUFFER_OUTPUT_POINTER)
1870                         .addAdd(18)
1871                         .addStoreToMemory(MemorySlot.TX_BUFFER_OUTPUT_POINTER, R0)
1872                         .addTransmitWithoutChecksum()
1873                         .addCountAndDrop(DROPPED_ARP_REQUEST_REPLIED);
1874             }
1875         }
1876         // If we're not clat, and we don't have an ipv4 address, allow all ARP request to avoid
1877         // racing against DHCP.
1878         gen.addCountAndPass(PASSED_ARP_REQUEST);
1879     }
1880 
1881     /**
1882      * Generate filter code to reply and drop unicast ICMPv4 echo request.
1883      * <p>
1884      * On entry, we know it is IPv4 ethertype, but don't know anything else.
1885      * R0/R1 have nothing useful in them, and can be clobbered.
1886      */
generateUnicastIpv4PingOffload(ApfV6GeneratorBase<?> gen)1887     private void generateUnicastIpv4PingOffload(ApfV6GeneratorBase<?> gen)
1888             throws IllegalInstructionException {
1889 
1890         final short skipIpv4PingFilter = gen.getUniqueLabel();
1891         // Check 1) it's not a fragment. 2) it's ICMP.
1892         // If condition not match then skip the ping filter logic
1893         gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_ICMP, skipIpv4PingFilter);
1894 
1895         // Only offload unicast Ipv4 ping request for now.
1896         // While we could potentially support offloading multicast and broadcast ping requests in
1897         // the future, such packets will likely be dropped by multicast filters.
1898         // Since the device may have packet forwarding enabled, APF needs to pass any received
1899         // unicast IPv4 ping not destined for the device's IP address to the kernel.
1900         gen.addJumpIfBytesAtOffsetNotEqual(
1901                 ETH_DEST_ADDR_OFFSET, mHardwareAddress, skipIpv4PingFilter)
1902                 .addLoadImmediate(R0, IPV4_DEST_ADDR_OFFSET)
1903                 .addJumpIfBytesAtR0NotEqual(mIPv4Address, skipIpv4PingFilter);
1904 
1905         // Ignore ping packets with IPv4 options (header size != 20) as they are rare.
1906         // Pass them to the kernel to save bytecode space.
1907         gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE)
1908                 .addJumpIfR0NotEquals(IPV4_HEADER_MIN_LEN, skipIpv4PingFilter);
1909 
1910         // We need to check if the packet is sufficiently large to be a valid ICMP packet.
1911         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
1912                 .addCountAndDropIfR0LessThan(
1913                         ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN,
1914                         DROPPED_IPV4_ICMP_INVALID);
1915 
1916         // If it is not a ICMP echo request, then skip.
1917         gen.addLoad8intoR0(ICMP4_TYPE_NO_OPTIONS_OFFSET)
1918                 .addJumpIfR0NotEquals(ICMP_ECHO, skipIpv4PingFilter);
1919 
1920         final int defaultTtl = mDependencies.getIpv4DefaultTtl();
1921         // Construct the ICMP echo reply packet.
1922         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
1923                 .addAllocateR0()
1924                 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) // Dst MAC address
1925                 .addDataCopy(mHardwareAddress) // Src MAC address
1926                 // Reuse the following fields from the input packet:
1927                 // 2 bytes: EtherType
1928                 // 4 bytes: version, IHL, TOS, total length
1929                 // 4 bytes: identification, flags, fragment offset
1930                 .addPacketCopy(ETH_ETHERTYPE_OFFSET, 10)
1931                 // Ttl: default ttl, Protocol: IPPROTO_ICMP, checksum: 0
1932                 .addWrite32((defaultTtl << 24) | (IPPROTO_ICMP << 16))
1933                 .addWrite32(mIPv4Address) // Src ip
1934                 .addPacketCopy(IPV4_SRC_ADDR_OFFSET, IPV4_ADDR_LEN) // Dst ip
1935                 .addWrite32((ICMP_ECHOREPLY << 24)) // Type: echo reply, code: 0, checksum: 0
1936                 // Copy identifier, sequence number and ping payload
1937                 .addSub(ICMP4_CONTENT_NO_OPTIONS_OFFSET)
1938                 .addLoadImmediate(R1, ICMP4_CONTENT_NO_OPTIONS_OFFSET)
1939                 .addSwap() // Swaps R0 and R1, so they're the offset and length.
1940                 .addPacketCopyFromR0LenR1()
1941                 .addTransmitL4(
1942                         ETHER_HEADER_LEN, // ip_ofs
1943                         ICMP4_CHECKSUM_NO_OPTIONS_OFFSET, // csum_ofs
1944                         ICMP4_TYPE_NO_OPTIONS_OFFSET, // csum_start
1945                         0, // partial_sum
1946                         false // udp
1947                 )
1948                 .addCountAndDrop(DROPPED_IPV4_PING_REQUEST_REPLIED);
1949 
1950         gen.defineLabel(skipIpv4PingFilter);
1951     }
1952 
1953     /**
1954      * Generates filter code to handle IPv4 mDNS packets.
1955      * <p>
1956      * On entry, this filter knows it is processing an IPv4 packet. It will then process all IPv4
1957      * mDNS packets, either passing or dropping them. IPv4 non-mDNS packets are skipped.
1958      *
1959      * @param gen the APF generator to generate the filter code
1960      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
1961      */
generateIPv4MdnsFilter(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)1962     private void generateIPv4MdnsFilter(ApfV6GeneratorBase<?> gen,
1963             short labelCheckMdnsQueryPayload)
1964             throws IllegalInstructionException {
1965         final short skipMdnsFilter = gen.getUniqueLabel();
1966 
1967         // If the packet is too short to be a valid IPv4 mDNS packet, the filter is skipped.
1968         // For APF performance reasons, we check udp destination port before confirming it is
1969         // non-fragmented IPv4 udp packet. We proceed only if the destination port is 5353 (mDNS).
1970         // Otherwise, skip filtering.
1971         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
1972                 .addJumpIfR0LessThan(
1973                         ETH_HEADER_LEN + IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN,
1974                         skipMdnsFilter)
1975                 .addLoad16intoR0(IPV4_UDP_DESTINATION_PORT_NO_OPTIONS_OFFSET)
1976                 .addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter);
1977 
1978         // If the destination MAC address is not 01:00:5e:00:00:fb (the mDNS multicast MAC
1979         // address for IPv4 mDNS packet) or the device's MAC address, skip filtering.
1980         // We need to check both the mDNS multicast MAC address and the device's MAC address
1981         // because multicast to unicast conversion might have occurred.
1982         gen.addJumpIfBytesAtOffsetEqualsNoneOf(
1983                 ETH_DEST_ADDR_OFFSET,
1984                 List.of(mHardwareAddress, ETH_MULTICAST_MDNS_V4_MAC_ADDRESS),
1985                 skipMdnsFilter
1986         );
1987 
1988         // Ignore packets with IPv4 options (header size not equal to 20) as they are rare.
1989         gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE)
1990                 .addJumpIfR0NotEquals(IPV4_HEADER_MIN_LEN, skipMdnsFilter);
1991 
1992         // Skip filtering if the packet is not a non-fragmented IPv4 UDP packet.
1993         gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_UDP, skipMdnsFilter);
1994 
1995         // Skip filtering if the IPv4 destination address is not 224.0.0.251 (the mDNS multicast
1996         // address).
1997         // Some devices can use unicast queries for mDNS to improve performance and reliability.
1998         // These packets are not currently offloaded and will be passed by APF and handled
1999         // by NsdService.
2000         gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET)
2001                 .addJumpIfR0NotEquals(MDNS_IPV4_ADDR_IN_LONG, skipMdnsFilter);
2002 
2003         // We now know that the packet is an mDNS packet,
2004         // i.e., a non-fragmented IPv4 UDP packet destined for port 5353 with the expected
2005         // destination MAC and IP addresses.
2006 
2007         // If the packet contains questions, check the query payload. Otherwise, check the
2008         // reply payload.
2009         gen.addLoad16intoR0(IPV4_DNS_QDCOUNT_NO_OPTIONS_OFFSET)
2010                 // Set the UDP payload offset in R1 before potentially jumping to the payload
2011                 // check logic.
2012                 .addLoadImmediate(R1, IPV4_UDP_PAYLOAD_NO_OPTIONS_OFFSET)
2013                 .addJumpIfR0NotEquals(0, labelCheckMdnsQueryPayload);
2014 
2015         // TODO: check the reply payload.
2016         if (mMulticastFilter) {
2017             gen.addCountAndDrop(DROPPED_MDNS);
2018         } else {
2019             gen.addCountAndPass(PASSED_MDNS);
2020         }
2021 
2022         gen.defineLabel(skipMdnsFilter);
2023     }
2024 
2025     /**
2026      * Generate filter code to process IPv4 packets. Execution of this code ends in either the
2027      * DROP_LABEL or PASS_LABEL and does not fall off the end.
2028      * Preconditions:
2029      *  - Packet being filtered is IPv4
2030      *
2031      * @param gen the APF generator to generate the filter code
2032      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
2033      */
generateIPv4Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2034     private void generateIPv4Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)
2035             throws IllegalInstructionException {
2036         // Here's a basic summary of what the IPv4 filter program does:
2037         //
2038         // if the network is IPv6 only network:
2039         //   if the packet is fragmented:
2040         //     drop
2041         //   if the packet is a dhcp packet comes from server:
2042         //     pass
2043         //   else
2044         //     drop
2045         //
2046         // (APFv6+ specific logic)
2047         // if it's mDNS:
2048         //   if it's a query:
2049         //     if mNumOfMdnsRuleToOffload == -1:
2050         //       pass
2051         //     if the query matches one of the offload rules from idx [0, mNumOfMdnsRuleToOffload):
2052         //       transmit mDNS reply and drop
2053         //     else if query matches one of the rest of the offload rules:
2054         //       pass
2055         //     else if filtering multicast (i.e. multicast lock not held):
2056         //       drop
2057         //     else
2058         //       pass
2059         //   else:
2060         //     if filtering multicast (i.e. multicast lock not held):
2061         //       drop
2062         //     else
2063         //       pass
2064         //
2065         // (APFv6+ specific logic)
2066         // if it's IGMP:
2067         //   if payload length is invalid (less than 8 or equal to 9, 10, 11):
2068         //     drop
2069         //   if the packet is an IGMP report:
2070         //     drop
2071         //   if the packet is not an IGMP query:
2072         //     drop
2073         //   if the group_addr is not 0.0.0.0, then it is group specific query:
2074         //     pass
2075         //   ===== handle IGMPv1/v2/v3 general query =====
2076         //   if the IPv4 dst addr is not 224.0.0.1:
2077         //     drop
2078         //   if the packet length >= 12, then it is IGMPv3:
2079         //     transmit IGMPv3 report and drop
2080         //   else if the packet length == 8, then it is either IGMPv1 or IGMPv2:
2081         //     if the max_res_code == 0, then it is IGMPv1:
2082         //       pass
2083         //     else it is IGMPv2:
2084         //       transmit IGMPv2 reports (one report per group) and drop
2085         //
2086         // if filtering multicast (i.e. multicast lock not held):
2087         //   if it's DHCP destined to our MAC:
2088         //     pass
2089         //   if it's L2 broadcast:
2090         //     drop
2091         //   if it's IPv4 multicast:
2092         //     drop
2093         //   if it's IPv4 broadcast:
2094         //     drop
2095         //
2096         // if keepalive ack
2097         //   drop
2098         //
2099         // (APFv6+ specific logic) if it's unicast IPv4 ICMP echo request to our host:
2100         //    transmit echo reply and drop
2101         //
2102         // pass
2103 
2104         if (mHasClat) {
2105             // Check 1) it's not a fragment. 2) it's UDP.
2106             // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol
2107             gen.addLoad32intoR0(IPV4_FRAGMENT_OFFSET_OFFSET);
2108             // Mask out the reserved and don't fragment bits, plus the TTL field.
2109             // Because:
2110             //   IPV4_FRAGMENT_OFFSET_MASK = 0x1fff
2111             //   IPV4_FRAGMENT_MORE_FRAGS_MASK = 0x2000
2112             // hence this constant ends up being 0x3FFF00FF.
2113             // We want the more flag bit and offset to be 0 (ie. not a fragment),
2114             // so after this masking we end up with just the ip protocol (hopefully UDP).
2115             gen.addAnd((IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK) << 16 | 0xFF);
2116             gen.addCountAndDropIfR0NotEquals(IPPROTO_UDP, DROPPED_IPV4_NON_DHCP4);
2117             // Check it's addressed to DHCP client port.
2118             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
2119             gen.addLoad32R1IndexedIntoR0(TCP_UDP_SOURCE_PORT_OFFSET);
2120             gen.addCountAndDropIfR0NotEquals(DHCP_SERVER_PORT << 16 | DHCP_CLIENT_PORT,
2121                     DROPPED_IPV4_NON_DHCP4);
2122             gen.addCountAndPass(PASSED_IPV4_FROM_DHCPV4_SERVER);
2123             return;
2124         }
2125 
2126         if (enableMdns4Offload()) {
2127             generateIPv4MdnsFilter((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload);
2128         }
2129 
2130         if (enableIgmpOffload()) {
2131             generateIgmpFilter((ApfV6GeneratorBase<?>) gen);
2132         }
2133 
2134         if (mMulticastFilter) {
2135             final short skipDhcpv4Filter = gen.getUniqueLabel();
2136 
2137             // Pass DHCP addressed to us.
2138             // Check 1) it's not a fragment. 2) it's UDP.
2139             gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_UDP, skipDhcpv4Filter);
2140             // Check it's addressed to DHCP client port.
2141             gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
2142             gen.addLoad16R1IndexedIntoR0(TCP_UDP_DESTINATION_PORT_OFFSET);
2143             gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
2144             // Check it's DHCP to our MAC address.
2145             gen.addLoadImmediate(R0, DHCP_CLIENT_MAC_OFFSET);
2146             // NOTE: Relies on R1 containing IPv4 header offset.
2147             gen.addAddR1ToR0();
2148             gen.addJumpIfBytesAtR0NotEqual(mHardwareAddress, skipDhcpv4Filter);
2149             gen.addCountAndPass(PASSED_DHCP);
2150 
2151             // Drop all multicasts/broadcasts.
2152             gen.defineLabel(skipDhcpv4Filter);
2153 
2154             // If IPv4 destination address is in multicast range, drop.
2155             gen.addLoad8intoR0(IPV4_DEST_ADDR_OFFSET);
2156             // we just loaded a byte, so top 24 bits are zero, thus and'ing
2157             // with either one of 0xF0 and 0xFFFFFFF0 accomplishes the same thing,
2158             // we thus choose the one which encodes shorter
2159             gen.addAnd((gen instanceof ApfV4Generator) ? 0xF0 : 0xFFFFFFF0);
2160             gen.addCountAndDropIfR0Equals(0xe0, DROPPED_IPV4_MULTICAST);
2161 
2162             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
2163             gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET);
2164             gen.addCountAndDropIfR0Equals(IPV4_BROADCAST_ADDRESS, DROPPED_IPV4_BROADCAST_ADDR);
2165             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
2166                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
2167                 gen.addCountAndDropIfR0Equals(broadcastAddr, DROPPED_IPV4_BROADCAST_NET);
2168             }
2169         }
2170 
2171         // If any TCP keepalive filter matches, drop
2172         generateV4KeepaliveFilters(gen);
2173 
2174         // If any NAT-T keepalive filter matches, drop
2175         generateV4NattKeepaliveFilters(gen);
2176 
2177         // If TCP unicast on port 7, drop
2178         generateV4TcpPort7Filter(gen);
2179 
2180         if (enableIpv4PingOffload()) {
2181             generateUnicastIpv4PingOffload((ApfV6GeneratorBase<?>) gen);
2182         }
2183 
2184         if (mMulticastFilter) {
2185             // Otherwise, this is an IPv4 unicast, pass
2186             // If L2 broadcast packet, drop.
2187             // TODO: can we invert this condition to fall through to the common pass case below?
2188             gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST,
2189                     PASSED_IPV4_UNICAST);
2190             gen.addCountAndDrop(DROPPED_IPV4_L2_BROADCAST);
2191         }
2192 
2193         // Otherwise, pass
2194         gen.addCountAndPass(PASSED_IPV4);
2195     }
2196 
generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, int offset, short label)2197     private void generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto,
2198             int offset, short label) throws IllegalInstructionException {
2199         final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets,
2200                 filterType::isInstance);
2201 
2202         // If no keepalive packets of this type
2203         if (!haveKeepaliveResponses) return;
2204 
2205         // If not the right proto, skip keepalive filters
2206         gen.addLoad8intoR0(offset);
2207         gen.addJumpIfR0NotEquals(proto, label);
2208 
2209         // Drop Keepalive responses
2210         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
2211             final KeepalivePacket response = mKeepalivePackets.valueAt(i);
2212             if (filterType.isInstance(response)) response.generateFilter(gen);
2213         }
2214 
2215         gen.defineLabel(label);
2216     }
2217 
generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)2218     private void generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)
2219             throws IllegalInstructionException {
2220         generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
2221                 gen.getUniqueLabel());
2222     }
2223 
generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)2224     private void generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)
2225             throws IllegalInstructionException {
2226         generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
2227                 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, gen.getUniqueLabel());
2228     }
2229 
getSolicitedNodeMcastAddressSuffix( @onNull List<byte[]> ipv6Addresses)2230     private List<byte[]> getSolicitedNodeMcastAddressSuffix(
2231             @NonNull List<byte[]> ipv6Addresses) {
2232         final List<byte[]> suffixes = new ArrayList<>();
2233         for (byte[] addr: ipv6Addresses) {
2234             suffixes.add(Arrays.copyOfRange(addr, 13,  16));
2235         }
2236         return suffixes;
2237     }
2238 
getIpv6Addresses( boolean includeNonTentative, boolean includeTentative, boolean includeAnycast)2239     private List<byte[]> getIpv6Addresses(
2240             boolean includeNonTentative, boolean includeTentative, boolean includeAnycast) {
2241         final List<byte[]> addresses = new ArrayList<>();
2242         if (includeNonTentative) {
2243             for (Inet6Address addr : mIPv6NonTentativeAddresses) {
2244                 addresses.add(addr.getAddress());
2245             }
2246         }
2247 
2248         if (includeTentative) {
2249             for (Inet6Address addr : mIPv6TentativeAddresses) {
2250                 addresses.add(addr.getAddress());
2251             }
2252         }
2253 
2254         if (includeAnycast) {
2255             addresses.addAll(mDependencies.getAnycast6Addresses(mInterfaceParams.name));
2256         }
2257         return addresses;
2258     }
2259 
getKnownMacAddresses()2260     private List<byte[]> getKnownMacAddresses() {
2261         final List<byte[]> addresses = new ArrayList<>();
2262         addresses.addAll(mDependencies.getEtherMulticastAddresses(mInterfaceParams.name));
2263         addresses.add(mHardwareAddress);
2264         addresses.add(ETHER_BROADCAST);
2265         return addresses;
2266     }
2267 
2268     /**
2269      * Generate allocate and transmit code to send ICMPv6 non-DAD NA packets.
2270      */
generateNonDadNaTransmit(ApfV6GeneratorBase<?> gen)2271     private void generateNonDadNaTransmit(ApfV6GeneratorBase<?> gen)
2272             throws IllegalInstructionException {
2273         final int ipv6PayloadLen = ICMPV6_NA_HEADER_LEN + ICMPV6_ND_OPTION_TLLA_LEN;
2274         final int pktLen = ETH_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLen;
2275 
2276         gen.addAllocate(pktLen);
2277 
2278         // Ethernet Header
2279         gen.addPacketCopy(ICMP6_NS_OPTION_TYPE_OFFSET + 2, ETHER_ADDR_LEN)  // dst MAC address
2280                 .addDataCopy(mHardwareAddress)  // src MAC address
2281                 .addWriteU16(ETH_P_IPV6);  // IPv6 type
2282 
2283         int tclass = mDependencies.getNdTrafficClass(mInterfaceParams.name);
2284         int vtf = (0x60000000 | (tclass << 20));
2285         // IPv6 header
2286         gen.addWrite32(vtf)  // IPv6 Header: version, traffic class, flowlabel
2287                 // payload length (2 bytes) | next header: ICMPv6 (1 byte) | hop limit (1 byte)
2288                 .addWrite32((ipv6PayloadLen << 16) | ((IPPROTO_ICMPV6 << 8) | 255))
2289                 // target ip is guaranteed to be non-tentative as we already check before
2290                 // we call transmit, but the link local ip can potentially be tentative.
2291                 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN)  // src ip
2292                 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN);  // dst ip
2293 
2294         // ICMPv6 header and payload
2295         // ICMPv6 type: NA (1 byte) | code: 0 (1 byte) | checksum: set to payload size (2 bytes)
2296         gen.addWrite32((ICMPV6_NEIGHBOR_ADVERTISEMENT << 24) | ipv6PayloadLen)
2297                 // Always set Router flag to prevent host deleting routes point at the router
2298                 // Always set Override flag to update neighbor's cache
2299                 // Solicited flag set to 1 if non DAD, refer to RFC4861#7.2.4
2300                 .addWrite32(0xe0000000) // flags: R=1, S=1, O=1
2301                 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // target address
2302                 // lla option: type (1 byte) | lla option: length (1 byte)
2303                 .addWriteU16((ICMPV6_ND_OPTION_TLLA << 8) | 1)
2304                 .addDataCopy(mHardwareAddress);  // lla option: link layer address
2305 
2306         gen.addTransmitL4(
2307                 ETHER_HEADER_LEN,   // ip_ofs
2308                 ICMP6_CHECKSUM_OFFSET,  // csum_ofs
2309                 IPV6_SRC_ADDR_OFFSET,   // csum_start
2310                 IPPROTO_ICMPV6, // partial_sum
2311                 false   // udp
2312         );
2313     }
2314 
generateNsFilter(ApfV6GeneratorBase<?> v6Gen)2315     private void generateNsFilter(ApfV6GeneratorBase<?> v6Gen)
2316             throws IllegalInstructionException {
2317         final List<byte[]> allIPv6Addrs = getIpv6Addresses(
2318                 true /* includeNonTentative */,
2319                 true /* includeTentative */,
2320                 true /* includeAnycast */);
2321         if (allIPv6Addrs.isEmpty()) {
2322             // If there is no IPv6 link local address, allow all NS packets to avoid racing
2323             // against RS.
2324             v6Gen.addCountAndPass(PASSED_IPV6_ICMP);
2325             return;
2326         }
2327 
2328         // Warning: APF program may temporarily filter NS packets targeted for anycast addresses
2329         // used by processes other than clatd. This is because APF cannot reliably detect signal
2330         // on when IPV6_{JOIN,LEAVE}_ANYCAST is triggered.
2331         final List<byte[]> allMACs = getKnownMacAddresses();
2332         v6Gen.addCountAndDropIfBytesAtOffsetEqualsNoneOf(ETH_DEST_ADDR_OFFSET, allMACs,
2333                 DROPPED_IPV6_NS_OTHER_HOST);
2334 
2335         // Dst IPv6 address check:
2336         final List<byte[]> allSuffixes = getSolicitedNodeMcastAddressSuffix(allIPv6Addrs);
2337         final short notIpV6SolicitedNodeMcast = v6Gen.getUniqueLabel();
2338         final short endOfIpV6DstCheck = v6Gen.getUniqueLabel();
2339         v6Gen.addJumpIfBytesAtOffsetNotEqual(
2340                 IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODES_PREFIX, notIpV6SolicitedNodeMcast)
2341                 .addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET + 13)
2342                 .addCountAndDropIfBytesAtR0EqualsNoneOf(allSuffixes, DROPPED_IPV6_NS_OTHER_HOST)
2343                 .addJump(endOfIpV6DstCheck)
2344                 .defineLabel(notIpV6SolicitedNodeMcast)
2345                 .addCountAndDropIfBytesAtOffsetEqualsNoneOf(
2346                         IPV6_DEST_ADDR_OFFSET, allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST)
2347                 .defineLabel(endOfIpV6DstCheck);
2348 
2349         // Hop limit not 255, NS requires hop limit to be 255 -> drop
2350         v6Gen.addLoad8intoR0(IPV6_HOP_LIMIT_OFFSET)
2351                 .addCountAndDropIfR0NotEquals(255, DROPPED_IPV6_NS_INVALID);
2352 
2353         // payload length < 24 (8 bytes ICMP6 header + 16 bytes target address) -> drop
2354         v6Gen.addLoad16intoR0(IPV6_PAYLOAD_LEN_OFFSET)
2355                 .addCountAndDropIfR0LessThan(24, DROPPED_IPV6_NS_INVALID);
2356 
2357         // ICMPv6 code not 0 -> drop
2358         v6Gen.addLoad8intoR0(ICMP6_CODE_OFFSET)
2359                 .addCountAndDropIfR0NotEquals(0, DROPPED_IPV6_NS_INVALID);
2360 
2361         // target address (ICMPv6 NS payload)
2362         //   1) is one of tentative addresses -> pass
2363         //   2) is none of {non-tentative, anycast} addresses -> drop
2364         final List<byte[]> tentativeIPv6Addrs = getIpv6Addresses(
2365                 false, /* includeNonTentative */
2366                 true, /* includeTentative */
2367                 false /* includeAnycast */
2368         );
2369 
2370         if (!tentativeIPv6Addrs.isEmpty()) {
2371             v6Gen.addCountAndPassIfBytesAtOffsetEqualsAnyOf(
2372                     ICMP6_NS_TARGET_IP_OFFSET, tentativeIPv6Addrs, PASSED_IPV6_ICMP);
2373         }
2374 
2375         final List<byte[]> nonTentativeIpv6Addrs = getIpv6Addresses(
2376                 true, /* includeNonTentative */
2377                 false, /* includeTentative */
2378                 true /* includeAnycast */
2379         );
2380         if (nonTentativeIpv6Addrs.isEmpty()) {
2381             v6Gen.addCountAndDrop(DROPPED_IPV6_NS_OTHER_HOST);
2382             return;
2383         }
2384         v6Gen.addCountAndDropIfBytesAtOffsetEqualsNoneOf(
2385                 ICMP6_NS_TARGET_IP_OFFSET, nonTentativeIpv6Addrs, DROPPED_IPV6_NS_OTHER_HOST);
2386 
2387         // if source ip is unspecified (::), it's DAD request -> pass
2388         v6Gen.addCountAndPassIfBytesAtOffsetEqual(
2389                 IPV6_SRC_ADDR_OFFSET, IPV6_UNSPECIFIED_ADDRESS, PASSED_IPV6_ICMP);
2390 
2391         // Only offload NUD/Address resolution packets that have SLLA as the their first option.
2392         // For option-less NUD packets or NUD/Address resolution packets where
2393         // the first option is not SLLA, pass them to the kernel for handling.
2394         // if payload len < 32 -> pass
2395         v6Gen.addLoad16intoR0(IPV6_PAYLOAD_LEN_OFFSET)
2396                 .addCountAndPassIfR0LessThan(32, PASSED_IPV6_ICMP);
2397 
2398         // if the first option is not SLLA -> pass
2399         // 0                   1                   2                   3
2400         // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2401         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2402         // |     Type      |    Length     |Link-Layer Addr  |
2403         // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2404         v6Gen.addLoad8intoR0(ICMP6_NS_OPTION_TYPE_OFFSET)
2405                 .addCountAndPassIfR0NotEquals(ICMPV6_ND_OPTION_SLLA, PASSED_IPV6_ICMP);
2406 
2407         // Src IPv6 address check:
2408         // if multicast address (FF::/8) or loopback address (00::/8) -> drop
2409         v6Gen.addLoad8intoR0(IPV6_SRC_ADDR_OFFSET)
2410                 .addCountAndDropIfR0IsOneOf(Set.of(0L, 0xffL), DROPPED_IPV6_NS_INVALID);
2411 
2412         // if multicast MAC in SLLA option -> drop
2413         v6Gen.addLoad8intoR0(ICMP6_NS_OPTION_TYPE_OFFSET + 2)
2414                 .addCountAndDropIfR0AnyBitsSet(1, DROPPED_IPV6_NS_INVALID);
2415         generateNonDadNaTransmit(v6Gen);
2416         v6Gen.addCountAndDrop(DROPPED_IPV6_NS_REPLIED_NON_DAD);
2417     }
2418 
2419     /**
2420      * Generates filter code to handle IPv6 mDNS packets.
2421      * <p>
2422      * On entry, this filter knows it is processing an IPv6 packet. It will then process all IPv6
2423      * mDNS packets, either passing or dropping them. IPv6 non-mDNS packets are skipped.
2424      *
2425      * @param gen the APF generator to generate the filter code
2426      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
2427      */
generateIPv6MdnsFilter(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2428     private void generateIPv6MdnsFilter(ApfV6GeneratorBase<?> gen,
2429             short labelCheckMdnsQueryPayload) throws IllegalInstructionException {
2430         final short skipMdnsFilter = gen.getUniqueLabel();
2431 
2432         // If the packet is too short to be a valid IPv6 mDNS packet, the filter is skipped.
2433         // For APF performance reasons, we check udp destination port before confirming it is IPv6
2434         // udp packet. We proceed only if the destination port is 5353 (mDNS). Otherwise, skip
2435         // filtering.
2436         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
2437                 .addJumpIfR0LessThan(
2438                         ETH_HEADER_LEN + IPV6_HEADER_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN,
2439                         skipMdnsFilter)
2440                 .addLoad16intoR0(IPV6_UDP_DESTINATION_PORT_OFFSET)
2441                 .addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter);
2442 
2443         // If the destination MAC address is not 33:33:00:00:00:fb (the mDNS multicast MAC
2444         // address for IPv6 mDNS packet) or the device's MAC address, skip filtering.
2445         // We need to check both the mDNS multicast MAC address and the device's MAC address
2446         // because multicast to unicast conversion might have occurred.
2447         gen.addJumpIfBytesAtOffsetEqualsNoneOf(
2448                 ETH_DEST_ADDR_OFFSET,
2449                 List.of(mHardwareAddress, ETH_MULTICAST_MDNS_V6_MAC_ADDRESS),
2450                 skipMdnsFilter
2451         );
2452 
2453         // Skip filtering if the packet is not an IPv6 UDP packet.
2454         gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET)
2455                 .addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter);
2456 
2457         // Skip filtering if the IPv6 destination address is not ff02::fb (the mDNS multicast
2458         // IPv6 address).
2459         // Some devices can use unicast queries for mDNS to improve performance and reliability.
2460         // These packets are not currently offloaded and will be passed by APF and handled
2461         // by NsdService.
2462         gen.addJumpIfBytesAtOffsetNotEqual(IPV6_DEST_ADDR_OFFSET, MDNS_IPV6_ADDR, skipMdnsFilter);
2463 
2464         // We now know that the packet is an mDNS packet,
2465         // i.e., an IPv6 UDP packet destined for port 5353 with the expected destination MAC and IP
2466         // addresses.
2467 
2468         // If the packet contains questions, check the query payload. Otherwise, check the
2469         // reply payload.
2470         gen.addLoad16intoR0(IPV6_DNS_QDCOUNT_OFFSET)
2471                 // Set the UDP payload offset in R1 before potentially jumping to the payload
2472                 // check logic.
2473                 .addLoadImmediate(R1, IPv6_UDP_PAYLOAD_OFFSET)
2474                 .addJumpIfR0NotEquals(0, labelCheckMdnsQueryPayload);
2475 
2476         // TODO: check the reply payload.
2477         if (mMulticastFilter) {
2478             gen.addCountAndDrop(DROPPED_MDNS);
2479         } else {
2480             gen.addCountAndPass(PASSED_MDNS);
2481         }
2482 
2483         gen.defineLabel(skipMdnsFilter);
2484     }
2485 
2486     /**
2487      * Generate filter code to reply and drop unicast ICMPv6 echo request.
2488      * <p>
2489      * On entry, we know it is IPv6 packet, but don't know anything else.
2490      * R0 contains the u8 IPv6 next header.
2491      * R1 contains nothing useful in it, and can be clobbered.
2492      */
generateUnicastIpv6PingOffload(ApfV6GeneratorBase<?> gen)2493     private void generateUnicastIpv6PingOffload(ApfV6GeneratorBase<?> gen)
2494             throws IllegalInstructionException {
2495 
2496         final short skipPing6Offload = gen.getUniqueLabel();
2497         gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, skipPing6Offload);
2498 
2499         gen.addLoad8intoR0(ICMP6_TYPE_OFFSET)
2500                 .addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipPing6Offload);
2501 
2502         // Only offload unicast ping6.
2503         // While we could potentially support offloading multicast and broadcast ping6 requests in
2504         // the future, such packets will likely be dropped by the multicast filter.
2505         // Since the device may have packet forwarding enabled, APF needs to pass any received
2506         // unicast ping6 not destined for the device's IP address to the kernel.
2507         final List<byte[]> nonTentativeIPv6Addrs = getIpv6Addresses(
2508                 true /* includeNonTentative */,
2509                 false /* includeTentative */,
2510                 false /* includeAnycast */);
2511         gen.addJumpIfBytesAtOffsetNotEqual(
2512                 ETHER_DST_ADDR_OFFSET, mHardwareAddress, skipPing6Offload)
2513                 .addJumpIfBytesAtOffsetEqualsNoneOf(
2514                         IPV6_DEST_ADDR_OFFSET, nonTentativeIPv6Addrs, skipPing6Offload);
2515 
2516         // We need to check if the packet is sufficiently large to be a valid ICMPv6 echo packet.
2517         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
2518                 .addCountAndDropIfR0LessThan(
2519                         ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_ECHO_REQUEST_HEADER_LEN,
2520                         DROPPED_IPV6_ICMP6_ECHO_REQUEST_INVALID);
2521 
2522         int hopLimit = mDependencies.getIpv6DefaultHopLimit(mInterfaceParams.name);
2523         // Construct the ICMPv6 echo reply packet.
2524         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
2525                 .addAllocateR0()
2526                 // Eth header
2527                 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) // Dst MAC address
2528                 .addDataCopy(mHardwareAddress) // Src MAC address
2529                 // Reuse the following fields from input packet
2530                 //  2 byte: ethertype
2531                 //  4 bytes: version, traffic class, flowlabel
2532                 //  2 bytes: payload length
2533                 //  1 byte: next header
2534                 .addPacketCopy(ETH_ETHERTYPE_OFFSET, 9)
2535                 .addWriteU8(hopLimit)
2536                 .addPacketCopy(IPV6_DEST_ADDR_OFFSET, IPV6_ADDR_LEN) // Src ip
2537                 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN) // Dst ip
2538                 .addWriteU16((ICMP6_ECHO_REPLY << 8) | 0) // Type: echo reply, code: 0
2539                 // Checksum: initialized to the IPv6 payload length as a partial checksum. The final
2540                 // checksum will be calculated by the interpreter.
2541                 .addPacketCopy(IPV6_PAYLOAD_LEN_OFFSET, 2)
2542                 // Copy identifier, sequence number and ping payload
2543                 .addSub(ICMP6_CONTENT_OFFSET)
2544                 .addLoadImmediate(R1, ICMP6_CONTENT_OFFSET)
2545                 .addSwap() // Swaps R0 and R1, so they're the offset and length.
2546                 .addPacketCopyFromR0LenR1()
2547                 .addTransmitL4(
2548                         ETHER_HEADER_LEN, // ip_ofs
2549                         ICMP6_CHECKSUM_OFFSET, // csum_ofs
2550                         IPV6_SRC_ADDR_OFFSET, // csum_start
2551                         IPPROTO_ICMPV6, // partial_sum
2552                         false // udp
2553                 )
2554                 .addCountAndDrop(DROPPED_IPV6_ICMP6_ECHO_REQUEST_REPLIED);
2555 
2556         gen.defineLabel(skipPing6Offload);
2557     }
2558 
2559     /**
2560      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
2561      * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
2562      * Preconditions:
2563      *  - Packet being filtered is IPv6
2564      *
2565      * @param gen the APF generator to generate the filter code
2566      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
2567      */
generateIPv6Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2568     private void generateIPv6Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)
2569             throws IllegalInstructionException {
2570         // Here's a basic summary of what the IPv6 filter program does:
2571         //
2572         // if there is a HOPOPTS option present (e.g. MLD query)
2573         //   (APFv6+ specific logic)
2574         //   if MLD offload is enabled:
2575         //     if it is an MLDv1 report/done or MLDv2 report:
2576         //       drop
2577         //     if the payload length is invalid (25, 26, 27):
2578         //       drop
2579         //     if the IPv6 src addr is not link-local address:
2580         //       drop
2581         //     if the IPv6 hop limit is not 1:
2582         //       drop
2583         //     if it is an multicast address specific query (the MLD multicast address is not "::"):
2584         //       pass
2585         //     if the IPv6 dst addr is not ff02::1:
2586         //       drop
2587         //     if it is an MLDv2 general query (payload length is not 24):
2588         //       transmit MLDv2 report and drop
2589         //     else it is an MLDv1 general query:
2590         //       transmit MLDv1 reports (one report per multicast group) and drop
2591         //   else
2592         //     pass (on APFv2+)
2593         //
2594         // (APFv6+ specific logic)
2595         // if it's mDNS:
2596         //   if it's a query:
2597         //     if mNumOfMdnsRuleToOffload == -1:
2598         //       pass
2599         //     if the query matches one of the offload rules from idx [0, mNumOfMdnsRuleToOffload):
2600         //       transmit mDNS reply and drop
2601         //     else if query matches one of the rest of the offload rules:
2602         //       pass
2603         //     else if filtering multicast (i.e. multicast lock not held):
2604         //       drop
2605         //     else
2606         //       pass
2607         //   else:
2608         //     if filtering multicast (i.e. multicast lock not held):
2609         //       drop
2610         //     else
2611         //       pass
2612         //
2613         // (APFv6+ specific logic) if it's unicast ICMPv6 echo request to our host:
2614         //    transmit echo reply and drop
2615         //
2616         // if we're dropping multicast
2617         //   if it's not ICMPv6 or it's ICMPv6 but we're in doze mode:
2618         //     if it's multicast:
2619         //       drop
2620         //     pass
2621         //
2622         // (APFv6+ specific logic)
2623         // if it's ICMPv6 NS:
2624         //   if there are no IPv6 addresses (including link local address) on the interface:
2625         //     pass
2626         //   if MAC dst is none of known {unicast, multicast, broadcast} MAC addresses
2627         //     drop
2628         //   if IPv6 dst prefix is "ff02::1:ff00:0/104" but is none of solicited-node multicast
2629         //   IPv6 addresses:
2630         //     drop
2631         //   else if IPv6 dst is none of interface unicast IPv6 addresses (incl. anycast):
2632         //     drop
2633         //   if hop limit is not 255 (NS requires hop limit to be 255):
2634         //     drop
2635         //   if payload len < 24 (8 bytes ICMP6 header + 16 bytes target address):
2636         //     drop
2637         //   if ICMPv6 code is not 0:
2638         //     drop
2639         //   if target IP is one of tentative IPv6 addresses:
2640         //     pass
2641         //   if target IP is none of non-tentative IPv6 addresses (incl. anycast):
2642         //     drop
2643         //   if IPv6 src is unspecified (::):
2644         //     pass
2645         //   if payload len < 32 (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option):
2646         //     pass
2647         //   if IPv6 src is multicast address (FF::/8) or loopback address (00::/8):
2648         //     drop
2649         //   if multicast MAC in SLLA option:
2650         //     drop
2651         //   transmit NA and drop
2652         //
2653         // if it's ICMPv6 RS to any:
2654         //   drop
2655         //
2656         // if it's ICMPv6 NA to anything in ff02::/120
2657         //   drop
2658         //
2659         // if keepalive ack
2660         //   drop
2661 
2662         gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET);
2663 
2664         if (enableMldOffload()) {
2665             generateMldFilter((ApfV6GeneratorBase<?>) gen);
2666             gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET);
2667         } else {
2668             gen.addCountAndPassIfR0Equals(IPPROTO_HOPOPTS, PASSED_IPV6_HOPOPTS);
2669         }
2670 
2671         if (enableMdns6Offload()) {
2672             generateIPv6MdnsFilter((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload);
2673             gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET);
2674         }
2675 
2676         if (enableIpv6PingOffload()) {
2677             generateUnicastIpv6PingOffload((ApfV6GeneratorBase<?>) gen);
2678             gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET);
2679         }
2680 
2681         // Drop multicast if the multicast filter is enabled.
2682         if (mMulticastFilter) {
2683             final short skipIPv6MulticastFilterLabel = gen.getUniqueLabel();
2684             final short dropAllIPv6MulticastsLabel = gen.getUniqueLabel();
2685 
2686             // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
2687             // While awake, let all ICMPv6 multicasts through.
2688             if (mInDozeMode) {
2689                 // Not ICMPv6? -> Proceed to multicast filtering
2690                 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
2691 
2692                 // ICMPv6 but not ECHO? -> Skip the multicast filter.
2693                 // (ICMPv6 ECHO requests will go through the multicast filter below).
2694                 gen.addLoad8intoR0(ICMP6_TYPE_OFFSET);
2695                 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
2696             } else {
2697                 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
2698             }
2699 
2700             // Drop all other packets sent to ff00::/8 (multicast prefix).
2701             gen.defineLabel(dropAllIPv6MulticastsLabel);
2702             gen.addLoad8intoR0(IPV6_DEST_ADDR_OFFSET);
2703             gen.addCountAndDropIfR0Equals(0xff, DROPPED_IPV6_NON_ICMP_MULTICAST);
2704             // If any keepalive filter matches, drop
2705             generateV6KeepaliveFilters(gen);
2706             // Not multicast. Pass.
2707             gen.addCountAndPass(PASSED_IPV6_UNICAST_NON_ICMP);
2708             gen.defineLabel(skipIPv6MulticastFilterLabel);
2709         } else {
2710             generateV6KeepaliveFilters(gen);
2711             // If not ICMPv6, pass.
2712             gen.addCountAndPassIfR0NotEquals(IPPROTO_ICMPV6, PASSED_IPV6_NON_ICMP);
2713         }
2714 
2715         // If we got this far, the packet is ICMPv6.  Drop some specific types.
2716         // Not ICMPv6 NS -> skip.
2717         gen.addLoad8intoR0(ICMP6_TYPE_OFFSET); // warning: also used further below.
2718         if (enableNdOffload()) {
2719             final short skipNsPacketFilter = gen.getUniqueLabel();
2720             gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_SOLICITATION, skipNsPacketFilter);
2721             generateNsFilter((ApfV6GeneratorBase<?>) gen);
2722             // End of NS filter. generateNsFilter() method is terminal, so NS packet will be
2723             // either dropped or passed inside generateNsFilter().
2724             gen.defineLabel(skipNsPacketFilter);
2725         }
2726 
2727         // Add unsolicited multicast neighbor announcements filter
2728         short skipUnsolicitedMulticastNALabel = gen.getUniqueLabel();
2729         // Drop all router solicitations (b/32833400)
2730         gen.addCountAndDropIfR0Equals(ICMPV6_ROUTER_SOLICITATION, DROPPED_IPV6_ROUTER_SOLICITATION);
2731         // If not neighbor announcements, skip filter.
2732         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
2733         // Drop all multicast NA to ff02::/120.
2734         // This is a way to cover ff02::1 and ff02::2 with a single JNEBS.
2735         // TODO: Drop only if they don't contain the address of on-link neighbours.
2736         final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15);
2737         gen.addJumpIfBytesAtOffsetNotEqual(
2738                 IPV6_DEST_ADDR_OFFSET, unsolicitedNaDropPrefix, skipUnsolicitedMulticastNALabel);
2739 
2740         gen.addCountAndDrop(DROPPED_IPV6_MULTICAST_NA);
2741         gen.defineLabel(skipUnsolicitedMulticastNALabel);
2742     }
2743 
2744     /**
2745      * Creates the portion of an IGMP packet from the Ethernet source MAC address to the IPv4
2746      * Type of Service field.
2747      */
createIgmpPktFromEthSrcToIPv4Tos()2748     private byte[] createIgmpPktFromEthSrcToIPv4Tos() {
2749         return CollectionUtils.concatArrays(
2750                 mHardwareAddress,
2751                 new byte[] {
2752                         // etherType: IPv4
2753                         (byte) 0x08, 0x00,
2754                         // version, IHL
2755                         (byte) 0x46,
2756                         // Tos: 0xC0 (ref: net/ipv4/igmp.c#igmp_send_report())
2757                         (byte) 0xc0}
2758         );
2759     }
2760 
2761     /**
2762      * Creates the portion of an IGMP packet from the IPv4 Identification field to the IPv4
2763      * Source Address.
2764      */
createIgmpPktFromIPv4IdToSrc()2765     private byte[] createIgmpPktFromIPv4IdToSrc() {
2766         final byte[] ipIdToSrc = new byte[] {
2767                 // identification
2768                 0, 0,
2769                 // fragment flag
2770                 (byte) (IPV4_FLAG_DF >> 8), 0,
2771                 // TTL
2772                 (byte) 1,
2773                 // protocol
2774                 (byte) IPV4_PROTOCOL_IGMP,
2775                 // router alert option is { 0x94, 0x04, 0x00, 0x00 }, so we precalculate IPv4
2776                 // checksum as 0x9404 + 0x0000 = 0x9404
2777                 (byte) 0x94, (byte) 0x04
2778         };
2779         return CollectionUtils.concatArrays(
2780                 ipIdToSrc,
2781                 mIPv4Address
2782         );
2783     }
2784 
2785     /**
2786      * Creates IGMPv3 Membership Report packet payload (rfc3376#section-7.3.2).
2787      */
createIgmpV3ReportPayload()2788     private byte[] createIgmpV3ReportPayload() {
2789         final int groupNum = mIPv4McastAddrsExcludeAllHost.size();
2790         final byte[] igmpHeader = new byte[] {
2791                 // IGMP type
2792                 (byte) IPV4_IGMP_TYPE_V3_REPORT,
2793                 // reserved
2794                 0,
2795                 // checksum, calculate later
2796                 0, 0,
2797                 // reserved
2798                 0, 0,
2799                 // num group records
2800                 (byte) ((groupNum >> 8) & 0xff), (byte) (groupNum & 0xff)
2801         };
2802         final byte[] groupRecordHeader = new byte[] {
2803                 // record type
2804                 (byte) IGMPV3_MODE_IS_EXCLUDE,
2805                 // aux data len,
2806                 0,
2807                 // num src
2808                 0, 0
2809         };
2810         final byte[] payload =
2811                 new byte[igmpHeader.length + groupNum * (groupRecordHeader.length + IPV4_ADDR_LEN)];
2812         int offset = 0;
2813 
2814         System.arraycopy(igmpHeader, 0, payload, offset, igmpHeader.length);
2815         offset += igmpHeader.length;
2816         for (Inet4Address mcastAddr: mIPv4McastAddrsExcludeAllHost) {
2817             System.arraycopy(groupRecordHeader, 0, payload, offset, groupRecordHeader.length);
2818             offset += groupRecordHeader.length;
2819             System.arraycopy(mcastAddr.getAddress(), 0, payload, offset, IPV4_ADDR_LEN);
2820             offset += IPV4_ADDR_LEN;
2821         }
2822 
2823         return payload;
2824     }
2825 
2826     /**
2827      * Generate transmit code to send IGMPv3 report in response to general query packets.
2828      */
generateIgmpV3ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)2829     private void generateIgmpV3ReportTransmit(ApfV6GeneratorBase<?> gen,
2830             byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)
2831             throws IllegalInstructionException {
2832         // We place template packet chunks in the data region first to reduce the number of
2833         // instructions needed for creating multiple IGMPv2 reports.
2834         // The following packet chunks can be used for creating both IGMPv2 and IGMPv3 reports:
2835         //   - from Ethernet source to IPv4 Tos: 10 bytes
2836         //   - from IPv4 identification to source address: 12 bytes
2837         final int igmpV2Ipv4TotalLen =
2838                 IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN + IPV4_IGMP_MIN_SIZE;
2839         final byte[] igmpV3ReportPayload = createIgmpV3ReportPayload();
2840         final byte[] igmpReportTemplate = CollectionUtils.concatArrays(
2841                 ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS,
2842                 igmpPktFromEthSrcToIpTos,
2843                 new byte[] {
2844                         (byte) ((igmpV2Ipv4TotalLen >> 8) & 0xff),
2845                         (byte) (igmpV2Ipv4TotalLen & 0xff),
2846                 },
2847                 igmpPktFromIpIdToSrc,
2848                 IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS,
2849                 IPV4_ROUTER_ALERT_OPTION,
2850                 igmpV3ReportPayload
2851         );
2852         gen.maybeUpdateDataRegion(igmpReportTemplate);
2853 
2854         final int ipv4TotalLen = IPV4_HEADER_MIN_LEN
2855                 + IPV4_ROUTER_ALERT_OPTION_LEN
2856                 + IPV4_IGMP_MIN_SIZE
2857                 + (mIPv4McastAddrsExcludeAllHost.size() * IPV4_IGMP_GROUP_RECORD_SIZE);
2858         final byte[] igmpV3FromEthDstToIpTos = CollectionUtils.concatArrays(
2859                 ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS,
2860                 igmpPktFromEthSrcToIpTos
2861         );
2862         final byte[] igmpV3PktFromIpIdToEnd = CollectionUtils.concatArrays(
2863                 igmpPktFromIpIdToSrc,
2864                 IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS,
2865                 IPV4_ROUTER_ALERT_OPTION,
2866                 igmpV3ReportPayload
2867         );
2868         gen.addAllocate(ETHER_HEADER_LEN + ipv4TotalLen)
2869                 .addDataCopy(igmpV3FromEthDstToIpTos)
2870                 .addWriteU16(ipv4TotalLen)
2871                 .addDataCopy(igmpV3PktFromIpIdToEnd)
2872                 .addTransmitL4(
2873                         // ip_ofs
2874                         ETHER_HEADER_LEN,
2875                         // csum_ofs
2876                         IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET,
2877                         // csum_start
2878                         ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN,
2879                         // partial_sum
2880                         0,
2881                         // udp
2882                         false
2883                 )
2884                 .addCountAndDrop(Counter.DROPPED_IGMP_V3_GENERAL_QUERY_REPLIED);
2885     }
2886 
2887     /**
2888      * Generate transmit code to send IGMPv2 report in response to general query packets.
2889      */
generateIgmpV2ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)2890     private void generateIgmpV2ReportTransmit(ApfV6GeneratorBase<?> gen,
2891             byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)
2892             throws IllegalInstructionException {
2893         final int ipv4TotalLen =
2894                 IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN + IPV4_IGMP_MIN_SIZE;
2895         final byte[] igmpV2PktFromEthSrcToIpSrc =  CollectionUtils.concatArrays(
2896                 igmpPktFromEthSrcToIpTos,
2897                 new byte[] {
2898                         (byte) ((ipv4TotalLen >> 8) & 0xff), (byte) (ipv4TotalLen & 0xff),
2899                 },
2900                 igmpPktFromIpIdToSrc
2901         );
2902         for (Inet4Address mcastAddr: mIPv4McastAddrsExcludeAllHost) {
2903             final MacAddress mcastEther =
2904                     NetworkStackUtils.ipv4MulticastToEthernetMulticast(mcastAddr);
2905             gen.addAllocate(ETHER_HEADER_LEN + ipv4TotalLen)
2906                     .addDataCopy(mcastEther.toByteArray())
2907                     .addDataCopy(igmpV2PktFromEthSrcToIpSrc)
2908                     .addDataCopy(mcastAddr.getAddress())
2909                     .addDataCopy(IGMPV2_REPORT_FROM_IPV4_OPTION_TO_IGMP_CHECKSUM)
2910                     .addDataCopy(mcastAddr.getAddress())
2911                     .addTransmitL4(
2912                             // ip_ofs
2913                             ETHER_HEADER_LEN,
2914                             // csum_ofs
2915                             IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET,
2916                             // csum_start
2917                             ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN,
2918                             // partial_sum
2919                             0,
2920                             // udp
2921                             false
2922                     );
2923         }
2924 
2925         gen.addCountAndDrop(Counter.DROPPED_IGMP_V2_GENERAL_QUERY_REPLIED);
2926     }
2927 
2928     /**
2929      * Generates filter code to handle IGMP packets.
2930      * <p>
2931      * On entry, this filter know it is processing an IPv4 packet. It will then process all IGMP
2932      * packets, either passing or dropping them. Non-IGMP packets are skipped.
2933      */
generateIgmpFilter(ApfV6GeneratorBase<?> v6Gen)2934     private void generateIgmpFilter(ApfV6GeneratorBase<?> v6Gen)
2935             throws IllegalInstructionException {
2936         final short skipIgmpFilter = v6Gen.getUniqueLabel();
2937         final short checkIgmpV1orV2 = v6Gen.getUniqueLabel();
2938 
2939         // Check 1) it's not a fragment. 2) it's IGMP.
2940         v6Gen.addJumpIfNotUnfragmentedIPv4Protocol(IPV4_PROTOCOL_IGMP, skipIgmpFilter);
2941 
2942         // Calculate the IPv4 payload length: (total length - IPv4 header length).
2943         // Memory slot 0 is occupied temporarily to store the length.
2944         v6Gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET)
2945                 .addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE)
2946                 .addNeg(R1)
2947                 .addAddR1ToR0()
2948                 .addStoreToMemory(MemorySlot.SLOT_0, R0);
2949 
2950         // If payload length is less than 8 or equal to 9, 10, 11, it's invalid IGMP packet: drop.
2951         v6Gen.addCountAndDropIfR0LessThan(IPV4_IGMP_MIN_SIZE, DROPPED_IGMP_INVALID)
2952                 .addCountAndDropIfR0IsOneOf(Set.of(9L, 10L, 11L), DROPPED_IGMP_INVALID);
2953 
2954         // If it's an IGMPv1/IGMPv2/IGMPv3 report: drop.
2955         // A host normally cancels its own pending report if it observes
2956         // an identical report from another host on the network (host suppression).
2957         // While dropping reports here technically disrupts this host's suppression behavior,
2958         // it is acceptable since other devices on the network will perform the suppression.
2959         // If the IGMP type is not one of the reports, it's either a query(type=0x11) or an
2960         // invalid packet.
2961         v6Gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE)
2962                 .addLoad8R1IndexedIntoR0(ETHER_HEADER_LEN)
2963                 .addCountAndDropIfR0IsOneOf(IGMP_TYPE_REPORTS, DROPPED_IGMP_REPORT)
2964                 .addCountAndDropIfR0NotEquals(IPV4_IGMP_TYPE_QUERY, DROPPED_IGMP_INVALID);
2965 
2966         // If group address is not 0.0.0.0, it's an IGMPv2/v3 group specific query: pass.
2967         // rfc3376#section-6.1 mentions group specific queries are sent when a router receives a
2968         // State-Change record indicating a system is leaving a group. Therefore, since the
2969         // router only sends group-specific queries after receiving a leave message, it is not
2970         // sent out periodically.
2971         // Increased APF bytecode size for offloading these queries may not yield significant
2972         // power benefits. In this case, letting the kernel handle group-specific queries is
2973         // acceptable.
2974         v6Gen.addLoad32R1IndexedIntoR0(IGMP_MULTICAST_ADDRESS_OFFSET)
2975                 .addCountAndPassIfR0NotEquals(0 /* 0.0.0.0 */, PASSED_IPV4);
2976 
2977         // If we reach here, we know it is an IGMPv1/IGMPv2/IGMPv3 general query.
2978 
2979         // The general query IPv4 destination address must be 224.0.0.1.
2980         v6Gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET)
2981                 .addCountAndDropIfR0NotEquals(IPV4_ALL_HOSTS_ADDRESS_IN_LONG,
2982                         DROPPED_IGMP_INVALID);
2983 
2984         // Check payload length, since invalid length already checked,
2985         // it should be 8 (IGMPv1 or IGMPv2) or >=12 (IGMPv3)
2986         v6Gen.addLoadFromMemory(R0, MemorySlot.SLOT_0)
2987                 .addJumpIfR0Equals(IPV4_IGMP_MIN_SIZE, checkIgmpV1orV2);
2988 
2989         // ===== IGMPv3 general query =====
2990         // To optimize for bytecode size, the IGMPv3 report is constructed first.
2991         // Its packet structure is then reused as a template when creating the IGMPv2 report.
2992         final byte[] igmpPktFromEthSrcToIpTos = createIgmpPktFromEthSrcToIPv4Tos();
2993         final byte[] igmpPktFromIpIdToSrc = createIgmpPktFromIPv4IdToSrc();
2994         generateIgmpV3ReportTransmit(v6Gen, igmpPktFromEthSrcToIpTos, igmpPktFromIpIdToSrc);
2995 
2996         // ===== IGMPv1 or IGMPv2 general query =====
2997         v6Gen.defineLabel(checkIgmpV1orV2);
2998         // Based on rfc3376#section-7.1 If max resp time is 0, it's IGMPv1: pass.
2999         // We don't expect many networks are still using IGMPv1, pass it to the kernel to save
3000         // bytecode size.
3001         // (Note: R1 is still IPV4_HEADER_SIZE)
3002         v6Gen.addLoad8R1IndexedIntoR0(IGMP_MAX_RESP_TIME_OFFSET)
3003                 .addCountAndPassIfR0Equals(0, PASSED_IPV4); // IGMPv1
3004 
3005         // Drop and transmit IGMPv2 reports
3006         generateIgmpV2ReportTransmit(v6Gen, igmpPktFromEthSrcToIpTos, igmpPktFromIpIdToSrc);
3007 
3008         v6Gen.defineLabel(skipIgmpFilter);
3009     }
3010 
3011     /**
3012      * Creates MLDv1 Listener Report packet message (rfc2710#section-3).
3013      */
createMldV1ReportMessage(final Inet6Address mcastAddr)3014     private byte[] createMldV1ReportMessage(final Inet6Address mcastAddr) {
3015         final byte[] mldv1Header = new byte[] {
3016             // MLD type
3017             (byte) IPV6_MLD_TYPE_V1_REPORT,
3018             // code
3019             0,
3020             // hop-by-hop option is { 0x3a, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00 }
3021             // so we precalculate MLD checksum as follows:
3022             // 0xffff - (0x3a00 + 0x0502 + 0x0000 + 0x0100) = 0xbffd
3023             (byte) 0xbf, (byte) 0xfd,
3024             // max response delay
3025             0, 0,
3026             // reserved
3027             0, 0
3028         };
3029 
3030         return CollectionUtils.concatArrays(mldv1Header, mcastAddr.getAddress());
3031     }
3032 
3033     /**
3034      * Creates MLDv2 Listener Report packet payload (rfc3810#section-5.2).
3035      */
createMldV2ReportPayload()3036     private byte[] createMldV2ReportPayload() {
3037         final int mcastAddrsNum = mIPv6McastAddrsExcludeAllHost.size();
3038         final byte[] mldHeader = new byte[] {
3039             // MLD type
3040             (byte) IPV6_MLD_TYPE_V2_REPORT,
3041             // code
3042             0,
3043             // hop-by-hop option is { 0x3a, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00 }
3044             // so we precalculate MLD checksum as follows:
3045             // 0xffff - (0x3a00 + 0x0502 + 0x0000 + 0x0100) = 0xbffd
3046             (byte) 0xbf, (byte) 0xfd,
3047             // reserved
3048             0, 0,
3049             // num of multicast address records
3050             (byte) ((mcastAddrsNum >> 8) & 0xff), (byte) (mcastAddrsNum & 0xff)
3051         };
3052 
3053         final byte[] mcastRecordHeader = new byte[] {
3054             // record type
3055             (byte) MLD2_MODE_IS_EXCLUDE,
3056             // aux data len,
3057             0,
3058             // num src
3059             0, 0
3060         };
3061 
3062         final byte[] payload =
3063                 new byte[
3064                     mldHeader.length + mcastAddrsNum * IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE
3065                 ];
3066         int offset = 0;
3067 
3068         System.arraycopy(mldHeader, 0, payload, offset, mldHeader.length);
3069         offset += mldHeader.length;
3070         for (Inet6Address mcastAddr: mIPv6McastAddrsExcludeAllHost) {
3071             System.arraycopy(mcastRecordHeader, 0, payload, offset, mcastRecordHeader.length);
3072             offset += mcastRecordHeader.length;
3073             System.arraycopy(mcastAddr.getAddress(), 0, payload, offset, IPV6_ADDR_LEN);
3074             offset += IPV6_ADDR_LEN;
3075         }
3076 
3077         return payload;
3078     }
3079 
3080     /**
3081      * Creates the portion of an MLD packet from the Ethernet source MAC address to the IPv6
3082      * VTF field.
3083      */
createMldPktFromEthSrcToIPv6Vtf()3084     private byte[] createMldPktFromEthSrcToIPv6Vtf() {
3085         return CollectionUtils.concatArrays(
3086             mHardwareAddress,
3087             new byte[] {
3088                 // etherType: IPv6
3089                 (byte) 0x86, (byte) 0xdd,
3090                 // version, traffic class, flow label
3091                 // 0x60000000 (ref: net/ipv6/mcast.c#ip6_mc_hdr())
3092                 (byte) 0x60, 0, 0, 0}
3093         );
3094     }
3095 
3096     /**
3097      * Creates the portion of an MLD packet from the IPv6 Next Header to the IPv6 Source Address.
3098      */
createMldPktFromIPv6NextHdrToSrc()3099     private byte[] createMldPktFromIPv6NextHdrToSrc() {
3100         final byte[] ipv6FromNextHdrToHoplimit = new byte[] {
3101             // Next header: HOPOPTS
3102             0,
3103             // Hop limit
3104             (byte) 1
3105         };
3106         return CollectionUtils.concatArrays(
3107             ipv6FromNextHdrToHoplimit,
3108             mIPv6LinkLocalAddress.getAddress()
3109         );
3110     }
3111 
3112     /**
3113      * Generate transmit code to send MLDv1 report in response to general query packets.
3114      */
generateMldV1ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)3115     private void generateMldV1ReportTransmit(ApfV6GeneratorBase<?> gen,
3116             byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)
3117             throws IllegalInstructionException {
3118         final int packetSize =
3119                 ETHER_HEADER_LEN
3120                 + IPV6_HEADER_LEN
3121                 + IPV6_MLD_HOPOPTS.length
3122                 + IPV6_MLD_V1_MESSAGE_SIZE;
3123         final int mldV1Ipv6PayloadLength = IPV6_MLD_HOPOPTS.length + IPV6_MLD_V1_MESSAGE_SIZE;
3124         final byte[] mldV1PktFromEthSrcToIpv6Src =  CollectionUtils.concatArrays(
3125                 mldPktFromEthSrcToIpv6Vtf,
3126                 new byte[] {
3127                         (byte) ((mldV1Ipv6PayloadLength >> 8) & 0xff),
3128                         (byte) (mldV1Ipv6PayloadLength & 0xff),
3129                 },
3130                 mldPktFromIpv6NextHdrToSrc
3131         );
3132         for (Inet6Address mcastAddr: mIPv6McastAddrsExcludeAllHost) {
3133             final MacAddress mcastEther =
3134                     NetworkStackUtils.ipv6MulticastToEthernetMulticast(mcastAddr);
3135             gen.addAllocate(packetSize)
3136                     .addDataCopy(mcastEther.toByteArray())
3137                     .addDataCopy(mldV1PktFromEthSrcToIpv6Src)
3138                     .addDataCopy(mcastAddr.getAddress())
3139                     .addDataCopy(IPV6_MLD_HOPOPTS)
3140                     .addDataCopy(createMldV1ReportMessage(mcastAddr))
3141                     .addTransmitL4(
3142                         // ip_ofs
3143                         ETHER_HEADER_LEN,
3144                         // csum_ofs
3145                         IPV6_MLD_CHECKSUM_OFFSET,
3146                         // csum_start
3147                         IPV6_SRC_ADDR_OFFSET,
3148                         // partial_sum
3149                         IPPROTO_ICMPV6 + IPV6_MLD_V1_MESSAGE_SIZE,
3150                         // udp
3151                         false
3152                     );
3153         }
3154 
3155         gen.addCountAndDrop(DROPPED_IPV6_MLD_V1_GENERAL_QUERY_REPLIED);
3156     }
3157 
3158     /**
3159      * Generate transmit code to send MLDv2 report in response to general query packets.
3160      */
generateMldV2ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)3161     private void generateMldV2ReportTransmit(ApfV6GeneratorBase<?> gen,
3162             byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)
3163             throws IllegalInstructionException {
3164         final int mldV1Ipv6PayloadLength = IPV6_MLD_HOPOPTS.length + IPV6_MLD_V1_MESSAGE_SIZE;
3165         final byte[] encodedMldV1Ipv6PayloadLength = {
3166             (byte) ((mldV1Ipv6PayloadLength >> 8) & 0xff), (byte) (mldV1Ipv6PayloadLength & 0xff),
3167         };
3168         // We place template packet chunks in the data region first to reduce the number of
3169         // instructions needed for creating multiple MLDv1 reports.
3170         // The following packet chunks can be used for creating both MLDv1 and MLDv2 reports:
3171         //   - from Ethernet source to IPv6 VTF: 12 bytes
3172         //   - from IPv6 next header to source address: 18 bytes
3173         final byte[] mldV2ReportPayload = createMldV2ReportPayload();
3174         final byte[] template = CollectionUtils.concatArrays(
3175             ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS,
3176             mldPktFromEthSrcToIpv6Vtf,
3177             encodedMldV1Ipv6PayloadLength,
3178             mldPktFromIpv6NextHdrToSrc,
3179             IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS,
3180             IPV6_MLD_HOPOPTS,
3181             mldV2ReportPayload
3182         );
3183         gen.maybeUpdateDataRegion(template);
3184 
3185         final byte[] mldV2PktFromEthDstToIpv6Vtf = CollectionUtils.concatArrays(
3186                 ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS,
3187                 mldPktFromEthSrcToIpv6Vtf
3188         );
3189         final byte[] mldV2PktFromIpv6NextHdrToEnd = CollectionUtils.concatArrays(
3190                 mldPktFromIpv6NextHdrToSrc,
3191                 IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS,
3192                 IPV6_MLD_HOPOPTS,
3193                 mldV2ReportPayload
3194         );
3195         final int mcastAddrsNum = mIPv6McastAddrsExcludeAllHost.size();
3196         final int ipv6PayloadLength = IPV6_MLD_HOPOPTS.length
3197                 + IPV6_MLD_MESSAGE_MIN_SIZE
3198                 + (mcastAddrsNum * IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE);
3199         gen.addAllocate(ETHER_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLength)
3200             .addDataCopy(mldV2PktFromEthDstToIpv6Vtf)
3201             .addWriteU16(ipv6PayloadLength)
3202             .addDataCopy(mldV2PktFromIpv6NextHdrToEnd)
3203             .addTransmitL4(
3204                 // ip_ofs
3205                 ETHER_HEADER_LEN,
3206                 // csum_ofs
3207                 IPV6_MLD_CHECKSUM_OFFSET,
3208                 // csum_start
3209                 IPV6_SRC_ADDR_OFFSET,
3210                 // partial_sum
3211                 IPPROTO_ICMPV6 + (ipv6PayloadLength - IPV6_MLD_HOPOPTS.length),
3212                 // udp
3213                 false
3214             ).addCountAndDrop(DROPPED_IPV6_MLD_V2_GENERAL_QUERY_REPLIED);
3215     }
3216 
3217     /**
3218      * Generates filter code to handle MLD packets.
3219      * <p>
3220      * On entry, this filter knows it is processing an IPv6 packet. It will then process all MLD
3221      * packets, either passing or dropping them. Non-MLD packets are skipped.
3222      * R0 contains the u8 IPv6 next header.
3223      */
generateMldFilter(ApfV6GeneratorBase<?> gen)3224     private void generateMldFilter(ApfV6GeneratorBase<?> gen)
3225             throws IllegalInstructionException {
3226         final short skipMldFilter = gen.getUniqueLabel();
3227         final short checkMldv1 = gen.getUniqueLabel();
3228 
3229         // If next header is not hop-by-hop, then skip
3230         gen.addJumpIfR0NotEquals(IPPROTO_HOPOPTS, skipMldFilter);
3231 
3232         final int mldPacketMinSize =
3233                 ETHER_HEADER_LEN + IPV6_HEADER_LEN + IPV6_MLD_HOPOPTS.length + IPV6_MLD_MIN_SIZE;
3234         // If packet is too small to be MLD packet, then skip
3235         gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE)
3236                 .addJumpIfR0LessThan(mldPacketMinSize, skipMldFilter)
3237                 .addSub(ETHER_HEADER_LEN + IPV6_HEADER_LEN + IPV6_MLD_HOPOPTS.length)
3238                 // Memory slot 0 is occupied temporarily to store the MLD payload length.
3239                 .addStoreToMemory(MemorySlot.SLOT_0, R0);
3240 
3241         // If the hop-by-hop option is not the one used by MLD, then skip
3242         gen.addLoadImmediate(R0, IPV6_EXT_HEADER_OFFSET)
3243                 .addJumpIfBytesAtR0NotEqual(IPV6_MLD_HOPOPTS, skipMldFilter);
3244 
3245         // If the packet is an MLDv1 report or done, or an MLDv2 report, then drop it.
3246         // Else if the packet is not an MLD query packet, then skip.
3247         gen.addLoad8intoR0(IPV6_MLD_TYPE_OFFSET)
3248                 .addCountAndDropIfR0IsOneOf(IPV6_MLD_TYPE_REPORTS, DROPPED_IPV6_MLD_REPORT)
3249                 .addJumpIfR0NotEquals(IPV6_MLD_TYPE_QUERY, skipMldFilter);
3250 
3251         // If we reach here, we know it is an MLDv1/MLDv2 query.
3252 
3253         // If the payload length is 25, 26, or 27, the MLD packet is invalid and should be dropped.
3254         gen.addLoadFromMemory(R0, MemorySlot.SLOT_0)
3255                 .addCountAndDropIfR0IsOneOf(Set.of(25L, 26L, 27L), DROPPED_IPV6_MLD_INVALID);
3256 
3257         // rfc3810#section-5 and rfc2710#section-3 describe that all MLD messages are sent with a
3258         // link-local IPv6 source address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert
3259         // option [RTR-ALERT] in a Hop-by-Hop Options header.
3260         // rfc3810#section-5.2.13 describes that an MLDv2 Report MUST be sent with a valid
3261         // IPv6 link-local source address, or the unspecified address (::), if the sending interface
3262         // has not yet acquired a valid link-local address.
3263         // Its OK to not check :: here since we also drop MLD reports.
3264         // If the source address is a not a link-local address, then drop.
3265         gen.addLoad16intoR0(IPV6_SRC_ADDR_OFFSET)
3266                 .addCountAndDropIfR0NotEquals(0xfe80, DROPPED_IPV6_MLD_INVALID);
3267 
3268         // If hop limit is not 1, then drop.
3269         gen.addLoad8intoR0(IPV6_HOP_LIMIT_OFFSET)
3270                 .addCountAndDropIfR0NotEquals(1, DROPPED_IPV6_MLD_INVALID);
3271 
3272         // If the multicast address is not "::", it is an MLD2 multicast-address-specific query,
3273         // then pass.
3274         gen.addCountAndPassIfBytesAtOffsetNotEqual(
3275                 IPV6_MLD_MULTICAST_ADDR_OFFSET, IPV6_ADDR_ANY.getAddress(), PASSED_IPV6_ICMP);
3276 
3277         // If we reach here, we know it is an MLDv1/MLDv2 general query.
3278 
3279         // The general query IPv6 destination address must be ff02::1.
3280         gen.addCountAndDropIfBytesAtOffsetNotEqual(
3281                         IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS, DROPPED_IPV6_MLD_INVALID);
3282 
3283         // If the MLD payload length is 24, it is an MLDv1 packet, otherwise, it is an MLDv2 packet.
3284         gen.addLoadFromMemory(R0, MemorySlot.SLOT_0)
3285                 .addJumpIfR0Equals(IPV6_MLD_MIN_SIZE, checkMldv1);
3286 
3287         // ===== MLDv2 general query =====
3288         // To optimize for bytecode size, the MLDv2 report is constructed first.
3289         // Its packet structure is then reused as a template when creating the IGMPv1 report.
3290         final byte[] mldPktFromEthSrcToIPv6Vtf = createMldPktFromEthSrcToIPv6Vtf();
3291         final byte[] mldPktFromIPv6NextHdrToSrc = createMldPktFromIPv6NextHdrToSrc();
3292         generateMldV2ReportTransmit(gen, mldPktFromEthSrcToIPv6Vtf, mldPktFromIPv6NextHdrToSrc);
3293 
3294         gen.defineLabel(checkMldv1);
3295         // ===== MLDv1 general query =====
3296         generateMldV1ReportTransmit(gen, mldPktFromEthSrcToIPv6Vtf, mldPktFromIPv6NextHdrToSrc);
3297 
3298         gen.defineLabel(skipMldFilter);
3299     }
3300 
3301     /**
3302      * Generate filter code to drop IPv4 TCP packets on port 7.
3303      * <p>
3304      * On entry, we know it is IPv4 ethertype, but don't know anything else.
3305      * R0/R1 have nothing useful in them, and can be clobbered.
3306      */
generateV4TcpPort7Filter(ApfV4GeneratorBase<?> gen)3307     private void generateV4TcpPort7Filter(ApfV4GeneratorBase<?> gen)
3308             throws IllegalInstructionException {
3309         final short skipPort7V4Filter = gen.getUniqueLabel();
3310 
3311         // Check it's TCP.
3312         gen.addLoad8intoR0(IPV4_PROTOCOL_OFFSET);
3313         gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipPort7V4Filter);
3314 
3315         // Check it's not a fragment or is the initial fragment.
3316         gen.addLoad16intoR0(IPV4_FRAGMENT_OFFSET_OFFSET);
3317         gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipPort7V4Filter);
3318 
3319         // Check it's destination port 7.
3320         gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE);
3321         gen.addLoad16R1IndexedIntoR0(TCP_UDP_DESTINATION_PORT_OFFSET);
3322         gen.addJumpIfR0NotEquals(ECHO_PORT, skipPort7V4Filter);
3323 
3324         // Drop it.
3325         gen.addCountAndDrop(DROPPED_IPV4_TCP_PORT7_UNICAST);
3326 
3327         // Skip label.
3328         gen.defineLabel(skipPort7V4Filter);
3329     }
3330 
generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)3331     private void generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)
3332             throws IllegalInstructionException {
3333         generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
3334                 gen.getUniqueLabel());
3335     }
3336 
createMdns4PktFromEthDstToIPv4Tos(boolean enabled)3337     private byte[] createMdns4PktFromEthDstToIPv4Tos(boolean enabled) {
3338         if (!enabled) {
3339             return null;
3340         }
3341         return concatArrays(
3342                 ETH_MULTICAST_MDNS_V4_MAC_ADDRESS,
3343                 mHardwareAddress,
3344                 new byte[]{
3345                         0x08, 0x00, // ethertype: IPv4
3346                         0x45, 0x00, // version, IHL, DSCP, ECN,
3347                 });
3348     }
3349 
createMdns6PktFromEthDstToIPv6FlowLabel(boolean enabled)3350     private byte[] createMdns6PktFromEthDstToIPv6FlowLabel(boolean enabled) {
3351         if (!enabled) {
3352             return null;
3353         }
3354         return concatArrays(
3355                 ETH_MULTICAST_MDNS_V6_MAC_ADDRESS,
3356                 mHardwareAddress,
3357                 new byte[]{
3358                         (byte) 0x86, (byte) 0xdd, // ethertype: IPv6
3359                         0x60, 0x00, 0x00, 0x00, // version, traffic class, flow label
3360                 });
3361     }
3362 
3363 
createMdns4PktFromIPv4IdToUdpDport(boolean enabled)3364     private byte[] createMdns4PktFromIPv4IdToUdpDport(boolean enabled) {
3365         if (!enabled) {
3366             return null;
3367         }
3368         return concatArrays(
3369                 new byte[]{
3370                         0x00, 0x00, // identification
3371                         (byte) (IPV4_FLAG_DF >> 8), 0, // flags, fragment offset
3372                         (byte) 0xff, // set TTL to 255 per rfc6762#section-11
3373                         (byte) IPPROTO_UDP,
3374                         0x00, 0x00, // checksum, it's a placeholder that will be filled in later.
3375                 },
3376                 mIPv4Address,
3377                 MDNS_IPV4_ADDR,
3378                 MDNS_PORT_IN_BYTES, // source port
3379                 MDNS_PORT_IN_BYTES); // destination port
3380     }
3381 
createMdns6PktFromIPv6NextHdrToUdpDport(boolean enabled)3382     private byte[] createMdns6PktFromIPv6NextHdrToUdpDport(boolean enabled) {
3383         if (!enabled) {
3384             return null;
3385         }
3386         return concatArrays(
3387                 new byte[]{
3388                         (byte) IPPROTO_UDP,
3389                         (byte) 0xff, // set hop limit to 255 per rfc6762#section-11
3390                 },
3391                 mIPv6LinkLocalAddress.getAddress(),
3392                 MDNS_IPV6_ADDR,
3393                 MDNS_PORT_IN_BYTES, // source port
3394                 MDNS_PORT_IN_BYTES); // destination port
3395     }
3396 
3397     /**
3398      * Generates filter code to process an mDNS payload against offload rules.
3399      * The generated filter code is guaranteed to process all IPv4 and IPv6 mDNS packets,
3400      * ensuring each packet is either passed or dropped.
3401      * <p>
3402      * The only way to enter the mDNS offload payload check logic is by jumping to the
3403      * labelCheckMdnsQueryPayload label.
3404      * On entry, the packet is known to be an IPv4/IPv6 mDNS query packet, and register R1
3405      * is set to the offset of the beginning of the UDP payload (the DNS header).
3406      *
3407      * @param gen the APF generator to generate the filter code
3408      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
3409      */
generateMdnsQueryOffload(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload, int numOfMdnsRuleToOffload)3410     private void generateMdnsQueryOffload(ApfV6GeneratorBase<?> gen,
3411             short labelCheckMdnsQueryPayload, int numOfMdnsRuleToOffload)
3412             throws IllegalInstructionException {
3413         // The mDNS payload check logic is terminal; the program will always result in either
3414         // PASS or DROP.
3415         gen.defineLabel(labelCheckMdnsQueryPayload);
3416 
3417         if (numOfMdnsRuleToOffload == -1) {
3418             gen.addCountAndPass(PASSED_MDNS);
3419             return;
3420         }
3421 
3422         // Set R0 to the offset of the beginning of the UDP payload (the DNS header)
3423         gen.addSwap();
3424 
3425         final boolean enableMdns4 = enableMdns4Offload();
3426         final boolean enableMdns6 = enableMdns6Offload();
3427         final byte[] mdns4EthDstToTos = createMdns4PktFromEthDstToIPv4Tos(enableMdns4);
3428         final byte[] mdns4IdToUdpDport = createMdns4PktFromIPv4IdToUdpDport(enableMdns4);
3429         final byte[] mdns6EthDstToFlowLabel = createMdns6PktFromEthDstToIPv6FlowLabel(enableMdns6);
3430         final byte[] mdns6NextHdrToUdpDport = createMdns6PktFromIPv6NextHdrToUdpDport(enableMdns6);
3431 
3432         for (int i = 0; i < mOffloadRules.size(); i++) {
3433             final MdnsOffloadRule rule = mOffloadRules.get(i);
3434             final short ruleNotMatch = gen.getUniqueLabel();
3435             final short ruleMatch = gen.getUniqueLabel();
3436             final short offloadIPv6Mdns = gen.getUniqueLabel();
3437 
3438             for (MdnsOffloadRule.Matcher matcher : rule.mMatchers) {
3439                 try {
3440                     gen.addJumpIfPktAtR0ContainDnsQ(matcher.mQnames, matcher.mQtypes, ruleMatch);
3441                 } catch (IllegalArgumentException e) {
3442                     Log.e(TAG, "Failed to generate mDNS offload filter for rule: " + rule, e);
3443                 }
3444             }
3445 
3446             gen.addJump(ruleNotMatch);
3447 
3448             gen.defineLabel(ruleMatch);
3449 
3450             // If there is no offload payload, pass the packet to let NsdService handle it.
3451             // If there isn't enough space to offload all rules, packets should be processed
3452             // by iterating through the rules, starting with the lowest priority.
3453             if (rule.mOffloadPayload == null || i >= numOfMdnsRuleToOffload) {
3454                 gen.addCountAndPass(PASSED_MDNS);
3455             } else {
3456                 if (enableMdns4 && enableMdns6) {
3457                     gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET)
3458                             .addJumpIfR0NotEquals(ETH_P_IP, offloadIPv6Mdns);
3459                 }
3460 
3461                 if (enableMdns4) {
3462                     final int udpLength = UDP_HEADER_LEN + rule.mOffloadPayload.length;
3463                     final int ipv4TotalLength = IPV4_HEADER_MIN_LEN + udpLength;
3464                     final int pktLength = ETH_HEADER_LEN + ipv4TotalLength;
3465 
3466                     gen.addAllocate(pktLength)
3467                             .addDataCopy(mdns4EthDstToTos)
3468                             .addWriteU16(ipv4TotalLength)
3469                             .addDataCopy(mdns4IdToUdpDport)
3470                             .addWrite32(udpLength << 16) // udp length and checksum
3471                             .addDataCopy(rule.mOffloadPayload)
3472                             .addTransmitL4(
3473                                     ETH_HEADER_LEN, // ip_ofs
3474                                     IPV4_UDP_DESTINATION_CHECKSUM_NO_OPTIONS_OFFSET, // csum_ofs
3475                                     IPV4_SRC_ADDR_OFFSET, // csum_start
3476                                     IPPROTO_UDP + udpLength, // partial_sum
3477                                     true // udp
3478                             ).addCountAndDrop(Counter.DROPPED_MDNS_REPLIED);
3479                 }
3480 
3481                 if (enableMdns4 && enableMdns6) {
3482                     gen.defineLabel(offloadIPv6Mdns);
3483                 }
3484 
3485                 if (enableMdns6) {
3486                     final int udpLength = UDP_HEADER_LEN + rule.mOffloadPayload.length;
3487                     final int pktLength = ETH_HEADER_LEN + IPV6_HEADER_LEN + udpLength;
3488                     gen.addAllocate(pktLength)
3489                             .addDataCopy(mdns6EthDstToFlowLabel)
3490                             .addWriteU16(udpLength) // payload length
3491                             .addDataCopy(mdns6NextHdrToUdpDport)
3492                             .addWrite32(udpLength << 16) //  udp length and checksum
3493                             .addDataCopy(rule.mOffloadPayload)
3494                             .addTransmitL4(
3495                                     ETH_HEADER_LEN, // ip_ofs
3496                                     IPV6_UDP_DESTINATION_CHECKSUM_OFFSET, // csum_ofs
3497                                     IPV6_SRC_ADDR_OFFSET, // csum_start
3498                                     IPPROTO_UDP + udpLength, // partial_sum
3499                                     true // udp
3500                             ).addCountAndDrop(Counter.DROPPED_MDNS_REPLIED);
3501                 }
3502             }
3503 
3504             gen.defineLabel(ruleNotMatch);
3505         }
3506 
3507         // If no offload rules match, we should still respect the multicast filter. During the
3508         // transition period, not all apps will use NsdManager for mDNS advertising. If an app
3509         // decides to perform mDNS advertising itself, it must acquire a multicast lock, and no
3510         // offload rules will be registered for that app. In this case, the APF should pass the
3511         // mDNS packet and allow the app to handle the query.
3512         if (mMulticastFilter) {
3513             gen.addCountAndDrop(DROPPED_MDNS);
3514         } else {
3515             gen.addCountAndPass(PASSED_MDNS);
3516         }
3517     }
3518 
3519     /**
3520      * Begin generating an APF program to:
3521      * <ul>
3522      * <li>Drop/Pass 802.3 frames (based on policy)
3523      * <li>Drop packets with EtherType within the Black List
3524      * <li>Drop ARP requests not for us, if mIPv4Address is set,
3525      * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
3526      * <li>Drop IPv4 multicast packets, if mMulticastFilter,
3527      * <li>Pass all other IPv4 packets,
3528      * <li>Drop all broadcast non-IP non-ARP packets.
3529      * <li>Pass all non-ICMPv6 IPv6 packets,
3530      * <li>Pass all non-IPv4 and non-IPv6 packets,
3531      * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120.
3532      * <li>Drop IPv6 ICMPv6 RSs.
3533      * <li>Filter IPv4 packets (see generateIPv4Filter())
3534      * <li>Filter IPv6 packets (see generateIPv6Filter())
3535      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
3536      *     insertion of RA filters here, or if there aren't any, just passes the packets.
3537      * </ul>
3538      * @param gen the APF generator to generate the filter code
3539      * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload
3540      */
emitPrologue(@onNull ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)3541     private void emitPrologue(@NonNull ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)
3542             throws IllegalInstructionException {
3543         if (hasDataAccess(mApfVersionSupported)) {
3544             if (gen instanceof ApfV4Generator) {
3545                 // Increment TOTAL_PACKETS.
3546                 // Only needed in APFv4.
3547                 // In APFv6, the interpreter will increase the counter on packet receive.
3548                 gen.addIncrementCounter(TOTAL_PACKETS);
3549             }
3550 
3551             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS);
3552             gen.addStoreCounter(FILTER_AGE_SECONDS, R0);
3553 
3554             // requires a new enough APFv5+ interpreter, otherwise will be 0
3555             gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_16384THS);
3556             gen.addStoreCounter(FILTER_AGE_16384THS, R0);
3557 
3558             // requires a new enough APFv5+ interpreter, otherwise will be 0
3559             gen.addLoadFromMemory(R0, MemorySlot.APF_VERSION);
3560             gen.addStoreCounter(APF_VERSION, R0);
3561 
3562             // store this program's sequential id, for later comparison
3563             gen.addLoadImmediate(R0, mNumProgramUpdates);
3564             gen.addStoreCounter(APF_PROGRAM_ID, R0);
3565         }
3566 
3567         // Here's a basic summary of what the initial program does:
3568         //
3569         // if it is a loopback (src mac is nic's primary mac) packet
3570         //    if 25Q2+:
3571         //      drop
3572         //    else
3573         //      pass
3574         // if it's a TDLS packet:
3575         //    it is unicast:
3576         //      pass
3577         //    else
3578         //      drop
3579         // if it's a 802.3 Frame (ethtype < 0x0600):
3580         //    drop or pass based on configurations
3581         // if it has a ether-type that belongs to the black list
3582         //    drop
3583         // if it's ARP:
3584         //   insert ARP filter to drop or pass these appropriately
3585         // if it's IPv4:
3586         //   insert IPv4 filter to drop or pass these appropriately
3587         // if it's not IPv6:
3588         //   if it's broadcast:
3589         //     drop
3590         //   pass
3591         // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
3592 
3593         if (NetworkStackUtils.isAtLeast25Q2()) {
3594             gen.addCountAndDropIfBytesAtOffsetEqual(ETHER_SRC_ADDR_OFFSET, mHardwareAddress,
3595                     DROPPED_ETHER_OUR_SRC_MAC);
3596         } else {
3597             // TODO: we don't have test coverage for this line
3598             gen.addCountAndPassIfBytesAtOffsetEqual(ETHER_SRC_ADDR_OFFSET, mHardwareAddress,
3599                     PASSED_ETHER_OUR_SRC_MAC);
3600         }
3601 
3602         gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET);
3603         if (SdkLevel.isAtLeastV()) {
3604             // Pass unicast TDLS packet but drop non-unicast TDLS packet.
3605             short skipTDLScheck = gen.getUniqueLabel();
3606             gen.addJumpIfR0NotEquals(0x890DL, skipTDLScheck)
3607                     .addCountAndDropIfBytesAtOffsetNotEqual(
3608                             ETH_DEST_ADDR_OFFSET, mHardwareAddress, DROPPED_NON_UNICAST_TDLS)
3609                     .addCountAndPass(PASSED_NON_IP_UNICAST)
3610                     .defineLabel(skipTDLScheck);
3611 
3612             // IPv4, ARP, IPv6, EAPOL, WAPI
3613             gen.addCountAndDropIfR0IsNoneOf(
3614                     Set.of(0x0800L, 0x0806L, 0x86DDL, 0x888EL, 0x88B4L),
3615                     DROPPED_ETHERTYPE_NOT_ALLOWED);
3616         } else  {
3617             if (mDrop802_3Frames) {
3618                 // drop 802.3 frames (ethtype < 0x0600)
3619                 gen.addCountAndDropIfR0LessThan(ETH_TYPE_MIN, DROPPED_802_3_FRAME);
3620             }
3621             // Handle ether-type black list
3622             if (mEthTypeBlackList.length > 0) {
3623                 final Set<Long> deniedEtherTypes = new ArraySet<>();
3624                 for (int p : mEthTypeBlackList) {
3625                     deniedEtherTypes.add((long) p);
3626                 }
3627                 gen.addCountAndDropIfR0IsOneOf(deniedEtherTypes, DROPPED_ETHERTYPE_NOT_ALLOWED);
3628             }
3629         }
3630 
3631         // Add ARP filters:
3632         short skipArpFiltersLabel = gen.getUniqueLabel();
3633         gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
3634         generateArpFilter(gen);
3635         gen.defineLabel(skipArpFiltersLabel);
3636 
3637         gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET);
3638 
3639         // Add IPv4 filters:
3640         short skipIPv4FiltersLabel = gen.getUniqueLabel();
3641         gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
3642         generateIPv4Filter(gen, labelCheckMdnsQueryPayload);
3643         gen.defineLabel(skipIPv4FiltersLabel);
3644 
3645         // Check for IPv6:
3646         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did
3647         // not execute the IPv4 filter, since this filter do not fall through, but either drop or
3648         // pass.
3649         short ipv6FilterLabel = gen.getUniqueLabel();
3650         gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
3651 
3652         // Drop non-IP non-ARP broadcasts, pass the rest
3653         gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST,
3654                 PASSED_NON_IP_UNICAST);
3655         gen.addCountAndDrop(DROPPED_ETH_BROADCAST);
3656 
3657         // Add IPv6 filters:
3658         gen.defineLabel(ipv6FilterLabel);
3659         generateIPv6Filter(gen, labelCheckMdnsQueryPayload);
3660     }
3661 
getApfConfigMessage()3662     private String getApfConfigMessage() {
3663         final StringBuilder sb = new StringBuilder();
3664         sb.append("{ ");
3665         sb.append("mcast: ");
3666         sb.append(mMulticastFilter ? "DROP" : "ALLOW");
3667         sb.append(", ");
3668         sb.append("doze: ");
3669         sb.append(mInDozeMode ? "TRUE" : "FALSE");
3670         sb.append(", ");
3671         sb.append("offloads: ");
3672         sb.append("[ ");
3673         if (enableArpOffload()) {
3674             sb.append("ARP, ");
3675         }
3676         if (enableNdOffload()) {
3677             sb.append("ND, ");
3678         }
3679         if (enableIgmpOffload()) {
3680             sb.append("IGMP, ");
3681         }
3682         if (enableMldOffload()) {
3683             sb.append("MLD, ");
3684         }
3685         if (enableIpv4PingOffload()) {
3686             sb.append("Ping4, ");
3687         }
3688         if (enableIpv6PingOffload()) {
3689             sb.append("Ping6, ");
3690         }
3691         if (enableMdns4Offload()) {
3692             sb.append("Mdns4, ");
3693         }
3694         if (enableMdns6Offload()) {
3695             sb.append("Mdns6, ");
3696         }
3697         sb.append("] ");
3698         sb.append("total RAs: ");
3699         sb.append(mRas.size());
3700         sb.append(" filtered RAs: ");
3701         sb.append(mNumFilteredRas);
3702         sb.append(" mDNSs: ");
3703         sb.append(mOffloadRules.size());
3704         sb.append(" }");
3705         return sb.toString();
3706     }
3707 
installPacketFilter(byte[] program, String logInfo)3708     private void installPacketFilter(byte[] program, String logInfo) {
3709         if (!mApfController.installPacketFilter(program, logInfo)) {
3710             sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE);
3711         }
3712     }
3713 
createApfGenerator()3714     private ApfV4GeneratorBase<?> createApfGenerator() throws IllegalInstructionException {
3715         if (useApfV61Generator()) {
3716             return new ApfV61Generator(mApfVersionSupported, mApfRamSize,
3717                     mInstallableProgramSizeClamp);
3718         } else if (useApfV6Generator()) {
3719             return new ApfV6Generator(mApfVersionSupported, mApfRamSize,
3720                     mInstallableProgramSizeClamp);
3721         } else {
3722             return new ApfV4Generator(mApfVersionSupported, mApfRamSize,
3723                     mInstallableProgramSizeClamp);
3724         }
3725     }
3726 
3727     @VisibleForTesting
getOverEstimatedProgramSize()3728     public int getOverEstimatedProgramSize() {
3729         return mOverEstimatedProgramSize;
3730     }
3731 
calcMdnsOffloadProgramSizeOverEstimate(int numOfMdnsRuleToOffload)3732     private int calcMdnsOffloadProgramSizeOverEstimate(int numOfMdnsRuleToOffload)
3733             throws IllegalInstructionException {
3734         ApfV6GeneratorBase<?> gen = (ApfV6GeneratorBase<?>) createApfGenerator();
3735         // We need to preload data for size estimation because the preloaded data contains mDNS
3736         // data chunks. If we don't preload, generateMdnsQueryOffload() will add data to the data
3737         // region, resulting in an incorrect estimated size.
3738         if (gen instanceof ApfV61GeneratorBase<?>) {
3739             preloadData((ApfV61GeneratorBase<?>) gen);
3740         }
3741         final int programLengthOverEstimateBefore = gen.programLengthOverEstimate();
3742         short tmpLabelCheckMdnsQueryPayload = gen.getUniqueLabel();
3743         generateMdnsQueryOffload(gen, tmpLabelCheckMdnsQueryPayload,
3744                 numOfMdnsRuleToOffload);
3745         return gen.programLengthOverEstimate() - programLengthOverEstimateBefore;
3746     }
3747 
preloadData(ApfV61GeneratorBase<?> gen)3748     void preloadData(ApfV61GeneratorBase<?> gen) throws IllegalInstructionException {
3749         final List<byte[]> preloadedMacAddress = getKnownMacAddresses();
3750         final List<byte[]> preloadedIPv6Address = getIpv6Addresses(true /* includeNonTentative */,
3751                 true /* includeTentative */, true /* includeAnycast */);
3752         preloadedIPv6Address.add(IPV6_ADDR_ALL_NODES_MULTICAST.getAddress());
3753         preloadedIPv6Address.add(IPV6_ADDR_ANY.getAddress());
3754         byte[] mdns6NextHdrToUdpDport = new byte[0];
3755         byte[] mdns6EthDstToFlowLabel = new byte[0];
3756         byte[] mdns4EthDstToTos = new byte[0];
3757         if (enableMdns6Offload()) {
3758             mdns6NextHdrToUdpDport = createMdns6PktFromIPv6NextHdrToUdpDport(true);
3759             preloadedIPv6Address.removeIf(
3760                     addr -> Arrays.equals(addr, mIPv6LinkLocalAddress.getAddress()));
3761             mdns6EthDstToFlowLabel = createMdns6PktFromEthDstToIPv6FlowLabel(true);
3762             preloadedMacAddress.removeIf(
3763                     addr -> Arrays.equals(addr, mHardwareAddress) || Arrays.equals(addr,
3764                             ETH_MULTICAST_MDNS_V6_MAC_ADDRESS));
3765         }
3766 
3767         if (enableMdns4Offload()) {
3768             mdns4EthDstToTos = createMdns4PktFromEthDstToIPv4Tos(true);
3769             preloadedMacAddress.removeIf(
3770                     addr -> Arrays.equals(addr, mHardwareAddress) || Arrays.equals(addr,
3771                             ETH_MULTICAST_MDNS_V4_MAC_ADDRESS));
3772         }
3773 
3774         int preloadDataSize = mdns6NextHdrToUdpDport.length + mdns6EthDstToFlowLabel.length
3775                 + mdns4EthDstToTos.length + preloadedIPv6Address.size() * 16
3776                 + preloadedMacAddress.size() * 6;
3777 
3778         if (enableArpOffload()) {
3779             preloadDataSize += FIXED_ARP_REPLY_HEADER.length;
3780         }
3781 
3782         final byte[] preloadData = new byte[preloadDataSize];
3783         int offset = 0;
3784         System.arraycopy(mdns6NextHdrToUdpDport, 0, preloadData, offset,
3785                 mdns6NextHdrToUdpDport.length);
3786         offset += mdns6NextHdrToUdpDport.length;
3787         System.arraycopy(mdns6EthDstToFlowLabel, 0, preloadData, offset,
3788                 mdns6EthDstToFlowLabel.length);
3789         offset += mdns6EthDstToFlowLabel.length;
3790         System.arraycopy(mdns4EthDstToTos, 0, preloadData, offset, mdns4EthDstToTos.length);
3791         offset += mdns4EthDstToTos.length;
3792         for (byte[] addr : preloadedMacAddress) {
3793             System.arraycopy(addr, 0, preloadData, offset, 6);
3794             offset += 6;
3795         }
3796         for (byte[] addr : preloadedIPv6Address) {
3797             System.arraycopy(addr, 0, preloadData, offset, 16);
3798             offset += 16;
3799         }
3800         if (enableArpOffload()) {
3801             System.arraycopy(FIXED_ARP_REPLY_HEADER, 0, preloadData, offset,
3802                     FIXED_ARP_REPLY_HEADER.length);
3803             offset += FIXED_ARP_REPLY_HEADER.length;
3804         }
3805 
3806         if (preloadDataSize > 0) {
3807             gen.addPreloadData(preloadData);
3808         }
3809     }
3810 
3811     /**
3812      * Generate and install a new filter program.
3813      */
3814     @VisibleForTesting
installNewProgram()3815     public void installNewProgram() {
3816         ArrayList<Ra> rasToFilter = new ArrayList<>();
3817         final byte[] program;
3818         int programMinLft = Integer.MAX_VALUE;
3819 
3820         // Ensure the entire APF program uses the same time base.
3821         final int timeSeconds = secondsSinceBoot();
3822         // Every return from this function calls installPacketFilter().
3823         mLastTimeInstalledProgram = timeSeconds;
3824 
3825         // Increase the counter before we generate the program.
3826         // This keeps the APF_PROGRAM_ID counter in sync with the program.
3827         mNumProgramUpdates++;
3828 
3829         try {
3830             // Step 1: Determine how many RA filters/mDNS offloads we can fit in the program.
3831             ApfV4GeneratorBase<?> gen = createApfGenerator();
3832             if (gen instanceof ApfV61GeneratorBase<?>) {
3833                 preloadData((ApfV61GeneratorBase<?>) gen);
3834             }
3835             short labelCheckMdnsQueryPayload = gen.getUniqueLabel();
3836 
3837             emitPrologue(gen, labelCheckMdnsQueryPayload);
3838 
3839             int programLengthOverEstimate = gen.programLengthOverEstimate();
3840 
3841             // The default packet handling normally goes after the RA filters, but add it early to
3842             // include its length when estimating the total.
3843             programLengthOverEstimate += gen.getDefaultPacketHandlingSizeOverEstimate();
3844 
3845             // Can't fit the program even without any RA filters/Mdns offloads?
3846             if (programLengthOverEstimate > mMaximumApfProgramSize) {
3847                 Log.e(TAG, "Program exceeds maximum size " + mMaximumApfProgramSize);
3848                 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
3849                 installPacketFilter(new byte[mMaximumApfProgramSize],
3850                         getApfConfigMessage() + " (clear memory, reason: program too large)");
3851                 return;
3852             }
3853 
3854             // We attempt to fit the mDNS offload rules into the program before fitting RAs. The
3855             // strategy is as follows:
3856             // 1. If sufficient memory is available, offload all rules.
3857             // 2. If memory is insufficient, switch low-priority rules to passthrough mode.
3858             // 3. If memory remains insufficient after all rules are switched to passthrough
3859             // mode, fail open to pass all mDNS packets.
3860             //
3861             // We prioritize mDNS offload over RA filters because:
3862             // 1. We plan to move away from the multicast lock API, making mDNS offload critical
3863             // for the application's proper function. Without it, app developers would likely
3864             // still use the multicast lock, which would wake the device for almost all
3865             // multicast traffic, leading to serious power problems.
3866             // 2. For devices like TVs, reliable mDNS offload is key to meeting EU power regulation
3867             // requirement. These devices are usually on home networks with very chatty mDNS
3868             // traffic.
3869             if (enableMdns4Offload() || enableMdns6Offload()) {
3870                 final int remainSize = mMaximumApfProgramSize - programLengthOverEstimate;
3871                 mNumOfMdnsRuleToOffload = mOffloadRules.size();
3872                 int mDnsProgramLengthOverEstimate = 0;
3873                 for (; mNumOfMdnsRuleToOffload >= -1; --mNumOfMdnsRuleToOffload) {
3874                     mDnsProgramLengthOverEstimate = calcMdnsOffloadProgramSizeOverEstimate(
3875                             mNumOfMdnsRuleToOffload);
3876                     if (mDnsProgramLengthOverEstimate <= remainSize) {
3877                         break;
3878                     }
3879                 }
3880 
3881                 // When the size of offload rules is non-zero, at bare minimum, the
3882                 // program should be pass the mDNS packets. Otherwise, the application use case will
3883                 // be broken after we migrate away from multicast lock.
3884                 // If the remaining size is insufficient for mDNS fail-open, we should fail-open
3885                 // for the entire program.
3886                 if (mNumOfMdnsRuleToOffload < -1) {
3887                     Log.e(TAG, "Program exceeds maximum size (unable to fail-open for mDNS)  "
3888                             + mMaximumApfProgramSize);
3889                     sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
3890                     installPacketFilter(new byte[mMaximumApfProgramSize], getApfConfigMessage()
3891                             + " (clear memory, reason: unable to fail-open for mDNS)");
3892                     return;
3893                 }
3894 
3895                 programLengthOverEstimate += mDnsProgramLengthOverEstimate;
3896             } else {
3897                 mNumOfMdnsRuleToOffload = -1;
3898             }
3899 
3900 
3901             for (Ra ra : mRas) {
3902                 // skip filter if it has expired.
3903                 if (ra.getRemainingFilterLft(timeSeconds) <= 0) continue;
3904                 programLengthOverEstimate += ra.getRaProgramLengthOverEstimate(timeSeconds);
3905                 // Stop if we get too big.
3906                 if (programLengthOverEstimate > mMaximumApfProgramSize) {
3907                     Log.i(TAG, "Past maximum program size, skipping RAs");
3908                     break;
3909                 }
3910 
3911                 ra.generateFilter(gen, timeSeconds);
3912                 programMinLft = Math.min(programMinLft, ra.getRemainingFilterLft(timeSeconds));
3913                 rasToFilter.add(ra);
3914             }
3915 
3916             gen.addDefaultPacketHandling();
3917             if (enableMdns4Offload() || enableMdns6Offload()) {
3918                 generateMdnsQueryOffload((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload,
3919                         mNumOfMdnsRuleToOffload);
3920             }
3921 
3922             mNumFilteredRas = rasToFilter.size();
3923             mOverEstimatedProgramSize = gen.programLengthOverEstimate();
3924             program = gen.generate();
3925         } catch (IllegalInstructionException | IllegalStateException | IllegalArgumentException e) {
3926             Log.wtf(TAG, "Failed to generate APF program.", e);
3927             sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_GENERATE_FILTER_EXCEPTION);
3928             installPacketFilter(new byte[mMaximumApfProgramSize],
3929                     getApfConfigMessage() + String.format(" (clear memory, reason: %s)",
3930                             e.getMessage()));
3931             return;
3932         }
3933         if (mIsRunning) {
3934             if (program.length > mMaximumApfProgramSize) {
3935                 Log.wtf(TAG, String.format(
3936                         "Size estimation logic is wrong: final program size: %d exceeds maximum "
3937                                 + "size: %d. ",
3938                         program.length, mMaximumApfProgramSize));
3939                 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE);
3940                 installPacketFilter(new byte[mMaximumApfProgramSize],
3941                         getApfConfigMessage() + " (clear memory, reason: wrong size estimation)");
3942                 return;
3943             }
3944             installPacketFilter(program, getApfConfigMessage());
3945         }
3946         mLastInstalledProgramMinLifetime = programMinLft;
3947         mLastInstalledProgram = program;
3948         mMaxProgramSize = Math.max(mMaxProgramSize, program.length);
3949 
3950     }
3951 
hexDump(String msg, byte[] packet, int length)3952     private void hexDump(String msg, byte[] packet, int length) {
3953         log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
3954     }
3955 
3956     // Get the minimum value excludes zero. This is used for calculating the lowest lifetime values
3957     // in RA packets. Zero lifetimes are excluded because we want to detect whether there is any
3958     // unusually small lifetimes but zero lifetime is actually valid (cease to be a default router
3959     // or the option is no longer be used). Number of zero lifetime RAs is collected in a different
3960     // Metrics.
getMinForPositiveValue(long oldMinValue, long value)3961     private long getMinForPositiveValue(long oldMinValue, long value) {
3962         if (value < 1) return oldMinValue;
3963         return Math.min(oldMinValue, value);
3964     }
3965 
getMinForPositiveValue(int oldMinValue, int value)3966     private int getMinForPositiveValue(int oldMinValue, int value) {
3967         return (int) getMinForPositiveValue((long) oldMinValue, (long) value);
3968     }
3969 
3970     /**
3971      * Process an RA packet, updating the list of known RAs and installing a new APF program
3972      * if the current APF program should be updated.
3973      */
3974     @VisibleForTesting
processRa(byte[] packet, int length)3975     public void processRa(byte[] packet, int length) {
3976         final Ra ra;
3977         try {
3978             ra = new Ra(packet, length);
3979         } catch (Exception e) {
3980             Log.e(TAG, "Error parsing RA", e);
3981             mNumParseErrorRas++;
3982             return;
3983         }
3984 
3985         // Update info for Metrics
3986         mLowestRouterLifetimeSeconds = getMinForPositiveValue(
3987                 mLowestRouterLifetimeSeconds, ra.mRouterLifetime);
3988         mLowestPioValidLifetimeSeconds = getMinForPositiveValue(
3989                 mLowestPioValidLifetimeSeconds, ra.mMinPioValidLifetime);
3990         mLowestRioRouteLifetimeSeconds = getMinForPositiveValue(
3991                 mLowestRioRouteLifetimeSeconds, ra.mMinRioRouteLifetime);
3992         mLowestRdnssLifetimeSeconds = getMinForPositiveValue(
3993                 mLowestRdnssLifetimeSeconds, ra.mMinRdnssLifetime);
3994 
3995         // Remove all expired RA filters before trying to match the new RA.
3996         // TODO: matches() still checks that the old RA filter has not expired. Consider removing
3997         // that check.
3998         final int now = secondsSinceBoot();
3999         mRas.removeIf(item -> item.getRemainingFilterLft(now) <= 0);
4000 
4001         // Have we seen this RA before?
4002         for (int i = 0; i < mRas.size(); i++) {
4003             final Ra oldRa = mRas.get(i);
4004             final Ra.MatchType result = oldRa.matches(ra);
4005             if (result == Ra.MatchType.MATCH_PASS) {
4006                 log("Updating RA from " + oldRa + " to " + ra);
4007 
4008                 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
4009                 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
4010                 // until the filter program exceeds the maximum filter program size allowed by the
4011                 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
4012                 // filter program.
4013                 // TODO: consider sorting the RAs in order of increasing expiry time as well.
4014                 // Swap to front of array.
4015                 mRas.remove(i);
4016                 mRas.add(0, ra);
4017 
4018                 // Rate limit program installation
4019                 if (mTokenBucket.get()) {
4020                     installNewProgram();
4021                 } else {
4022                     Log.e(TAG, "Failed to install prog for tracked RA, too many updates. " + ra);
4023                 }
4024                 return;
4025             } else if (result == Ra.MatchType.MATCH_DROP) {
4026                 log("Ignoring RA " + ra + " which matches " + oldRa);
4027                 return;
4028             }
4029         }
4030         mMaxDistinctRas = Math.max(mMaxDistinctRas, mRas.size() + 1);
4031         if (mRas.size() >= MAX_RAS) {
4032             // Remove the last (i.e. oldest) RA.
4033             mRas.remove(mRas.size() - 1);
4034         }
4035         log("Adding " + ra);
4036         mRas.add(0, ra);
4037         // Rate limit program installation
4038         if (mTokenBucket.get()) {
4039             installNewProgram();
4040         } else {
4041             Log.e(TAG, "Failed to install prog for new RA, too many updates. " + ra);
4042         }
4043     }
4044 
4045     /**
4046      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
4047      * filtering using APF programs.
4048      */
maybeCreate(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics)4049     public static ApfFilter maybeCreate(Handler handler, Context context, ApfConfiguration config,
4050             InterfaceParams ifParams, IApfController apfController,
4051             NetworkQuirkMetrics networkQuirkMetrics) {
4052         if (context == null || config == null || ifParams == null) return null;
4053         if (!ApfV4Generator.supportsVersion(config.apfVersionSupported)) {
4054             return null;
4055         }
4056         if (config.apfRamSize < 512) {
4057             Log.e(TAG, "Unacceptably small APF limit: " + config.apfRamSize);
4058             return null;
4059         }
4060 
4061         return new ApfFilter(handler, context, config, ifParams, apfController,
4062                 networkQuirkMetrics);
4063     }
4064 
collectAndSendMetrics()4065     private void collectAndSendMetrics() {
4066         if (mIpClientRaInfoMetrics == null || mApfSessionInfoMetrics == null) return;
4067         final long sessionDurationMs = mDependencies.elapsedRealtime() - mSessionStartMs;
4068         if (sessionDurationMs < mMinMetricsSessionDurationMs) return;
4069 
4070         // Collect and send IpClientRaInfoMetrics.
4071         mIpClientRaInfoMetrics.setMaxNumberOfDistinctRas(mMaxDistinctRas);
4072         mIpClientRaInfoMetrics.setNumberOfZeroLifetimeRas(mNumZeroLifetimeRas);
4073         mIpClientRaInfoMetrics.setNumberOfParsingErrorRas(mNumParseErrorRas);
4074         mIpClientRaInfoMetrics.setLowestRouterLifetimeSeconds(mLowestRouterLifetimeSeconds);
4075         mIpClientRaInfoMetrics.setLowestPioValidLifetimeSeconds(mLowestPioValidLifetimeSeconds);
4076         mIpClientRaInfoMetrics.setLowestRioRouteLifetimeSeconds(mLowestRioRouteLifetimeSeconds);
4077         mIpClientRaInfoMetrics.setLowestRdnssLifetimeSeconds(mLowestRdnssLifetimeSeconds);
4078         mIpClientRaInfoMetrics.statsWrite();
4079 
4080         // Collect and send ApfSessionInfoMetrics.
4081         mApfSessionInfoMetrics.setVersion(mApfVersionSupported);
4082         mApfSessionInfoMetrics.setMemorySize(mApfRamSize);
4083         mApfSessionInfoMetrics.setApfSessionDurationSeconds(
4084                 (int) (sessionDurationMs / DateUtils.SECOND_IN_MILLIS));
4085         mApfSessionInfoMetrics.setNumOfTimesApfProgramUpdated(mNumProgramUpdates);
4086         mApfSessionInfoMetrics.setMaxProgramSize(mMaxProgramSize);
4087         for (Map.Entry<Counter, Long> entry : mApfCounterTracker.getCounters().entrySet()) {
4088             if (entry.getValue() > 0) {
4089                 mApfSessionInfoMetrics.addApfCounter(entry.getKey(), entry.getValue());
4090             }
4091         }
4092         mApfSessionInfoMetrics.statsWrite();
4093     }
4094 
shutdown()4095     public void shutdown() {
4096         collectAndSendMetrics();
4097         // The shutdown() must be called from the IpClient's handler thread
4098         mRaPacketReader.stop();
4099         mRas.clear();
4100         mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver);
4101         mIsApfShutdown = true;
4102         if (SdkLevel.isAtLeastV() && mApfMdnsOffloadEngine != null) {
4103             mApfMdnsOffloadEngine.unregisterOffloadEngine();
4104         }
4105 
4106         if (mMulticastReportMonitor != null) {
4107             mMulticastReportMonitor.stop();
4108         }
4109     }
4110 
setMulticastFilter(boolean isEnabled)4111     public void setMulticastFilter(boolean isEnabled) {
4112         if (mMulticastFilter == isEnabled) return;
4113         mMulticastFilter = isEnabled;
4114         installNewProgram();
4115     }
4116 
4117     @VisibleForTesting
setDozeMode(boolean isEnabled)4118     public void setDozeMode(boolean isEnabled) {
4119         if (mInDozeMode == isEnabled) return;
4120         mInDozeMode = isEnabled;
4121         installNewProgram();
4122     }
4123 
4124     /** Retrieve the single IPv4 LinkAddress if there is one, otherwise return null. */
retrieveIPv4LinkAddress(LinkProperties lp)4125     private static LinkAddress retrieveIPv4LinkAddress(LinkProperties lp) {
4126         LinkAddress ipv4Address = null;
4127         for (LinkAddress address : lp.getLinkAddresses()) {
4128             if (!(address.getAddress() instanceof Inet4Address)) {
4129                 continue;
4130             }
4131             if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
4132                 // More than one IPv4 address, abort.
4133                 return null;
4134             }
4135             ipv4Address = address;
4136         }
4137         return ipv4Address;
4138     }
4139 
4140     /** Retrieve the pair of IPv6 Inet6Address set, otherwise return pair with two empty set.
4141      *  The first element is a set containing tentative IPv6 addresses,
4142      *  the second element is a set containing non-tentative IPv6 addresses
4143      *  */
4144     private static Pair<Set<Inet6Address>, Set<Inet6Address>>
retrieveIPv6LinkAddress(LinkProperties lp)4145             retrieveIPv6LinkAddress(LinkProperties lp) {
4146         final Set<Inet6Address> tentativeAddrs = new ArraySet<>();
4147         final Set<Inet6Address> nonTentativeAddrs = new ArraySet<>();
4148         for (LinkAddress address : lp.getLinkAddresses()) {
4149             if (!(address.getAddress() instanceof Inet6Address)) {
4150                 continue;
4151             }
4152 
4153             if ((address.getFlags() & IFA_F_TENTATIVE) == IFA_F_TENTATIVE) {
4154                 tentativeAddrs.add((Inet6Address) address.getAddress());
4155             } else {
4156                 nonTentativeAddrs.add((Inet6Address) address.getAddress());
4157             }
4158         }
4159 
4160 
4161         return new Pair<>(tentativeAddrs, nonTentativeAddrs);
4162     }
4163 
setLinkProperties(LinkProperties lp)4164     public void setLinkProperties(LinkProperties lp) {
4165         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
4166         final LinkAddress ipv4Address = retrieveIPv4LinkAddress(lp);
4167         final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
4168         final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
4169         final Pair<Set<Inet6Address>, Set<Inet6Address>>
4170                 ipv6Addresses = retrieveIPv6LinkAddress(lp);
4171 
4172         if ((prefix == mIPv4PrefixLength)
4173                 && Arrays.equals(addr, mIPv4Address)
4174                 && ipv6Addresses.first.equals(mIPv6TentativeAddresses)
4175                 && ipv6Addresses.second.equals(mIPv6NonTentativeAddresses)
4176         ) {
4177             return;
4178         }
4179         mIPv4Address = addr;
4180         mIPv4PrefixLength = prefix;
4181         mIPv6TentativeAddresses = ipv6Addresses.first;
4182         mIPv6NonTentativeAddresses = ipv6Addresses.second;
4183         mIPv6LinkLocalAddress = NetworkStackUtils.selectPreferredIPv6LinkLocalAddress(lp);
4184 
4185         installNewProgram();
4186     }
4187 
updateClatInterfaceState(boolean add)4188     public void updateClatInterfaceState(boolean add) {
4189         if (mHasClat == add) {
4190             return;
4191         }
4192         mHasClat = add;
4193         installNewProgram();
4194     }
4195 
updateIPv6MulticastAddrs()4196     private boolean updateIPv6MulticastAddrs() {
4197         final Set<Inet6Address> mcastAddrs =
4198                 new ArraySet<>(mDependencies.getIPv6MulticastAddresses(mInterfaceParams.name));
4199 
4200         if (!mIPv6MulticastAddresses.equals(mcastAddrs)) {
4201             mIPv6MulticastAddresses.clear();
4202             mIPv6MulticastAddresses.addAll(mcastAddrs);
4203 
4204             mIPv6McastAddrsExcludeAllHost.clear();
4205             mIPv6McastAddrsExcludeAllHost.addAll(mIPv6MulticastAddresses);
4206             mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_ALL_NODES_MULTICAST);
4207             mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST);
4208             return true;
4209         }
4210         return false;
4211     }
4212 
updateIPv4MulticastAddrs()4213     private boolean updateIPv4MulticastAddrs() {
4214         final Set<Inet4Address> mcastAddrs =
4215                 new ArraySet<>(mDependencies.getIPv4MulticastAddresses(mInterfaceParams.name));
4216 
4217         if (!mIPv4MulticastAddresses.equals(mcastAddrs)) {
4218             mIPv4MulticastAddresses.clear();
4219             mIPv4MulticastAddresses.addAll(mcastAddrs);
4220 
4221             mIPv4McastAddrsExcludeAllHost.clear();
4222             mIPv4McastAddrsExcludeAllHost.addAll(mcastAddrs);
4223             mIPv4McastAddrsExcludeAllHost.remove(IPV4_ADDR_ALL_HOST_MULTICAST);
4224             return true;
4225         }
4226         return false;
4227     }
4228 
4229     /**
4230      * Updates IPv4/IPv6 multicast addresses.
4231      */
updateMulticastAddrs()4232     public void updateMulticastAddrs() {
4233         boolean ipv6MulticastUpdated = updateIPv6MulticastAddrs();
4234         boolean ipv4MulticastUpdated = updateIPv4MulticastAddrs();
4235         if (ipv6MulticastUpdated || ipv4MulticastUpdated) {
4236             installNewProgram();
4237         }
4238     }
4239 
4240     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableArpOffload()4241     private boolean enableArpOffload() {
4242         return mHandleArpOffload && useApfV6Generator() && mIPv4Address != null;
4243     }
4244 
4245     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableNdOffload()4246     public boolean enableNdOffload() {
4247         return mHandleNdOffload && useApfV6Generator();
4248     }
4249 
4250     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableOffloadEngineRegistration()4251     private boolean enableOffloadEngineRegistration() {
4252         return mHandleMdnsOffload && useApfV6Generator();
4253     }
4254 
4255     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableIgmpReportsMonitor()4256     private boolean enableIgmpReportsMonitor() {
4257         return mHandleIgmpOffload && useApfV6Generator();
4258     }
4259 
4260     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableMdns4Offload()4261     private boolean enableMdns4Offload() {
4262         return enableOffloadEngineRegistration() && mIPv4Address != null
4263                 && !mOffloadRules.isEmpty();
4264     }
4265 
4266     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableMdns6Offload()4267     private boolean enableMdns6Offload() {
4268         return enableOffloadEngineRegistration() && mIPv6LinkLocalAddress != null
4269                 && !mOffloadRules.isEmpty();
4270     }
4271 
4272     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableIgmpOffload()4273     private boolean enableIgmpOffload() {
4274         // Since the all-hosts multicast address (224.0.0.1) is always present for IPv4
4275         // multicast, and IGMP packets are not needed for this address, IGMP offloading is only
4276         // necessary if there are additional joined multicast addresses
4277         // (mIPv4MulticastAddresses.size() > 1).
4278         return enableIgmpReportsMonitor() && mIPv4MulticastAddresses.size() > 1
4279                 && mIPv4Address != null;
4280     }
4281 
4282     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableIpv4PingOffload()4283     private boolean enableIpv4PingOffload() {
4284         return mHandleIpv4PingOffload && useApfV6Generator() && mIPv4Address != null;
4285     }
4286 
4287     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableIpv6PingOffload()4288     private boolean enableIpv6PingOffload() {
4289         return mHandleIpv6PingOffload && useApfV6Generator()
4290                 && !mIPv6NonTentativeAddresses.isEmpty();
4291     }
4292 
4293     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableMldReportsMonitor()4294     private boolean enableMldReportsMonitor() {
4295         return mHandleMldOffload && useApfV6Generator();
4296     }
4297 
4298     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
enableMldOffload()4299     private boolean enableMldOffload() {
4300         return enableMldReportsMonitor() && mIPv6LinkLocalAddress != null
4301                 && !mIPv6McastAddrsExcludeAllHost.isEmpty();
4302     }
4303 
4304     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
useApfV6Generator()4305     private boolean useApfV6Generator() {
4306         return SdkLevel.isAtLeastV() && ApfV6Generator.supportsVersion(mApfVersionSupported);
4307     }
4308 
4309     @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */)
useApfV61Generator()4310     private boolean useApfV61Generator() {
4311         return SdkLevel.isAtLeastV() && ApfV61Generator.supportsVersion(mApfVersionSupported);
4312     }
4313 
4314     /**
4315      * Add TCP keepalive ack packet filter.
4316      * This will add a filter to drop acks to the keepalive packet passed as an argument.
4317      *
4318      * @param slot The index used to access the filter.
4319      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
4320      */
addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)4321     public void addTcpKeepalivePacketFilter(final int slot,
4322             final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
4323         log("Adding keepalive ack(" + slot + ")");
4324         if (null != mKeepalivePackets.get(slot)) {
4325             throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
4326         }
4327         final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
4328         mKeepalivePackets.put(slot, (ipVersion == 4)
4329                 ? new TcpKeepaliveAckV4(sentKeepalivePacket)
4330                 : new TcpKeepaliveAckV6(sentKeepalivePacket));
4331         installNewProgram();
4332     }
4333 
4334     /**
4335      * Add NAT-T keepalive packet filter.
4336      * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
4337      *
4338      * @param slot The index used to access the filter.
4339      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
4340      */
addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)4341     public void addNattKeepalivePacketFilter(final int slot,
4342             final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
4343         log("Adding NAT-T keepalive packet(" + slot + ")");
4344         if (null != mKeepalivePackets.get(slot)) {
4345             throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
4346         }
4347 
4348         // TODO : update ApfFilter to support dropping v6 keepalives
4349         if (sentKeepalivePacket.srcAddress.length != 4) {
4350             return;
4351         }
4352 
4353         mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
4354         installNewProgram();
4355     }
4356 
4357     /**
4358      * Remove keepalive packet filter.
4359      *
4360      * @param slot The index used to access the filter.
4361      */
removeKeepalivePacketFilter(int slot)4362     public void removeKeepalivePacketFilter(int slot) {
4363         log("Removing keepalive packet(" + slot + ")");
4364         mKeepalivePackets.remove(slot);
4365         installNewProgram();
4366     }
4367 
4368     /**
4369      * Determines whether the APF interpreter advertises support for the data buffer access
4370      * opcodes LDDW (LoaD Data Word) and STDW (STore Data Word).
4371      */
hasDataAccess(int apfVersionSupported)4372     public boolean hasDataAccess(int apfVersionSupported) {
4373         return apfVersionSupported > 2;
4374     }
4375 
dump(IndentingPrintWriter pw)4376     public void dump(IndentingPrintWriter pw) {
4377         pw.println(String.format(
4378                 "Capabilities: { apfVersionSupported: %d, maximumApfProgramSize: %d }",
4379                 mApfVersionSupported, mApfRamSize));
4380         pw.println("InstallableProgramSizeClamp: " + mInstallableProgramSizeClamp);
4381         pw.println("Filter update status: " + (mIsRunning ? "RUNNING" : "PAUSED"));
4382         pw.println("ApfConfig: " + getApfConfigMessage());
4383         pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec);
4384         pw.println("Interface MAC address: " + MacAddress.fromBytes(mHardwareAddress));
4385         pw.println("Multicast MAC addresses:");
4386         pw.increaseIndent();
4387         for (byte[] addr : mDependencies.getEtherMulticastAddresses(mInterfaceParams.name)) {
4388             pw.println(MacAddress.fromBytes(addr));
4389         }
4390         pw.decreaseIndent();
4391         if (SdkLevel.isAtLeastV()) {
4392             pw.print("Hardcoded not denylisted Ethertypes:");
4393             pw.println(
4394                     " 0800(IPv4) 0806(ARP) 86DD(IPv6) 888E(EAPOL) 88B4(WAPI) 890D(TDLS unicast)");
4395         } else {
4396             pw.print("Denylisted Ethertypes:");
4397             for (int p : mEthTypeBlackList) {
4398                 pw.print(String.format(" %04x", p));
4399             }
4400         }
4401         try {
4402             pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
4403         } catch (UnknownHostException | NullPointerException e) {
4404             pw.println("IPv4 address: None");
4405         }
4406 
4407         pw.println("IPv4 multicast addresses:");
4408         pw.increaseIndent();
4409         final List<Inet4Address> ipv4McastAddrs =
4410                 ProcfsParsingUtils.getIPv4MulticastAddresses(mInterfaceParams.name);
4411         for (Inet4Address addr: ipv4McastAddrs) {
4412             pw.println(addr.getHostAddress());
4413         }
4414         pw.decreaseIndent();
4415         pw.println("IPv6 non-tentative addresses:");
4416         pw.increaseIndent();
4417         for (Inet6Address addr : mIPv6NonTentativeAddresses) {
4418             pw.println(addr.getHostAddress());
4419         }
4420         pw.decreaseIndent();
4421         pw.println("IPv6 tentative addresses:");
4422         pw.increaseIndent();
4423         for (Inet6Address addr : mIPv6TentativeAddresses) {
4424             pw.println(addr.getHostAddress());
4425         }
4426         pw.decreaseIndent();
4427         pw.println("IPv6 anycast addresses:");
4428         pw.increaseIndent();
4429         final List<Inet6Address> anycastAddrs =
4430                 ProcfsParsingUtils.getAnycast6Addresses(mInterfaceParams.name);
4431         for (Inet6Address addr : anycastAddrs) {
4432             pw.println(addr.getHostAddress());
4433         }
4434         pw.decreaseIndent();
4435         pw.println("IPv6 multicast addresses:");
4436         pw.increaseIndent();
4437         final List<Inet6Address> multicastAddrs =
4438                 ProcfsParsingUtils.getIpv6MulticastAddresses(mInterfaceParams.name);
4439         for (Inet6Address addr : multicastAddrs) {
4440             pw.println(addr.getHostAddress());
4441         }
4442         pw.decreaseIndent();
4443 
4444         if (mLastTimeInstalledProgram == 0) {
4445             pw.println("No program installed.");
4446             return;
4447         }
4448         pw.println("Program updates: " + mNumProgramUpdates);
4449         int filterAgeSeconds = secondsSinceBoot() - mLastTimeInstalledProgram;
4450         pw.println(String.format(
4451                 "Last program length %d, installed %ds ago, lifetime %ds",
4452                 mLastInstalledProgram.length, filterAgeSeconds,
4453                 mLastInstalledProgramMinLifetime));
4454         pw.println();
4455         pw.println("Mdns filters:");
4456         pw.increaseIndent();
4457         if (mNumOfMdnsRuleToOffload == -1) {
4458             pw.println("pass all mDNS packet");
4459         } else {
4460             for (int i = 0; i < mOffloadRules.size(); ++i) {
4461                 final MdnsOffloadRule rule = mOffloadRules.get(i);
4462                 if (i >= mNumOfMdnsRuleToOffload) {
4463                     pw.println(String.format("passthrough service: %s", rule.mFullServiceName));
4464                 } else {
4465                     pw.println(String.format("offload service: %s, payloadSize: %d",
4466                             rule.mFullServiceName,
4467                             rule.mOffloadPayload == null ? 0 : rule.mOffloadPayload.length));
4468                 }
4469             }
4470         }
4471         pw.decreaseIndent();
4472         pw.println();
4473         pw.println("RA filters:");
4474         pw.increaseIndent();
4475         for (int i = 0; i < mRas.size(); ++i) {
4476             if (i < mNumFilteredRas) {
4477                 pw.println("Filtered: ");
4478             } else {
4479                 pw.println("Ignored: ");
4480             }
4481             final Ra ra = mRas.get(i);
4482             pw.println(ra);
4483             pw.increaseIndent();
4484             pw.println(String.format(
4485                     "Last seen %ds ago", secondsSinceBoot() - ra.mLastSeen));
4486             pw.println("Last match:");
4487             pw.increaseIndent();
4488             pw.println(ra.getLastMatchingPacket());
4489             pw.decreaseIndent();
4490             pw.decreaseIndent();
4491         }
4492         pw.decreaseIndent();
4493 
4494         pw.println("TCP Keepalive filters:");
4495         pw.increaseIndent();
4496         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
4497             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
4498             if (keepalivePacket instanceof TcpKeepaliveAck) {
4499                 pw.print("Slot ");
4500                 pw.print(mKeepalivePackets.keyAt(i));
4501                 pw.print(": ");
4502                 pw.println(keepalivePacket);
4503             }
4504         }
4505         pw.decreaseIndent();
4506 
4507         pw.println("NAT-T Keepalive filters:");
4508         pw.increaseIndent();
4509         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
4510             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
4511             if (keepalivePacket instanceof NattKeepaliveResponse) {
4512                 pw.print("Slot ");
4513                 pw.print(mKeepalivePackets.keyAt(i));
4514                 pw.print(": ");
4515                 pw.println(keepalivePacket);
4516             }
4517         }
4518         pw.decreaseIndent();
4519 
4520         pw.println("Last program:");
4521         pw.increaseIndent();
4522         pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
4523         pw.decreaseIndent();
4524 
4525         pw.println("APF packet counters:");
4526         pw.increaseIndent();
4527         if (!hasDataAccess(mApfVersionSupported)) {
4528             pw.println("APF counters not supported");
4529         } else if (mDataSnapshot == null) {
4530             pw.println("No last snapshot.");
4531         } else {
4532             try {
4533                 Counter[] counters = Counter.class.getEnumConstants();
4534                 long counterFilterAgeSeconds =
4535                         getCounterValue(mDataSnapshot, FILTER_AGE_SECONDS);
4536                 long counterApfProgramId =
4537                         getCounterValue(mDataSnapshot, APF_PROGRAM_ID);
4538                 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
4539                     long value = getCounterValue(mDataSnapshot, c);
4540 
4541                     String note = "";
4542                     boolean checkValueIncreases = true;
4543                     switch (c) {
4544                         case FILTER_AGE_SECONDS:
4545                             checkValueIncreases = false;
4546                             if (value != counterFilterAgeSeconds) {
4547                                 note = " [ERROR: impossible]";
4548                             } else if (counterApfProgramId < mNumProgramUpdates) {
4549                                 note = " [IGNORE: obsolete program]";
4550                             } else if (value > filterAgeSeconds) {
4551                                 long offset = value - filterAgeSeconds;
4552                                 note = " [ERROR: in the future by " + offset + "s]";
4553                             }
4554                             break;
4555                         case FILTER_AGE_16384THS:
4556                             if (mApfVersionSupported > BaseApfGenerator.APF_VERSION_4) {
4557                                 checkValueIncreases = false;
4558                                 if (value % 16384 == 0) {
4559                                     // valid, but unlikely
4560                                     note = " [INFO: zero fractional portion]";
4561                                 }
4562                                 if (value / 16384 != counterFilterAgeSeconds) {
4563                                     // should not be able to happen
4564                                     note = " [ERROR: mismatch with FILTER_AGE_SECONDS]";
4565                                 }
4566                             } else if (value != 0) {
4567                                 note = " [UNEXPECTED: APF<=4, yet non-zero]";
4568                             }
4569                             break;
4570                         case APF_PROGRAM_ID:
4571                             if (value != counterApfProgramId) {
4572                                 note = " [ERROR: impossible]";
4573                             } else if (value < mNumProgramUpdates) {
4574                                 note = " [WARNING: OBSOLETE PROGRAM]";
4575                             } else if (value > mNumProgramUpdates) {
4576                                 note = " [ERROR: INVALID FUTURE ID]";
4577                             }
4578                             break;
4579                         default:
4580                             break;
4581                     }
4582 
4583                     // Only print non-zero counters (or those with a note)
4584                     if (value != 0 || !note.equals("")) {
4585                         pw.println(c.toString() + ": " + value + note);
4586                     }
4587 
4588                     if (checkValueIncreases) {
4589                         // If the counter's value decreases, it may have been cleaned up or there
4590                         // may be a bug.
4591                         long oldValue = mApfCounterTracker.getCounters().getOrDefault(c, 0L);
4592                         if (value < oldValue) {
4593                             Log.e(TAG, String.format(
4594                                     "Apf Counter: %s unexpectedly decreased. oldValue: %d. "
4595                                             + "newValue: %d", c.toString(), oldValue, value));
4596                         }
4597                     }
4598                 }
4599             } catch (ArrayIndexOutOfBoundsException e) {
4600                 pw.println("Uh-oh: " + e);
4601             }
4602         }
4603         pw.decreaseIndent();
4604     }
4605 
4606     /** Return ApfFilter update status for testing purposes. */
isRunning()4607     public boolean isRunning() {
4608         return mIsRunning;
4609     }
4610 
4611     /** Pause ApfFilter updates for testing purposes. */
pause()4612     public void pause() {
4613         mIsRunning = false;
4614     }
4615 
4616     /** Resume ApfFilter updates for testing purposes. */
resume()4617     public void resume() {
4618         maybeCleanUpApfRam();
4619         // Since the resume() function and cleanup process invalidate previous counter
4620         // snapshots, the ApfCounterTracker needs to be reset to maintain reliable, incremental
4621         // counter tracking.
4622         mApfCounterTracker.clearCounters();
4623         mIsRunning = true;
4624     }
4625 
4626     /** Return data snapshot as hex string for testing purposes. */
getDataSnapshotHexString()4627     public @Nullable String getDataSnapshotHexString() {
4628         if (mDataSnapshot == null) {
4629             return null;
4630         }
4631         return HexDump.toHexString(mDataSnapshot, 0, mDataSnapshot.length, false /* lowercase */);
4632     }
4633 
4634     // TODO: move to android.net.NetworkUtils
4635     @VisibleForTesting
ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)4636     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
4637         return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
4638     }
4639 
uint8(byte b)4640     private static int uint8(byte b) {
4641         return b & 0xff;
4642     }
4643 
getUint16(ByteBuffer buffer, int position)4644     private static int getUint16(ByteBuffer buffer, int position) {
4645         return buffer.getShort(position) & 0xffff;
4646     }
4647 
getUint32(ByteBuffer buffer, int position)4648     private static long getUint32(ByteBuffer buffer, int position) {
4649         return Integer.toUnsignedLong(buffer.getInt(position));
4650     }
4651 
getUint8(ByteBuffer buffer, int position)4652     private static int getUint8(ByteBuffer buffer, int position) {
4653         return uint8(buffer.get(position));
4654     }
4655 
bytesToBEInt(byte[] bytes)4656     private static int bytesToBEInt(byte[] bytes) {
4657         return (uint8(bytes[0]) << 24)
4658                 + (uint8(bytes[1]) << 16)
4659                 + (uint8(bytes[2]) << 8)
4660                 + (uint8(bytes[3]));
4661     }
4662 
sendNetworkQuirkMetrics(final NetworkQuirkEvent event)4663     private void sendNetworkQuirkMetrics(final NetworkQuirkEvent event) {
4664         if (mNetworkQuirkMetrics == null) return;
4665         mNetworkQuirkMetrics.setEvent(event);
4666         mNetworkQuirkMetrics.statsWrite();
4667     }
4668 }
4669