• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.server.connectivity;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.any;
25 import static org.mockito.Mockito.anyInt;
26 import static org.mockito.Mockito.anyString;
27 import static org.mockito.Mockito.eq;
28 import static org.mockito.Mockito.inOrder;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.verifyNoMoreInteractions;
33 import static org.mockito.Mockito.when;
34 
35 import android.net.ConnectivityManager;
36 import android.net.IDnsResolver;
37 import android.net.INetd;
38 import android.net.InterfaceConfigurationParcel;
39 import android.net.IpPrefix;
40 import android.net.LinkAddress;
41 import android.net.LinkProperties;
42 import android.net.NetworkAgentConfig;
43 import android.net.NetworkCapabilities;
44 import android.net.NetworkInfo;
45 import android.os.Build;
46 import android.os.Handler;
47 import android.os.test.TestLooper;
48 
49 import androidx.annotation.NonNull;
50 import androidx.annotation.Nullable;
51 import androidx.test.filters.SmallTest;
52 
53 import com.android.modules.utils.build.SdkLevel;
54 import com.android.server.ConnectivityService;
55 import com.android.testutils.DevSdkIgnoreRule;
56 import com.android.testutils.DevSdkIgnoreRunner;
57 
58 import org.junit.Before;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 import org.mockito.ArgumentCaptor;
62 import org.mockito.InOrder;
63 import org.mockito.Mock;
64 import org.mockito.MockitoAnnotations;
65 
66 @RunWith(DevSdkIgnoreRunner.class)
67 @SmallTest
68 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
69 public class Nat464XlatTest {
70 
71     static final String BASE_IFACE = "test0";
72     static final String STACKED_IFACE = "v4-test0";
73     static final LinkAddress V6ADDR = new LinkAddress("2001:db8:1::f00/64");
74     static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
75     static final String NAT64_PREFIX = "64:ff9b::/96";
76     static final String OTHER_NAT64_PREFIX = "2001:db8:0:64::/96";
77     static final int NETID = 42;
78 
79     @Mock ConnectivityService mConnectivity;
80     @Mock IDnsResolver mDnsResolver;
81     @Mock INetd mNetd;
82     @Mock NetworkAgentInfo mNai;
83     @Mock ClatCoordinator mClatCoordinator;
84 
85     TestLooper mLooper;
86     Handler mHandler;
87     NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
88 
makeNat464Xlat(boolean isCellular464XlatEnabled)89     Nat464Xlat makeNat464Xlat(boolean isCellular464XlatEnabled) {
90         final ConnectivityService.Dependencies deps = new ConnectivityService.Dependencies() {
91             @Override public ClatCoordinator getClatCoordinator(INetd netd) {
92                 return mClatCoordinator;
93             }
94         };
95 
96         return new Nat464Xlat(mNai, mNetd, mDnsResolver, deps) {
97             @Override protected int getNetId() {
98                 return NETID;
99             }
100 
101             @Override protected boolean isCellular464XlatEnabled() {
102                 return isCellular464XlatEnabled;
103             }
104         };
105     }
106 
107     private void markNetworkConnected() {
108         mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
109     }
110 
111     private void markNetworkDisconnected() {
112         mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, "", "");
113     }
114 
115     @Before
116     public void setUp() throws Exception {
117         mLooper = new TestLooper();
118         mHandler = new Handler(mLooper.getLooper());
119 
120         MockitoAnnotations.initMocks(this);
121 
122         mNai.linkProperties = new LinkProperties();
123         mNai.linkProperties.setInterfaceName(BASE_IFACE);
124         mNai.networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */,
125                 null /* typeName */, null /* subtypeName */);
126         mNai.networkCapabilities = new NetworkCapabilities();
127         markNetworkConnected();
128         when(mNai.connService()).thenReturn(mConnectivity);
129         when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
130         when(mNai.handler()).thenReturn(mHandler);
131         final InterfaceConfigurationParcel mConfig = new InterfaceConfigurationParcel();
132         when(mNetd.interfaceGetCfg(eq(STACKED_IFACE))).thenReturn(mConfig);
133         mConfig.ipv4Addr = ADDR.getAddress().getHostAddress();
134         mConfig.prefixLength =  ADDR.getPrefixLength();
135     }
136 
137     private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
138         Nat464Xlat nat = makeNat464Xlat(true);
139         String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
140                 + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
141                 nai.networkInfo.getDetailedState(),
142                 mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
143                 nai.linkProperties.getLinkAddresses());
144         assertEquals(msg, expected, nat.requiresClat(nai));
145     }
146 
147     private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) {
148         Nat464Xlat nat = makeNat464Xlat(true);
149         String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
150                 + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
151                 nai.networkInfo.getDetailedState(),
152                 mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
153                 nai.linkProperties.getLinkAddresses());
154         assertEquals(msg, expected, nat.shouldStartClat(nai));
155     }
156 
157     @Test
158     public void testRequiresClat() throws Exception {
159         final int[] supportedTypes = {
160             ConnectivityManager.TYPE_MOBILE,
161             ConnectivityManager.TYPE_WIFI,
162             ConnectivityManager.TYPE_ETHERNET,
163         };
164 
165         // NetworkInfo doesn't allow setting the State directly, but rather
166         // requires setting DetailedState in order set State as a side-effect.
167         final NetworkInfo.DetailedState[] supportedDetailedStates = {
168             NetworkInfo.DetailedState.CONNECTED,
169             NetworkInfo.DetailedState.SUSPENDED,
170         };
171 
172         LinkProperties oldLp = new LinkProperties(mNai.linkProperties);
173         for (int type : supportedTypes) {
174             mNai.networkInfo.setType(type);
175             for (NetworkInfo.DetailedState state : supportedDetailedStates) {
176                 mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
177 
178                 mNai.linkProperties.setNat64Prefix(new IpPrefix(OTHER_NAT64_PREFIX));
179                 assertRequiresClat(false, mNai);
180                 assertShouldStartClat(false, mNai);
181 
182                 mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
183                 assertRequiresClat(false, mNai);
184                 assertShouldStartClat(false, mNai);
185 
186                 mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
187                 assertRequiresClat(true, mNai);
188                 assertShouldStartClat(true, mNai);
189 
190                 mAgentConfig.skip464xlat = true;
191                 assertRequiresClat(false, mNai);
192                 assertShouldStartClat(false, mNai);
193 
194                 mAgentConfig.skip464xlat = false;
195                 assertRequiresClat(true, mNai);
196                 assertShouldStartClat(true, mNai);
197 
198                 mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
199                 assertRequiresClat(false, mNai);
200                 assertShouldStartClat(false, mNai);
201 
202                 mNai.linkProperties.removeLinkAddress(new LinkAddress("192.0.2.2/24"));
203                 assertRequiresClat(true, mNai);
204                 assertShouldStartClat(true, mNai);
205 
206                 mNai.linkProperties.setNat64Prefix(null);
207                 assertRequiresClat(true, mNai);
208                 assertShouldStartClat(false, mNai);
209 
210                 mNai.linkProperties = new LinkProperties(oldLp);
211             }
212         }
213     }
214 
215     private void makeClatUnnecessary(boolean dueToDisconnect) {
216         if (dueToDisconnect) {
217             markNetworkDisconnected();
218         } else {
219             mNai.linkProperties.addLinkAddress(ADDR);
220         }
221     }
222 
223     private <T> T verifyWithOrder(@Nullable InOrder inOrder, @NonNull T t) {
224         if (inOrder != null) {
225             return inOrder.verify(t);
226         } else {
227             return verify(t);
228         }
229     }
230 
231     private void verifyClatdStart(@Nullable InOrder inOrder) throws Exception {
232         if (SdkLevel.isAtLeastT()) {
233             verifyWithOrder(inOrder, mClatCoordinator)
234                 .clatStart(eq(BASE_IFACE), eq(NETID), eq(new IpPrefix(NAT64_PREFIX)));
235         } else {
236             verifyWithOrder(inOrder, mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
237         }
238     }
239 
240     private void verifyNeverClatdStart() throws Exception {
241         if (SdkLevel.isAtLeastT()) {
242             verify(mClatCoordinator, never()).clatStart(anyString(), anyInt(), any());
243         } else {
244             verify(mNetd, never()).clatdStart(anyString(), anyString());
245         }
246     }
247 
248     private void verifyClatdStop(@Nullable InOrder inOrder) throws Exception {
249         if (SdkLevel.isAtLeastT()) {
250             verifyWithOrder(inOrder, mClatCoordinator).clatStop();
251         } else {
252             verifyWithOrder(inOrder, mNetd).clatdStop(eq(BASE_IFACE));
253         }
254     }
255 
256     private void checkNormalStartAndStop(boolean dueToDisconnect) throws Exception {
257         Nat464Xlat nat = makeNat464Xlat(true);
258         ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
259 
260         mNai.linkProperties.addLinkAddress(V6ADDR);
261 
262         nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
263 
264         // Start clat.
265         nat.start();
266 
267         verifyClatdStart(null /* inOrder */);
268 
269         // Stacked interface up notification arrives.
270         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
271         mLooper.dispatchNext();
272 
273         verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
274         verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
275         assertFalse(c.getValue().getStackedLinks().isEmpty());
276         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
277         assertRunning(nat);
278 
279         // Stop clat (Network disconnects, IPv4 addr appears, ...).
280         makeClatUnnecessary(dueToDisconnect);
281         nat.stop();
282 
283         verifyClatdStop(null /* inOrder */);
284         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
285         assertTrue(c.getValue().getStackedLinks().isEmpty());
286         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
287         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
288         assertIdle(nat);
289 
290         // Stacked interface removed notification arrives and is ignored.
291         nat.interfaceRemoved(STACKED_IFACE);
292         mLooper.dispatchNext();
293 
294         verifyNoMoreInteractions(mNetd, mConnectivity);
295     }
296 
297     @Test
298     public void testNormalStartAndStopDueToDisconnect() throws Exception {
299         checkNormalStartAndStop(true);
300     }
301 
302     @Test
303     public void testNormalStartAndStopDueToIpv4Addr() throws Exception {
304         checkNormalStartAndStop(false);
305     }
306 
307     private void checkStartStopStart(boolean interfaceRemovedFirst) throws Exception {
308         Nat464Xlat nat = makeNat464Xlat(true);
309         ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
310         InOrder inOrder = inOrder(mNetd, mConnectivity, mClatCoordinator);
311 
312         mNai.linkProperties.addLinkAddress(V6ADDR);
313 
314         nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
315 
316         nat.start();
317 
318         verifyClatdStart(inOrder);
319 
320         // Stacked interface up notification arrives.
321         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
322         mLooper.dispatchNext();
323 
324         inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
325         assertFalse(c.getValue().getStackedLinks().isEmpty());
326         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
327         assertRunning(nat);
328 
329         // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
330         nat.stop();
331 
332         verifyClatdStop(inOrder);
333 
334         inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
335         assertTrue(c.getValue().getStackedLinks().isEmpty());
336         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
337         assertIdle(nat);
338 
339         if (interfaceRemovedFirst) {
340             // Stacked interface removed notification arrives and is ignored.
341             nat.interfaceRemoved(STACKED_IFACE);
342             mLooper.dispatchNext();
343             nat.interfaceLinkStateChanged(STACKED_IFACE, false);
344             mLooper.dispatchNext();
345         }
346 
347         assertTrue(c.getValue().getStackedLinks().isEmpty());
348         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
349         assertIdle(nat);
350         inOrder.verifyNoMoreInteractions();
351 
352         nat.start();
353 
354         verifyClatdStart(inOrder);
355 
356         if (!interfaceRemovedFirst) {
357             // Stacked interface removed notification arrives and is ignored.
358             nat.interfaceRemoved(STACKED_IFACE);
359             mLooper.dispatchNext();
360             nat.interfaceLinkStateChanged(STACKED_IFACE, false);
361             mLooper.dispatchNext();
362         }
363 
364         // Stacked interface up notification arrives.
365         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
366         mLooper.dispatchNext();
367 
368         inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
369         assertFalse(c.getValue().getStackedLinks().isEmpty());
370         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
371         assertRunning(nat);
372 
373         // ConnectivityService stops clat again.
374         nat.stop();
375 
376         verifyClatdStop(inOrder);
377 
378         inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
379         assertTrue(c.getValue().getStackedLinks().isEmpty());
380         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
381         assertIdle(nat);
382 
383         inOrder.verifyNoMoreInteractions();
384     }
385 
386     @Test
387     public void testStartStopStart() throws Exception {
388         checkStartStopStart(true);
389     }
390 
391     @Test
392     public void testStartStopStartBeforeInterfaceRemoved() throws Exception {
393         checkStartStopStart(false);
394     }
395 
396     @Test
397     public void testClatdCrashWhileRunning() throws Exception {
398         Nat464Xlat nat = makeNat464Xlat(true);
399         ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
400 
401         nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
402 
403         nat.start();
404 
405         verifyClatdStart(null /* inOrder */);
406 
407         // Stacked interface up notification arrives.
408         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
409         mLooper.dispatchNext();
410 
411         verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
412         verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
413         assertFalse(c.getValue().getStackedLinks().isEmpty());
414         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
415         assertRunning(nat);
416 
417         // Stacked interface removed notification arrives (clatd crashed, ...).
418         nat.interfaceRemoved(STACKED_IFACE);
419         mLooper.dispatchNext();
420 
421         verifyClatdStop(null /* inOrder */);
422         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
423         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
424         assertTrue(c.getValue().getStackedLinks().isEmpty());
425         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
426         assertIdle(nat);
427 
428         // ConnectivityService stops clat: no-op.
429         nat.stop();
430 
431         verifyNoMoreInteractions(mNetd, mConnectivity);
432     }
433 
434     private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
435         Nat464Xlat nat = makeNat464Xlat(true);
436 
437         mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
438 
439         nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
440 
441         nat.start();
442 
443         verifyClatdStart(null /* inOrder */);
444 
445         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
446         makeClatUnnecessary(dueToDisconnect);
447         nat.stop();
448 
449         verifyClatdStop(null /* inOrder */);
450         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
451         assertIdle(nat);
452 
453         // In-flight interface up notification arrives: no-op
454         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
455         mLooper.dispatchNext();
456 
457         // Interface removed notification arrives after stopClatd() takes effect: no-op.
458         nat.interfaceRemoved(STACKED_IFACE);
459         mLooper.dispatchNext();
460 
461         assertIdle(nat);
462 
463         verifyNoMoreInteractions(mNetd, mConnectivity);
464     }
465 
466     @Test
467     public void testStopDueToDisconnectBeforeClatdStarts() throws Exception {
468         checkStopBeforeClatdStarts(true);
469     }
470 
471     @Test
472     public void testStopDueToIpv4AddrBeforeClatdStarts() throws Exception {
473         checkStopBeforeClatdStarts(false);
474     }
475 
476     private void checkStopAndClatdNeverStarts(boolean dueToDisconnect) throws Exception {
477         Nat464Xlat nat = makeNat464Xlat(true);
478 
479         mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
480 
481         nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
482 
483         nat.start();
484 
485         verifyClatdStart(null /* inOrder */);
486 
487         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
488         makeClatUnnecessary(dueToDisconnect);
489         nat.stop();
490 
491         verifyClatdStop(null /* inOrder */);
492         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
493         assertIdle(nat);
494 
495         verifyNoMoreInteractions(mNetd, mConnectivity);
496     }
497 
498     @Test
499     public void testStopDueToDisconnectAndClatdNeverStarts() throws Exception {
500         checkStopAndClatdNeverStarts(true);
501     }
502 
503     @Test
504     public void testStopDueToIpv4AddressAndClatdNeverStarts() throws Exception {
505         checkStopAndClatdNeverStarts(false);
506     }
507 
508     @Test
509     public void testNat64PrefixPreference() throws Exception {
510         final IpPrefix prefixFromDns = new IpPrefix(NAT64_PREFIX);
511         final IpPrefix prefixFromRa = new IpPrefix(OTHER_NAT64_PREFIX);
512 
513         Nat464Xlat nat = makeNat464Xlat(true);
514 
515         final LinkProperties emptyLp = new LinkProperties();
516         LinkProperties fixedupLp;
517 
518         fixedupLp = new LinkProperties();
519         nat.setNat64PrefixFromDns(prefixFromDns);
520         nat.fixupLinkProperties(emptyLp, fixedupLp);
521         assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
522 
523         fixedupLp = new LinkProperties();
524         nat.setNat64PrefixFromRa(prefixFromRa);
525         nat.fixupLinkProperties(emptyLp, fixedupLp);
526         assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
527 
528         fixedupLp = new LinkProperties();
529         nat.setNat64PrefixFromRa(null);
530         nat.fixupLinkProperties(emptyLp, fixedupLp);
531         assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
532 
533         fixedupLp = new LinkProperties();
534         nat.setNat64PrefixFromRa(prefixFromRa);
535         nat.fixupLinkProperties(emptyLp, fixedupLp);
536         assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
537 
538         fixedupLp = new LinkProperties();
539         nat.setNat64PrefixFromDns(null);
540         nat.fixupLinkProperties(emptyLp, fixedupLp);
541         assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
542 
543         fixedupLp = new LinkProperties();
544         nat.setNat64PrefixFromRa(null);
545         nat.fixupLinkProperties(emptyLp, fixedupLp);
546         assertEquals(null, fixedupLp.getNat64Prefix());
547     }
548 
549     private void checkClatDisabledOnCellular(boolean onCellular) throws Exception {
550         // Disable 464xlat on cellular networks.
551         Nat464Xlat nat = makeNat464Xlat(false);
552         mNai.linkProperties.addLinkAddress(V6ADDR);
553         mNai.networkCapabilities.setTransportType(TRANSPORT_CELLULAR, onCellular);
554         nat.update();
555 
556         final IpPrefix nat64Prefix = new IpPrefix(NAT64_PREFIX);
557         if (onCellular) {
558             // Prefix discovery is never started.
559             verify(mDnsResolver, never()).startPrefix64Discovery(eq(NETID));
560             assertIdle(nat);
561 
562             // If a NAT64 prefix comes in from an RA, clat is not started either.
563             mNai.linkProperties.setNat64Prefix(nat64Prefix);
564             nat.setNat64PrefixFromRa(nat64Prefix);
565             nat.update();
566             verifyNeverClatdStart();
567             assertIdle(nat);
568         } else {
569             // Prefix discovery is started.
570             verify(mDnsResolver).startPrefix64Discovery(eq(NETID));
571             assertIdle(nat);
572 
573             // If a NAT64 prefix comes in from an RA, clat is started.
574             mNai.linkProperties.setNat64Prefix(nat64Prefix);
575             nat.setNat64PrefixFromRa(nat64Prefix);
576             nat.update();
577             verifyClatdStart(null /* inOrder */);
578             assertStarting(nat);
579         }
580     }
581 
582     @Test
583     public void testClatDisabledOnCellular() throws Exception {
584         checkClatDisabledOnCellular(true);
585     }
586 
587     @Test
588     public void testClatDisabledOnNonCellular() throws Exception {
589         checkClatDisabledOnCellular(false);
590     }
591 
592     static void assertIdle(Nat464Xlat nat) {
593         assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
594     }
595 
596     static void assertStarting(Nat464Xlat nat) {
597         assertTrue("Nat464Xlat was not STARTING", nat.isStarting());
598     }
599 
600     static void assertRunning(Nat464Xlat nat) {
601         assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
602     }
603 }
604