1 /*
2  * Copyright (C) 2017 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.ip;
18 
19 import static android.net.ip.IpClientLinkObserver.CONFIG_SOCKET_RECV_BUFSIZE;
20 import static android.net.ip.IpClientLinkObserver.SOCKET_RECV_BUFSIZE;
21 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
22 
23 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
24 import static com.android.net.module.util.netlink.NetlinkConstants.RTPROT_KERNEL;
25 import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELROUTE;
26 import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWADDR;
27 import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNDUSEROPT;
28 import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWROUTE;
29 import static com.android.net.module.util.netlink.NetlinkConstants.RTN_UNICAST;
30 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
31 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
32 
33 import static org.junit.Assert.assertArrayEquals;
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertNotNull;
37 import static org.junit.Assert.assertNull;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.mockito.ArgumentMatchers.anyBoolean;
41 import static org.mockito.Mockito.any;
42 import static org.mockito.Mockito.anyInt;
43 import static org.mockito.Mockito.anyString;
44 import static org.mockito.Mockito.clearInvocations;
45 import static org.mockito.Mockito.doReturn;
46 import static org.mockito.Mockito.eq;
47 import static org.mockito.Mockito.never;
48 import static org.mockito.Mockito.reset;
49 import static org.mockito.Mockito.timeout;
50 import static org.mockito.Mockito.verify;
51 import static org.mockito.Mockito.verifyNoMoreInteractions;
52 import static org.mockito.Mockito.when;
53 
54 import static java.util.Collections.emptySet;
55 
56 import android.annotation.SuppressLint;
57 import android.app.AlarmManager;
58 import android.content.ContentResolver;
59 import android.content.Context;
60 import android.content.res.Resources;
61 import android.net.ConnectivityManager;
62 import android.net.INetd;
63 import android.net.InetAddresses;
64 import android.net.IpPrefix;
65 import android.net.LinkAddress;
66 import android.net.LinkProperties;
67 import android.net.MacAddress;
68 import android.net.NetworkStackIpMemoryStore;
69 import android.net.RouteInfo;
70 import android.net.apf.ApfCapabilities;
71 import android.net.apf.ApfFilter.ApfConfiguration;
72 import android.net.ip.IpClientLinkObserver.IpClientNetlinkMonitor;
73 import android.net.ip.IpClientLinkObserver.IpClientNetlinkMonitor.INetlinkMessageProcessor;
74 import android.net.ipmemorystore.NetworkAttributes;
75 import android.net.metrics.IpConnectivityLog;
76 import android.net.shared.InitialConfiguration;
77 import android.net.shared.Layer2Information;
78 import android.net.shared.ProvisioningConfiguration;
79 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
80 import android.os.Build;
81 import android.system.OsConstants;
82 
83 import androidx.test.filters.SmallTest;
84 import androidx.test.runner.AndroidJUnit4;
85 
86 import com.android.modules.utils.build.SdkLevel;
87 import com.android.net.module.util.InterfaceParams;
88 import com.android.net.module.util.netlink.NduseroptMessage;
89 import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
90 import com.android.net.module.util.netlink.RtNetlinkRouteMessage;
91 import com.android.net.module.util.netlink.StructIfaddrMsg;
92 import com.android.net.module.util.netlink.StructNdOptRdnss;
93 import com.android.net.module.util.netlink.StructNlMsgHdr;
94 import com.android.net.module.util.netlink.StructRtMsg;
95 import com.android.networkstack.R;
96 import com.android.networkstack.ipmemorystore.IpMemoryStoreService;
97 import com.android.server.NetworkStackService;
98 import com.android.testutils.DevSdkIgnoreRule;
99 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
100 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
101 import com.android.testutils.HandlerUtils;
102 
103 import org.junit.Before;
104 import org.junit.Rule;
105 import org.junit.Test;
106 import org.junit.runner.RunWith;
107 import org.mockito.ArgumentCaptor;
108 import org.mockito.Mock;
109 import org.mockito.MockitoAnnotations;
110 
111 import java.io.FileDescriptor;
112 import java.io.PrintWriter;
113 import java.net.Inet4Address;
114 import java.net.Inet6Address;
115 import java.net.InetAddress;
116 import java.nio.ByteBuffer;
117 import java.util.Arrays;
118 import java.util.Collections;
119 import java.util.HashSet;
120 import java.util.List;
121 import java.util.Random;
122 import java.util.Set;
123 
124 
125 /**
126  * Tests for IpClient.
127  */
128 @RunWith(AndroidJUnit4.class)
129 @SmallTest
130 public class IpClientTest {
131     @Rule
132     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
133 
134     private static final String VALID = "VALID";
135     private static final String INVALID = "INVALID";
136     private static final String TEST_IFNAME = "test_wlan0";
137     private static final int TEST_IFINDEX = 1001;
138     // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
139     private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
140     private static final int TEST_TIMEOUT_MS = 30_000;
141     private static final String TEST_L2KEY = "some l2key";
142     private static final String TEST_CLUSTER = "some cluster";
143     private static final String TEST_SSID = "test_ssid";
144     private static final String TEST_BSSID = "00:11:22:33:44:55";
145     private static final String TEST_BSSID2 = "00:1A:11:22:33:44";
146 
147     private static final String TEST_GLOBAL_ADDRESS = "1234:4321::548d:2db2:4fcf:ef75/64";
148     private static final String[] TEST_LOCAL_ADDRESSES = {
149             "fe80::a4be:f92:e1f7:22d1/64",
150             "fe80::f04a:8f6:6a32:d756/64",
151             "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
152     };
153     private static final String TEST_IPV4_LINKADDRESS = "192.168.42.24/24";
154     private static final String[] TEST_PREFIXES = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
155     private static final String[] TEST_DNSES = { "fd2c:4e57:8e3c::42" };
156     private static final String TEST_IPV6_GATEWAY = "fd2c:4e57:8e3c::43";
157     private static final String TEST_IPV4_GATEWAY = "192.168.42.11";
158     private static final long TEST_DNS_LIFETIME = 3600;
159     // `whenMs` param in processNetlinkMessage is only used to process PREF64 option in RA, which
160     // is not used for RTM_NEWADDR, RTM_NEWROUTE and RDNSS option.
161     private static final long TEST_UNUSED_REAL_TIME = 0;
162 
163     @Mock private Context mContext;
164     @Mock private ConnectivityManager mCm;
165     @Mock private INetd mNetd;
166     @Mock private Resources mResources;
167     @Mock private IIpClientCallbacks mCb;
168     @Mock private AlarmManager mAlarm;
169     @Mock private IpClient.Dependencies mDependencies;
170     @Mock private ContentResolver mContentResolver;
171     @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
172     @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
173     @Mock private IpMemoryStoreService mIpMemoryStoreService;
174     @Mock private InterfaceParams mInterfaceParams;
175     @Mock private IpConnectivityLog mMetricsLog;
176     @Mock private FileDescriptor mFd;
177     @Mock private PrintWriter mWriter;
178     @Mock private IpClientNetlinkMonitor mNetlinkMonitor;
179 
180     private InterfaceParams mIfParams;
181     private INetlinkMessageProcessor mNetlinkMessageProcessor;
182 
183     @Before
setUp()184     public void setUp() throws Exception {
185         MockitoAnnotations.initMocks(this);
186 
187         when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
188         when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
189         when(mContext.getResources()).thenReturn(mResources);
190         when(mDependencies.getNetd(any())).thenReturn(mNetd);
191         when(mCm.shouldAvoidBadWifi()).thenReturn(true);
192         when(mContext.getContentResolver()).thenReturn(mContentResolver);
193         when(mNetworkStackServiceManager.getIpMemoryStoreService())
194                 .thenReturn(mIpMemoryStoreService);
195         when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams);
196         when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager))
197                 .thenReturn(mIpMemoryStore);
198         when(mDependencies.getIpConnectivityLog()).thenReturn(mMetricsLog);
199         when(mDependencies.getDeviceConfigPropertyInt(eq(CONFIG_SOCKET_RECV_BUFSIZE), anyInt()))
200                 .thenReturn(SOCKET_RECV_BUFSIZE);
201         when(mDependencies.makeIpClientNetlinkMonitor(
202                 any(), any(), any(), anyInt(), any())).thenReturn(mNetlinkMonitor);
203         when(mNetlinkMonitor.start()).thenReturn(true);
204 
205         mIfParams = null;
206     }
207 
setTestInterfaceParams(String ifname)208     private void setTestInterfaceParams(String ifname) {
209         mIfParams = (ifname != null)
210                 ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
211                 : null;
212         when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
213     }
214 
makeIpClient(String ifname)215     private IpClient makeIpClient(String ifname) throws Exception {
216         setTestInterfaceParams(ifname);
217         final IpClient ipc =
218                 new IpClient(mContext, ifname, mCb, mNetworkStackServiceManager, mDependencies);
219         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
220         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
221         final ArgumentCaptor<INetlinkMessageProcessor> processorCaptor =
222                 ArgumentCaptor.forClass(INetlinkMessageProcessor.class);
223         verify(mDependencies).makeIpClientNetlinkMonitor(any(), any(), any(), anyInt(),
224                 processorCaptor.capture());
225         mNetlinkMessageProcessor = processorCaptor.getValue();
226         reset(mNetd);
227         // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
228         verify(mCb, never()).onLinkPropertiesChange(any());
229         reset(mCb);
230         return ipc;
231     }
232 
makeEmptyLinkProperties(String iface)233     private static LinkProperties makeEmptyLinkProperties(String iface) {
234         final LinkProperties empty = new LinkProperties();
235         empty.setInterfaceName(iface);
236         return empty;
237     }
238 
verifyNetworkAttributesStored(final String l2Key, final NetworkAttributes attributes)239     private void verifyNetworkAttributesStored(final String l2Key,
240             final NetworkAttributes attributes) {
241         // TODO : when storing is implemented, turn this on
242         // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
243     }
244 
makeNetlinkMessageHeader(short type, short flags)245     private static StructNlMsgHdr makeNetlinkMessageHeader(short type, short flags) {
246         final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
247         nlmsghdr.nlmsg_type = type;
248         nlmsghdr.nlmsg_flags = flags;
249         nlmsghdr.nlmsg_seq = 1;
250         return nlmsghdr;
251     }
252 
buildRtmAddressMessage(short type, final LinkAddress la, int ifindex, int flags)253     private static RtNetlinkAddressMessage buildRtmAddressMessage(short type, final LinkAddress la,
254             int ifindex, int flags) {
255         final StructNlMsgHdr nlmsghdr =
256                 makeNetlinkMessageHeader(type, (short) (NLM_F_REQUEST | NLM_F_ACK));
257         InetAddress ip = la.getAddress();
258         final byte family =
259                 (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
260         StructIfaddrMsg ifaddrMsg = new StructIfaddrMsg(family,
261                 (short) la.getPrefixLength(),
262                 (short) la.getFlags(), (short) la.getScope(), ifindex);
263 
264         return new RtNetlinkAddressMessage(nlmsghdr, ifaddrMsg, ip,
265                 null /* structIfacacheInfo */, flags);
266     }
267 
buildRtmRouteMessage(short type, final RouteInfo route, int ifindex)268     private static RtNetlinkRouteMessage buildRtmRouteMessage(short type, final RouteInfo route,
269             int ifindex) {
270         final StructNlMsgHdr nlmsghdr =
271                 makeNetlinkMessageHeader(type, (short) (NLM_F_REQUEST | NLM_F_ACK));
272         final IpPrefix destination = route.getDestination();
273         final byte family = (byte) ((destination.getAddress() instanceof Inet6Address)
274                 ? OsConstants.AF_INET6
275                 : OsConstants.AF_INET);
276 
277         final StructRtMsg rtMsg = new StructRtMsg(family,
278                 (short) destination.getPrefixLength() /* dstLen */, (short) 0 /* srcLen */,
279                 (short) 0 /* tos */, (short) 0xfd /* main table */, RTPROT_KERNEL /* protocol */,
280                 (short) RT_SCOPE_UNIVERSE /* scope */, RTN_UNICAST /* type */, 0 /* flags */);
281         return new RtNetlinkRouteMessage(nlmsghdr, rtMsg, null /* source */, route.getDestination(),
282                 route.getGateway(), 0 /* iif */, ifindex /* oif */, null /* cacheInfo */);
283     }
284 
buildNduseroptMessage(int ifindex, long lifetime, final String[] servers)285     private static NduseroptMessage buildNduseroptMessage(int ifindex, long lifetime,
286             final String[] servers) {
287         final StructNlMsgHdr nlmsghdr =
288                 makeNetlinkMessageHeader(RTM_NEWNDUSEROPT, (short) (NLM_F_REQUEST | NLM_F_ACK));
289         final Inet6Address[] serverArray = new Inet6Address[servers.length];
290         for (int i = 0; i < servers.length; i++) {
291             serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]);
292         }
293         final StructNdOptRdnss option = new StructNdOptRdnss(serverArray, lifetime);
294         return new NduseroptMessage(nlmsghdr, (byte) OsConstants.AF_INET6 /* family */,
295                 0 /* opts_len */, ifindex, (byte) ICMPV6_ROUTER_ADVERTISEMENT /* icmp_type */,
296                 (byte) 0 /* icmp_code */, option, null /* srcaddr */);
297     }
298 
onInterfaceAddressUpdated(final LinkAddress la, int flags)299     private void onInterfaceAddressUpdated(final LinkAddress la, int flags) {
300         final RtNetlinkAddressMessage msg =
301                 buildRtmAddressMessage(RTM_NEWADDR, la, TEST_IFINDEX, flags);
302         mNetlinkMessageProcessor.processNetlinkMessage(msg, TEST_UNUSED_REAL_TIME /* whenMs */);
303     }
304 
onRouteUpdated(final RouteInfo route)305     private void onRouteUpdated(final RouteInfo route) {
306         final RtNetlinkRouteMessage msg = buildRtmRouteMessage(RTM_NEWROUTE, route, TEST_IFINDEX);
307         mNetlinkMessageProcessor.processNetlinkMessage(msg, TEST_UNUSED_REAL_TIME /* whenMs */);
308     }
309 
onRouteRemoved(final RouteInfo route)310     private void onRouteRemoved(final RouteInfo route) {
311         final RtNetlinkRouteMessage msg = buildRtmRouteMessage(RTM_DELROUTE, route, TEST_IFINDEX);
312         mNetlinkMessageProcessor.processNetlinkMessage(msg, TEST_UNUSED_REAL_TIME /* whenMs */);
313     }
314 
onInterfaceDnsServerInfo(long lifetime, final String[] dnsServers)315     private void onInterfaceDnsServerInfo(long lifetime, final String[] dnsServers) {
316         final NduseroptMessage msg = buildNduseroptMessage(TEST_IFINDEX, lifetime, dnsServers);
317         mNetlinkMessageProcessor.processNetlinkMessage(msg, TEST_UNUSED_REAL_TIME /* whenMs */);
318     }
319 
320     @Test
testNullInterfaceNameMostDefinitelyThrows()321     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
322         setTestInterfaceParams(null);
323         try {
324             final IpClient ipc = new IpClient(mContext, null, mCb, mNetworkStackServiceManager,
325                     mDependencies);
326             ipc.shutdown();
327             fail();
328         } catch (NullPointerException npe) {
329             // Phew; null interface names not allowed.
330         }
331     }
332 
333     @Test
testNullCallbackMostDefinitelyThrows()334     public void testNullCallbackMostDefinitelyThrows() throws Exception {
335         final String ifname = "lo";
336         setTestInterfaceParams(ifname);
337         try {
338             final IpClient ipc = new IpClient(mContext, ifname, null, mNetworkStackServiceManager,
339                     mDependencies);
340             ipc.shutdown();
341             fail();
342         } catch (NullPointerException npe) {
343             // Phew; null callbacks not allowed.
344         }
345     }
346 
347     @Test
testInvalidInterfaceDoesNotThrow()348     public void testInvalidInterfaceDoesNotThrow() throws Exception {
349         setTestInterfaceParams(TEST_IFNAME);
350         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mNetworkStackServiceManager,
351                 mDependencies);
352         verifyNoMoreInteractions(mIpMemoryStore);
353         ipc.shutdown();
354     }
355 
356     @Test
testInterfaceNotFoundFailsImmediately()357     public void testInterfaceNotFoundFailsImmediately() throws Exception {
358         setTestInterfaceParams(null);
359         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mNetworkStackServiceManager,
360                 mDependencies);
361         ipc.startProvisioning(new ProvisioningConfiguration());
362         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningFailure(any());
363         verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
364         ipc.shutdown();
365     }
366 
makeIPv6ProvisionedLinkProperties()367     private LinkProperties makeIPv6ProvisionedLinkProperties() {
368         // Add local addresses, and a global address with global scope
369         final Set<LinkAddress> addresses = links(TEST_LOCAL_ADDRESSES);
370         addresses.add(new LinkAddress(TEST_GLOBAL_ADDRESS, 0, RT_SCOPE_UNIVERSE));
371 
372         // Add a route on the interface for each prefix, and a global route
373         final Set<RouteInfo> routes = routes(TEST_PREFIXES);
374         routes.add(defaultIPV6Route(TEST_IPV6_GATEWAY));
375 
376         return linkproperties(addresses, routes, ips(TEST_DNSES));
377     }
378 
doProvisioningWithDefaultConfiguration()379     private IpClient doProvisioningWithDefaultConfiguration() throws Exception {
380         final IpClient ipc = makeIpClient(TEST_IFNAME);
381 
382         ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
383                 .withoutIPv4()
384                 // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
385                 // and enable it in this test
386                 .withoutIpReachabilityMonitor()
387                 .build();
388 
389         ipc.startProvisioning(config);
390         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setNeighborDiscoveryOffload(true);
391         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
392 
393         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
394         lp.getRoutes().forEach(route -> onRouteUpdated(route));
395         lp.getLinkAddresses().forEach(
396                 la -> onInterfaceAddressUpdated(la, la.getFlags()));
397         onInterfaceDnsServerInfo(TEST_DNS_LIFETIME,
398                 lp.getDnsServers().stream().map(InetAddress::getHostAddress)
399                         .toArray(String[]::new));
400 
401         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
402         verify(mCb, never()).onProvisioningFailure(any());
403         verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
404 
405         verify(mCb).onProvisioningSuccess(lp);
406         return ipc;
407     }
408 
409     @SuppressLint("NewApi")
addIPv4Provisioning(LinkProperties lp)410     private void addIPv4Provisioning(LinkProperties lp) {
411         final LinkAddress la = new LinkAddress(TEST_IPV4_LINKADDRESS);
412         final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
413                 InetAddresses.parseNumericAddress(TEST_IPV4_GATEWAY), TEST_IFNAME);
414         onInterfaceAddressUpdated(la, la.getFlags());
415         onRouteUpdated(defaultRoute);
416 
417         lp.addLinkAddress(la);
418         lp.addRoute(defaultRoute);
419     }
420 
421     /**
422      * Simulate loss of IPv6 provisioning (default route lost).
423      *
424      * @return The expected new LinkProperties.
425      */
doIPv6ProvisioningLoss(LinkProperties lp)426     private void doIPv6ProvisioningLoss(LinkProperties lp) {
427         final RouteInfo defaultRoute = defaultIPV6Route(TEST_IPV6_GATEWAY);
428         onRouteRemoved(defaultRoute);
429 
430         lp.removeRoute(defaultRoute);
431     }
432 
doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(boolean avoidBadWifi)433     private void doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(boolean avoidBadWifi)
434             throws Exception {
435         when(mCm.shouldAvoidBadWifi()).thenReturn(avoidBadWifi);
436         final IpClient ipc = doProvisioningWithDefaultConfiguration();
437         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
438 
439         reset(mCb);
440         doIPv6ProvisioningLoss(lp);
441         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
442         verify(mCb).onProvisioningFailure(lp);
443         verify(mCb).onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
444 
445         verifyShutdown(ipc);
446     }
447 
448     @Test
testDefaultIPv6ProvisioningConfiguration_AvoidBadWifi()449     public void testDefaultIPv6ProvisioningConfiguration_AvoidBadWifi() throws Exception {
450         doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(true /* avoidBadWifi */);
451     }
452 
453     @Test
testDefaultIPv6ProvisioningConfiguration_StayOnBadWifi()454     public void testDefaultIPv6ProvisioningConfiguration_StayOnBadWifi() throws Exception {
455         // Even when avoidBadWifi=false, if IPv6 only, loss of all provisioning causes
456         // onProvisioningFailure to be called.
457         doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(false /* avoidBadWifi */);
458     }
459 
doDefaultDualStackProvisioningConfigurationTest( boolean avoidBadWifi)460     private void doDefaultDualStackProvisioningConfigurationTest(
461             boolean avoidBadWifi) throws Exception {
462         when(mCm.shouldAvoidBadWifi()).thenReturn(avoidBadWifi);
463         final IpClient ipc = doProvisioningWithDefaultConfiguration();
464         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
465         addIPv4Provisioning(lp);
466         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
467 
468         reset(mCb);
469         doIPv6ProvisioningLoss(lp);
470         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
471         if (avoidBadWifi) { // Provisioning failure is expected only when avoidBadWifi is true
472             verify(mCb).onProvisioningFailure(lp);
473             verify(mCb).onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
474         } else {
475             verify(mCb, never()).onProvisioningFailure(any());
476             verify(mCb).onLinkPropertiesChange(lp);
477         }
478 
479         verifyShutdown(ipc);
480     }
481 
482     @Test
testDefaultDualStackProvisioningConfiguration_AvoidBadWifi()483     public void testDefaultDualStackProvisioningConfiguration_AvoidBadWifi() throws Exception {
484         doDefaultDualStackProvisioningConfigurationTest(true /* avoidBadWifi */);
485     }
486 
487     @Test
testDefaultDualStackProvisioningConfiguration_StayOnBadWifi()488     public void testDefaultDualStackProvisioningConfiguration_StayOnBadWifi() throws Exception {
489         doDefaultDualStackProvisioningConfigurationTest(false /* avoidBadWifi */);
490     }
491 
492     @Test
testProvisioningWithInitialConfiguration()493     public void testProvisioningWithInitialConfiguration() throws Exception {
494         final String iface = TEST_IFNAME;
495         final IpClient ipc = makeIpClient(iface);
496         final String l2Key = TEST_L2KEY;
497         final String cluster = TEST_CLUSTER;
498 
499         ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
500                 .withoutIPv4()
501                 .withoutIpReachabilityMonitor()
502                 .withInitialConfiguration(
503                         conf(links(TEST_LOCAL_ADDRESSES), prefixes(TEST_PREFIXES), ips()))
504                 .build();
505 
506         ipc.startProvisioning(config);
507         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setNeighborDiscoveryOffload(true);
508         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
509         verify(mCb, never()).onProvisioningFailure(any());
510         ipc.setL2KeyAndCluster(l2Key, cluster);
511 
512         for (String addr : TEST_LOCAL_ADDRESSES) {
513             String[] parts = addr.split("/");
514             verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
515                     .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
516         }
517 
518         final int lastAddr = TEST_LOCAL_ADDRESSES.length - 1;
519 
520         // Add N - 1 addresses
521         for (int i = 0; i < lastAddr; i++) {
522             onInterfaceAddressUpdated(new LinkAddress(TEST_LOCAL_ADDRESSES[i]), 0 /* flags */);
523             verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
524             reset(mCb);
525         }
526 
527         // Add Nth address
528         onInterfaceAddressUpdated(new LinkAddress(TEST_LOCAL_ADDRESSES[lastAddr]), 0 /* flags */);
529         LinkProperties want = linkproperties(links(TEST_LOCAL_ADDRESSES),
530                 routes(TEST_PREFIXES), emptySet() /* dnses */);
531         want.setInterfaceName(iface);
532         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
533         verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
534                 .setCluster(cluster)
535                 .build());
536 
537         verifyShutdown(ipc);
538     }
539 
verifyShutdown(IpClient ipc)540     private void verifyShutdown(IpClient ipc) throws Exception {
541         ipc.shutdown();
542         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(TEST_IFNAME, false);
543         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(TEST_IFNAME);
544         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
545                 .onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
546         verifyNoMoreInteractions(mIpMemoryStore);
547     }
548 
549     @Test
testIsProvisioned()550     public void testIsProvisioned() throws Exception {
551         final IpClient ipc = makeIpClient(TEST_IFNAME);
552         InitialConfiguration empty = conf(links(), prefixes());
553         IsProvisionedTestCase[] testcases = {
554             // nothing
555             notProvisionedCase(links(), routes(), dns(), null),
556             notProvisionedCase(links(), routes(), dns(), empty),
557 
558             // IPv4
559             provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
560 
561             // IPv6
562             notProvisionedCase(
563                     links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
564                     routes(), dns(), empty),
565             notProvisionedCase(
566                     links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
567                     routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
568             provisionedCase(
569                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
570                     routes("::/0"),
571                     dns("2001:db8:dead:beef:f00::02"), empty),
572 
573             // Initial configuration
574             provisionedCase(
575                     links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
576                     routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
577                     dns(),
578                     conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
579                         prefixes("fe80::/64", "fd2c:4e57:8e3c::/64"), ips())),
580 
581             // Test case with excluded route
582             notProvisionedCase(
583                     links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
584                     routes(
585                             routes("fe80::/64"),
586                             excludedRoutes("fd2c:4e57:8e3c::/64")),
587                     dns(),
588                     conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
589                             prefixes("fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
590         };
591 
592         for (IsProvisionedTestCase testcase : testcases) {
593             if (ipc.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
594                 fail(testcase.errorMessage());
595             }
596         }
597 
598         ipc.shutdown();
599     }
600 
601     static class IsProvisionedTestCase {
602         boolean isProvisioned;
603         LinkProperties lp;
604         InitialConfiguration config;
605 
errorMessage()606         String errorMessage() {
607             return String.format("expected %s with config %s to be %s, but was %s",
608                      lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
609         }
610 
provisioned(boolean isProvisioned)611         static String provisioned(boolean isProvisioned) {
612             return isProvisioned ? "provisioned" : "not provisioned";
613         }
614     }
615 
provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)616     static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
617             Set<InetAddress> lpDns, InitialConfiguration config) {
618         return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
619     }
620 
notProvisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)621     static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
622             Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
623         return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
624     }
625 
provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)626     static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
627             Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
628         IsProvisionedTestCase testcase = new IsProvisionedTestCase();
629         testcase.isProvisioned = isProvisioned;
630         testcase.lp = makeEmptyLinkProperties(TEST_IFNAME);
631         testcase.lp.setLinkAddresses(lpAddrs);
632         for (RouteInfo route : lpRoutes) {
633             testcase.lp.addRoute(route);
634         }
635         for (InetAddress dns : lpDns) {
636             testcase.lp.addDnsServer(dns);
637         }
638         testcase.config = config;
639         return testcase;
640     }
641 
642     @Test
testInitialConfigurations()643     public void testInitialConfigurations() throws Exception {
644         InitialConfigurationTestCase[] testcases = {
645             validConf("valid IPv4 configuration",
646                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
647             validConf("another valid IPv4 configuration",
648                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
649             validConf("valid IPv6 configurations",
650                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
651                     prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
652                     dns("2001:db8:dead:beef:f00::02")),
653             validConf("valid IPv6 configurations",
654                     links("fe80::1/64"), prefixes("fe80::/64"), dns()),
655             validConf("valid IPv6/v4 configuration",
656                     links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
657                     prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
658                     dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
659             validConf("valid IPv6 configuration without any GUA.",
660                     links("fd00:1234:5678::1/48"),
661                     prefixes("fd00:1234:5678::/48"),
662                     dns("fd00:1234:5678::1000")),
663 
664             invalidConf("empty configuration", links(), prefixes(), dns()),
665             invalidConf("v4 addr and dns not in any prefix",
666                     links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
667             invalidConf("v4 addr not in any prefix",
668                     links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
669             invalidConf("v4 dns addr not in any prefix",
670                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
671             invalidConf("v6 addr not in any prefix",
672                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
673                     prefixes("2001:db8:dead:beef::/64"),
674                     dns("2001:db8:dead:beef:f00::02")),
675             invalidConf("v6 dns addr not in any prefix",
676                     links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
677             invalidConf("default ipv6 route and no GUA",
678                     links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
679             invalidConf("invalid v6 prefix length",
680                     links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
681                     dns()),
682             invalidConf("another invalid v6 prefix length",
683                     links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
684                     dns())
685         };
686 
687         for (InitialConfigurationTestCase testcase : testcases) {
688             if (testcase.config.isValid() != testcase.isValid) {
689                 fail(testcase.errorMessage());
690             }
691         }
692     }
693 
694     static class InitialConfigurationTestCase {
695         String descr;
696         boolean isValid;
697         InitialConfiguration config;
errorMessage()698         public String errorMessage() {
699             return String.format("%s: expected configuration %s to be %s, but was %s",
700                     descr, config, validString(isValid), validString(!isValid));
701         }
validString(boolean isValid)702         static String validString(boolean isValid) {
703             return isValid ? VALID : INVALID;
704         }
705     }
706 
validConf(String descr, Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)707     static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
708             Set<IpPrefix> prefixes, Set<InetAddress> dns) {
709         return confTestCase(descr, true, conf(links, prefixes, dns));
710     }
711 
invalidConf(String descr, Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)712     static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
713             Set<IpPrefix> prefixes, Set<InetAddress> dns) {
714         return confTestCase(descr, false, conf(links, prefixes, dns));
715     }
716 
confTestCase( String descr, boolean isValid, InitialConfiguration config)717     static InitialConfigurationTestCase confTestCase(
718             String descr, boolean isValid, InitialConfiguration config) {
719         InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
720         testcase.descr = descr;
721         testcase.isValid = isValid;
722         testcase.config = config;
723         return testcase;
724     }
725 
linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes, Set<InetAddress> dnses)726     static LinkProperties linkproperties(Set<LinkAddress> addresses,
727             Set<RouteInfo> routes, Set<InetAddress> dnses) {
728         LinkProperties lp = makeEmptyLinkProperties(TEST_IFNAME);
729         lp.setLinkAddresses(addresses);
730         routes.forEach(lp::addRoute);
731         dnses.forEach(lp::addDnsServer);
732         return lp;
733     }
734 
conf(Set<LinkAddress> links, Set<IpPrefix> prefixes)735     static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
736         return conf(links, prefixes, new HashSet<>());
737     }
738 
conf( Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)739     static InitialConfiguration conf(
740             Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
741         InitialConfiguration conf = new InitialConfiguration();
742         conf.ipAddresses.addAll(links);
743         conf.directlyConnectedRoutes.addAll(prefixes);
744         conf.dnsServers.addAll(dns);
745         return conf;
746     }
747 
routes(String... routes)748     static Set<RouteInfo> routes(String... routes) {
749         return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r), null /* gateway */,
750                 TEST_IFNAME));
751     }
752 
excludedRoutes(String... excludedRoutes)753     static Set<RouteInfo> excludedRoutes(String... excludedRoutes) {
754         return mapIntoSet(excludedRoutes, (r) -> new RouteInfo(new IpPrefix(r), null /* gateway */,
755                 TEST_IFNAME, RouteInfo.RTN_THROW));
756     }
757 
routes(Set<RouteInfo> includedRoutes, Set<RouteInfo> excludedRoutes)758     static Set<RouteInfo> routes(Set<RouteInfo> includedRoutes, Set<RouteInfo> excludedRoutes) {
759         Set<RouteInfo> result = new HashSet<>(includedRoutes.size() + excludedRoutes.size());
760 
761         result.addAll(includedRoutes);
762         result.addAll(excludedRoutes);
763 
764         return result;
765     }
766 
767     @SuppressLint("NewApi")
defaultIPV6Route(String gateway)768     static RouteInfo defaultIPV6Route(String gateway) {
769         return new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
770                 InetAddresses.parseNumericAddress(gateway), TEST_IFNAME);
771     }
772 
prefixes(String... prefixes)773     static Set<IpPrefix> prefixes(String... prefixes) {
774         return mapIntoSet(prefixes, IpPrefix::new);
775     }
776 
links(String... addresses)777     static Set<LinkAddress> links(String... addresses) {
778         return mapIntoSet(addresses, LinkAddress::new);
779     }
780 
ips(String... addresses)781     static Set<InetAddress> ips(String... addresses) {
782         return mapIntoSet(addresses, InetAddress::getByName);
783     }
784 
dns(String... addresses)785     static Set<InetAddress> dns(String... addresses) {
786         return ips(addresses);
787     }
788 
mapIntoSet(A[] in, Fn<A, B> fn)789     static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
790         Set<B> out = new HashSet<>(in.length);
791         for (A item : in) {
792             try {
793                 out.add(fn.call(item));
794             } catch (Exception e) {
795                 throw new RuntimeException(e);
796             }
797         }
798         return out;
799     }
800 
verifyApfFilterCreatedOnStart(IpClient ipc, boolean isApfSupported)801     private ApfConfiguration verifyApfFilterCreatedOnStart(IpClient ipc, boolean isApfSupported) {
802         ProvisioningConfiguration.Builder config = new ProvisioningConfiguration.Builder()
803                 .withoutIPv4()
804                 .withoutIpReachabilityMonitor()
805                 .withInitialConfiguration(
806                         conf(links(TEST_LOCAL_ADDRESSES), prefixes(TEST_PREFIXES), ips()));
807         if (isApfSupported) {
808             config.withApfCapabilities(new ApfCapabilities(4 /* version */,
809                     4096 /* maxProgramSize */, 4 /* format */));
810         }
811 
812         ipc.startProvisioning(config.build());
813         final ArgumentCaptor<ApfConfiguration> configCaptor = ArgumentCaptor.forClass(
814                 ApfConfiguration.class);
815         verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter(
816                 any(), configCaptor.capture(), any(), any(), any(), anyBoolean());
817 
818         return configCaptor.getValue();
819     }
820 
821     @Test @IgnoreAfter(Build.VERSION_CODES.R)
testApfConfiguration_R()822     public void testApfConfiguration_R() throws Exception {
823         final IpClient ipc = makeIpClient(TEST_IFNAME);
824         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
825                 true /* isApfSupported */);
826 
827         assertEquals(ApfCapabilities.getApfDrop8023Frames(), config.ieee802_3Filter);
828         assertArrayEquals(ApfCapabilities.getApfEtherTypeBlackList(), config.ethTypeBlackList);
829 
830         verify(mResources, never()).getBoolean(R.bool.config_apfDrop802_3Frames);
831         verify(mResources, never()).getIntArray(R.array.config_apfEthTypeDenyList);
832 
833         verifyShutdown(ipc);
834     }
835 
836     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
testApfConfiguration()837     public void testApfConfiguration() throws Exception {
838         doReturn(true).when(mResources).getBoolean(R.bool.config_apfDrop802_3Frames);
839         final int[] ethTypeDenyList = new int[] { 0x88A2, 0x88A4 };
840         doReturn(ethTypeDenyList).when(mResources).getIntArray(
841                 R.array.config_apfEthTypeDenyList);
842 
843         final IpClient ipc = makeIpClient(TEST_IFNAME);
844         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
845                 true /* isApfSupported */);
846 
847         assertTrue(config.ieee802_3Filter);
848         assertArrayEquals(ethTypeDenyList, config.ethTypeBlackList);
849 
850         verifyShutdown(ipc);
851     }
852 
853     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
testApfConfiguration_NoApfDrop8023Frames()854     public void testApfConfiguration_NoApfDrop8023Frames() throws Exception {
855         doReturn(false).when(mResources).getBoolean(R.bool.config_apfDrop802_3Frames);
856         final int[] ethTypeDenyList = new int[] { 0x88A3, 0x88A5 };
857         doReturn(ethTypeDenyList).when(mResources).getIntArray(
858                 R.array.config_apfEthTypeDenyList);
859 
860         final IpClient ipc = makeIpClient(TEST_IFNAME);
861         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
862                 true /* isApfSupported */);
863 
864         assertFalse(config.ieee802_3Filter);
865         assertArrayEquals(ethTypeDenyList, config.ethTypeBlackList);
866 
867         verifyShutdown(ipc);
868     }
869 
870     @Test
testApfUpdateCapabilities()871     public void testApfUpdateCapabilities() throws Exception {
872         final IpClient ipc = makeIpClient(TEST_IFNAME);
873         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
874                 false /* isApfSupported */);
875         assertNull(config.apfCapabilities);
876         clearInvocations(mDependencies);
877 
878         ipc.updateApfCapabilities(new ApfCapabilities(4 /* version */, 4096 /* maxProgramSize */,
879                 4 /* format */));
880         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
881 
882         final ArgumentCaptor<ApfConfiguration> configCaptor = ArgumentCaptor.forClass(
883                 ApfConfiguration.class);
884         verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter(
885                 any(), configCaptor.capture(), any(), any(), any(), anyBoolean());
886         final ApfConfiguration actual = configCaptor.getValue();
887         assertNotNull(actual);
888         int expectedApfVersion = SdkLevel.isAtLeastS() ? 4 : 3;
889         assertEquals(expectedApfVersion, actual.apfCapabilities.apfVersionSupported);
890         assertEquals(4096, actual.apfCapabilities.maximumApfProgramSize);
891         assertEquals(4, actual.apfCapabilities.apfPacketFormat);
892 
893         verifyShutdown(ipc);
894     }
895 
896     @Test
testDumpApfFilter_withNoException()897     public void testDumpApfFilter_withNoException() throws Exception {
898         final IpClient ipc = makeIpClient(TEST_IFNAME);
899         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
900                 false /* isApfSupported */);
901         assertNull(config.apfCapabilities);
902         clearInvocations(mDependencies);
903         ipc.dump(mFd, mWriter, null /* args */);
904         verifyShutdown(ipc);
905     }
906 
907     @Test
testApfUpdateCapabilities_nonNullInitialApfCapabilities()908     public void testApfUpdateCapabilities_nonNullInitialApfCapabilities() throws Exception {
909         final IpClient ipc = makeIpClient(TEST_IFNAME);
910         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
911                 true /* isApfSupported */);
912         assertNotNull(config.apfCapabilities);
913         clearInvocations(mDependencies);
914 
915         final ApfCapabilities newApfCapabilities = new ApfCapabilities(4 /* version */,
916                 8192 /* maxProgramSize */, 4 /* format */);
917         ipc.updateApfCapabilities(newApfCapabilities);
918         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
919         verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any(), any(),
920                 anyBoolean());
921         verifyShutdown(ipc);
922     }
923 
924     @Test
testApfUpdateCapabilities_nullNewApfCapabilities()925     public void testApfUpdateCapabilities_nullNewApfCapabilities() throws Exception {
926         final IpClient ipc = makeIpClient(TEST_IFNAME);
927         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
928                 true /* isApfSupported */);
929         assertNotNull(config.apfCapabilities);
930         clearInvocations(mDependencies);
931 
932         ipc.updateApfCapabilities(null /* apfCapabilities */);
933         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
934         verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any(), any(),
935                 anyBoolean());
936         verifyShutdown(ipc);
937     }
938 
makeScanResultInfo(final String ssid, final String bssid)939     private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) {
940         final ByteBuffer payload = ByteBuffer.allocate(14 /* oui + type + data */);
941         final byte[] data = new byte[10];
942         new Random().nextBytes(data);
943         payload.put(new byte[] { 0x00, 0x1A, 0x11 });
944         payload.put((byte) 0x06);
945         payload.put(data);
946 
947         final ScanResultInfo.InformationElement ie =
948                 new ScanResultInfo.InformationElement(0xdd /* IE id */, payload);
949         return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie));
950     }
951 
952     @Test
testGetInitialBssidOnSOrAbove()953     public void testGetInitialBssidOnSOrAbove() throws Exception {
954         final IpClient ipc = makeIpClient(TEST_IFNAME);
955         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
956                 MacAddress.fromString(TEST_BSSID));
957         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID2);
958         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
959                 true /* isAtLeastS */);
960         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
961         ipc.shutdown();
962     }
963 
964     @Test
testGetInitialBssidOnSOrAbove_NullScanReqsultInfo()965     public void testGetInitialBssidOnSOrAbove_NullScanReqsultInfo() throws Exception {
966         final IpClient ipc = makeIpClient(TEST_IFNAME);
967         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
968                 MacAddress.fromString(TEST_BSSID));
969         final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* ScanResultInfo */,
970                 true /* isAtLeastS */);
971         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
972         ipc.shutdown();
973     }
974 
975     @Test
testGetInitialBssidOnSOrAbove_NullBssid()976     public void testGetInitialBssidOnSOrAbove_NullBssid() throws Exception {
977         final IpClient ipc = makeIpClient(TEST_IFNAME);
978         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
979                 null /* bssid */);
980         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
981         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
982                 true /* isAtLeastS */);
983         assertNull(bssid);
984         ipc.shutdown();
985     }
986 
987     @Test
testGetInitialBssidOnSOrAbove_NullLayer2Info()988     public void testGetInitialBssidOnSOrAbove_NullLayer2Info() throws Exception {
989         final IpClient ipc = makeIpClient(TEST_IFNAME);
990         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
991         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
992                 true /* isAtLeastS */);
993         assertNull(bssid);
994         ipc.shutdown();
995     }
996 
997     @Test
testGetInitialBssidBeforeS()998     public void testGetInitialBssidBeforeS() throws Exception {
999         final IpClient ipc = makeIpClient(TEST_IFNAME);
1000         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
1001                 MacAddress.fromString(TEST_BSSID2));
1002         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
1003         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
1004                 false /* isAtLeastS */);
1005         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
1006         ipc.shutdown();
1007     }
1008 
1009     @Test
testGetInitialBssidBeforeS_NullLayer2Info()1010     public void testGetInitialBssidBeforeS_NullLayer2Info() throws Exception {
1011         final IpClient ipc = makeIpClient(TEST_IFNAME);
1012         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
1013         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
1014                 false /* isAtLeastS */);
1015         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
1016         ipc.shutdown();
1017     }
1018 
1019     @Test
testGetInitialBssidBeforeS_BrokenInitialBssid()1020     public void testGetInitialBssidBeforeS_BrokenInitialBssid() throws Exception {
1021         final IpClient ipc = makeIpClient(TEST_IFNAME);
1022         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, "00:11:22:33:44:");
1023         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
1024                 false /* isAtLeastS */);
1025         assertNull(bssid);
1026         ipc.shutdown();
1027     }
1028 
1029     @Test
testGetInitialBssidBeforeS_BrokenInitialBssidFallback()1030     public void testGetInitialBssidBeforeS_BrokenInitialBssidFallback() throws Exception {
1031         final IpClient ipc = makeIpClient(TEST_IFNAME);
1032         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
1033                 MacAddress.fromString(TEST_BSSID));
1034         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, "00:11:22:33:44:");
1035         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
1036                 false /* isAtLeastS */);
1037         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
1038         ipc.shutdown();
1039     }
1040 
1041     @Test
testGetInitialBssidBeforeS_NullScanResultInfoFallback()1042     public void testGetInitialBssidBeforeS_NullScanResultInfoFallback() throws Exception {
1043         final IpClient ipc = makeIpClient(TEST_IFNAME);
1044         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
1045                 MacAddress.fromString(TEST_BSSID));
1046         final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* scanResultInfo */,
1047                 false /* isAtLeastS */);
1048         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
1049         ipc.shutdown();
1050     }
1051 
1052     @Test
testGetInitialBssidBeforeS_NullScanResultInfoAndLayer2Info()1053     public void testGetInitialBssidBeforeS_NullScanResultInfoAndLayer2Info() throws Exception {
1054         final IpClient ipc = makeIpClient(TEST_IFNAME);
1055         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */,
1056                 null /* scanResultInfo */, false /* isAtLeastS */);
1057         assertNull(bssid);
1058         ipc.shutdown();
1059     }
1060 
1061     interface Fn<A,B> {
call(A a)1062         B call(A a) throws Exception;
1063     }
1064 
1065     @Test
testAll()1066     public void testAll() {
1067         List<String> list1 = Arrays.asList();
1068         List<String> list2 = Arrays.asList("foo");
1069         List<String> list3 = Arrays.asList("bar", "baz");
1070         List<String> list4 = Arrays.asList("foo", "bar", "baz");
1071 
1072         assertTrue(InitialConfiguration.all(list1, (x) -> false));
1073         assertFalse(InitialConfiguration.all(list2, (x) -> false));
1074         assertTrue(InitialConfiguration.all(list3, (x) -> true));
1075         assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
1076         assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
1077     }
1078 
1079     @Test
testAny()1080     public void testAny() {
1081         List<String> list1 = Arrays.asList();
1082         List<String> list2 = Arrays.asList("foo");
1083         List<String> list3 = Arrays.asList("bar", "baz");
1084         List<String> list4 = Arrays.asList("foo", "bar", "baz");
1085 
1086         assertFalse(InitialConfiguration.any(list1, (x) -> true));
1087         assertTrue(InitialConfiguration.any(list2, (x) -> true));
1088         assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
1089         assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
1090         assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
1091     }
1092 
1093     @Test
testFindAll()1094     public void testFindAll() {
1095         List<String> list1 = Arrays.asList();
1096         List<String> list2 = Arrays.asList("foo");
1097         List<String> list3 = Arrays.asList("foo", "bar", "baz");
1098 
1099         assertEquals(list1, IpClient.findAll(list1, (x) -> true));
1100         assertEquals(list1, IpClient.findAll(list3, (x) -> false));
1101         assertEquals(list3, IpClient.findAll(list3, (x) -> true));
1102         assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
1103     }
1104 }
1105