blob: 0e4a36ccfc7e5f5b5371ca9daad1d41a2ce5c5d9 [file] [log] [blame]
Erik Kline92c4db02017-05-31 10:21:32 +09001/*
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
17package com.android.server.connectivity.tethering;
18
19import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
Erik Kline7990aef2017-06-01 20:11:25 +090020import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertTrue;
Erik Kline92c4db02017-05-31 10:21:32 +090022import static org.junit.Assert.fail;
23import static org.mockito.Matchers.any;
24import static org.mockito.Matchers.anyObject;
Erik Kline7990aef2017-06-01 20:11:25 +090025import static org.mockito.Matchers.eq;
Erik Kline92c4db02017-05-31 10:21:32 +090026import static org.mockito.Mockito.inOrder;
27import static org.mockito.Mockito.never;
Erik Kline7990aef2017-06-01 20:11:25 +090028import static org.mockito.Mockito.reset;
Erik Kline92c4db02017-05-31 10:21:32 +090029import static org.mockito.Mockito.times;
30import static org.mockito.Mockito.when;
31
32import android.content.Context;
Erik Klinef3a08b42017-06-07 16:33:19 +090033import android.content.pm.ApplicationInfo;
Erik Kline32179ff2017-07-04 18:28:11 +090034import android.net.IpPrefix;
Erik Kline7990aef2017-06-01 20:11:25 +090035import android.net.LinkAddress;
36import android.net.LinkProperties;
37import android.net.RouteInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090038import android.net.util.SharedLog;
39import android.provider.Settings;
40import android.provider.Settings.SettingNotFoundException;
41
42import android.support.test.filters.SmallTest;
43import android.support.test.runner.AndroidJUnit4;
44import android.test.mock.MockContentResolver;
45import com.android.internal.util.test.FakeSettingsProvider;
46
Erik Kline7990aef2017-06-01 20:11:25 +090047import java.net.InetAddress;
48import java.util.ArrayList;
Erik Kline32179ff2017-07-04 18:28:11 +090049import java.util.HashSet;
50import java.util.Set;
Erik Kline7990aef2017-06-01 20:11:25 +090051
Erik Klinec87cd412017-07-07 17:38:30 +090052import org.junit.After;
Erik Kline92c4db02017-05-31 10:21:32 +090053import org.junit.Before;
54import org.junit.runner.RunWith;
55import org.junit.Test;
Erik Kline7990aef2017-06-01 20:11:25 +090056import org.mockito.ArgumentCaptor;
Erik Kline92c4db02017-05-31 10:21:32 +090057import org.mockito.InOrder;
58import org.mockito.Mock;
59import org.mockito.MockitoAnnotations;
60
61
62@RunWith(AndroidJUnit4.class)
63@SmallTest
64public class OffloadControllerTest {
65
66 @Mock private OffloadHardwareInterface mHardware;
Erik Klinef3a08b42017-06-07 16:33:19 +090067 @Mock private ApplicationInfo mApplicationInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090068 @Mock private Context mContext;
Erik Kline7fd696c2017-06-12 18:20:08 +090069 private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
70 ArgumentCaptor.forClass(ArrayList.class);
Erik Kline92c4db02017-05-31 10:21:32 +090071 private MockContentResolver mContentResolver;
72
73 @Before public void setUp() throws Exception {
74 MockitoAnnotations.initMocks(this);
Erik Klinef3a08b42017-06-07 16:33:19 +090075 when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
76 when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
Erik Kline92c4db02017-05-31 10:21:32 +090077 mContentResolver = new MockContentResolver(mContext);
78 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline92c4db02017-05-31 10:21:32 +090079 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Erik Klinec87cd412017-07-07 17:38:30 +090080 FakeSettingsProvider.clearSettingsProvider();
81 }
82
83 @After public void tearDown() throws Exception {
84 FakeSettingsProvider.clearSettingsProvider();
Erik Kline92c4db02017-05-31 10:21:32 +090085 }
86
87 private void setupFunctioningHardwareInterface() {
88 when(mHardware.initOffloadConfig()).thenReturn(true);
89 when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
90 .thenReturn(true);
91 }
92
Erik Klinec87cd412017-07-07 17:38:30 +090093 private void enableOffload() {
94 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
95 }
96
Erik Kline92c4db02017-05-31 10:21:32 +090097 @Test
Erik Klinec87cd412017-07-07 17:38:30 +090098 public void testNoSettingsValueDefaultDisabledDoesNotStart() {
Erik Kline92c4db02017-05-31 10:21:32 +090099 setupFunctioningHardwareInterface();
Erik Klinec87cd412017-07-07 17:38:30 +0900100 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
Erik Kline92c4db02017-05-31 10:21:32 +0900101 try {
102 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
103 fail();
104 } catch (SettingNotFoundException expected) {}
105
106 final OffloadController offload =
107 new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
108 offload.start();
109
110 final InOrder inOrder = inOrder(mHardware);
Erik Klinec87cd412017-07-07 17:38:30 +0900111 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
112 inOrder.verify(mHardware, never()).initOffloadConfig();
113 inOrder.verify(mHardware, never()).initOffloadControl(
114 any(OffloadHardwareInterface.ControlCallback.class));
115 inOrder.verifyNoMoreInteractions();
116 }
117
118 @Test
119 public void testNoSettingsValueDefaultEnabledDoesStart() {
120 setupFunctioningHardwareInterface();
121 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
122 try {
123 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
124 fail();
125 } catch (SettingNotFoundException expected) {}
126
127 final OffloadController offload =
128 new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
129 offload.start();
130
131 final InOrder inOrder = inOrder(mHardware);
132 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900133 inOrder.verify(mHardware, times(1)).initOffloadConfig();
134 inOrder.verify(mHardware, times(1)).initOffloadControl(
135 any(OffloadHardwareInterface.ControlCallback.class));
136 inOrder.verifyNoMoreInteractions();
137 }
138
139 @Test
140 public void testSettingsAllowsStart() {
141 setupFunctioningHardwareInterface();
142 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
143
144 final OffloadController offload =
145 new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
146 offload.start();
147
148 final InOrder inOrder = inOrder(mHardware);
Erik Klinec87cd412017-07-07 17:38:30 +0900149 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900150 inOrder.verify(mHardware, times(1)).initOffloadConfig();
151 inOrder.verify(mHardware, times(1)).initOffloadControl(
152 any(OffloadHardwareInterface.ControlCallback.class));
153 inOrder.verifyNoMoreInteractions();
154 }
155
156 @Test
157 public void testSettingsDisablesStart() {
158 setupFunctioningHardwareInterface();
159 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
160
161 final OffloadController offload =
162 new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
163 offload.start();
164
165 final InOrder inOrder = inOrder(mHardware);
Erik Klinec87cd412017-07-07 17:38:30 +0900166 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900167 inOrder.verify(mHardware, never()).initOffloadConfig();
168 inOrder.verify(mHardware, never()).initOffloadControl(anyObject());
169 inOrder.verifyNoMoreInteractions();
170 }
Erik Kline7990aef2017-06-01 20:11:25 +0900171
172 @Test
173 public void testSetUpstreamLinkPropertiesWorking() throws Exception {
174 setupFunctioningHardwareInterface();
Erik Klinec87cd412017-07-07 17:38:30 +0900175 enableOffload();
176
Erik Kline7990aef2017-06-01 20:11:25 +0900177 final OffloadController offload =
178 new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
179 offload.start();
180
181 final InOrder inOrder = inOrder(mHardware);
Erik Klinec87cd412017-07-07 17:38:30 +0900182 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline7990aef2017-06-01 20:11:25 +0900183 inOrder.verify(mHardware, times(1)).initOffloadConfig();
184 inOrder.verify(mHardware, times(1)).initOffloadControl(
185 any(OffloadHardwareInterface.ControlCallback.class));
186 inOrder.verifyNoMoreInteractions();
187
Erik Kline32179ff2017-07-04 18:28:11 +0900188 // In reality, the UpstreamNetworkMonitor would have passed down to us
189 // a covering set of local prefixes representing a minimum essential
190 // set plus all the prefixes on networks with network agents.
191 //
192 // We simulate that there, and then add upstream elements one by one
193 // and watch what happens.
194 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
195 for (String s : new String[]{
196 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
197 minimumLocalPrefixes.add(new IpPrefix(s));
198 }
199 offload.setLocalPrefixes(minimumLocalPrefixes);
200 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
201 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
202 assertEquals(4, localPrefixes.size());
203 assertTrue(localPrefixes.contains("127.0.0.0/8"));
204 assertTrue(localPrefixes.contains("192.0.2.0/24"));
205 assertTrue(localPrefixes.contains("fe80::/64"));
206 assertTrue(localPrefixes.contains("2001:db8::/64"));
Erik Kline7990aef2017-06-01 20:11:25 +0900207 inOrder.verifyNoMoreInteractions();
Erik Kline32179ff2017-07-04 18:28:11 +0900208
209 offload.setUpstreamLinkProperties(null);
210 // No change in local addresses means no call to setLocalPrefixes().
211 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
212 // This LinkProperties value does not differ from the default upstream.
213 // There should be no extraneous call to setUpstreamParameters().
214 inOrder.verify(mHardware, never()).setUpstreamParameters(
215 anyObject(), anyObject(), anyObject(), anyObject());
216 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900217
218 final LinkProperties lp = new LinkProperties();
219
220 final String testIfName = "rmnet_data17";
221 lp.setInterfaceName(testIfName);
222 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900223 // No change in local addresses means no call to setLocalPrefixes().
224 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900225 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline11854592017-06-15 18:06:34 +0900226 eq(testIfName), eq(null), eq(null), eq(null));
Erik Kline7990aef2017-06-01 20:11:25 +0900227 inOrder.verifyNoMoreInteractions();
228
229 final String ipv4Addr = "192.0.2.5";
230 final String linkAddr = ipv4Addr + "/24";
231 lp.addLinkAddress(new LinkAddress(linkAddr));
Erik Kline32179ff2017-07-04 18:28:11 +0900232 lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
Erik Kline7990aef2017-06-01 20:11:25 +0900233 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900234 // IPv4 prefixes and addresses on the upstream are simply left as whole
235 // prefixes (already passed in from UpstreamNetworkMonitor code). If a
236 // tethering client sends traffic to the IPv4 default router or other
237 // clients on the upstream this will not be hardware-forwarded, and that
238 // should be fine for now. Ergo: no change in local addresses, no call
239 // to setLocalPrefixes().
240 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900241 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline11854592017-06-15 18:06:34 +0900242 eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
Erik Kline7990aef2017-06-01 20:11:25 +0900243 inOrder.verifyNoMoreInteractions();
244
245 final String ipv4Gateway = "192.0.2.1";
246 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
247 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900248 // No change in local addresses means no call to setLocalPrefixes().
249 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900250 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline11854592017-06-15 18:06:34 +0900251 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
Erik Kline7990aef2017-06-01 20:11:25 +0900252 inOrder.verifyNoMoreInteractions();
253
254 final String ipv6Gw1 = "fe80::cafe";
255 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
256 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900257 // No change in local addresses means no call to setLocalPrefixes().
258 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900259 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
260 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
261 ArrayList<String> v6gws = mStringArrayCaptor.getValue();
262 assertEquals(1, v6gws.size());
263 assertTrue(v6gws.contains(ipv6Gw1));
264 inOrder.verifyNoMoreInteractions();
265
266 final String ipv6Gw2 = "fe80::d00d";
267 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
268 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900269 // No change in local addresses means no call to setLocalPrefixes().
270 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900271 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
272 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
273 v6gws = mStringArrayCaptor.getValue();
274 assertEquals(2, v6gws.size());
275 assertTrue(v6gws.contains(ipv6Gw1));
276 assertTrue(v6gws.contains(ipv6Gw2));
277 inOrder.verifyNoMoreInteractions();
278
279 final LinkProperties stacked = new LinkProperties();
280 stacked.setInterfaceName("stacked");
281 stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
282 stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
283 stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
284 assertTrue(lp.addStackedLink(stacked));
285 offload.setUpstreamLinkProperties(lp);
Erik Kline32179ff2017-07-04 18:28:11 +0900286 // No change in local addresses means no call to setLocalPrefixes().
287 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900288 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
289 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
290 v6gws = mStringArrayCaptor.getValue();
291 assertEquals(2, v6gws.size());
292 assertTrue(v6gws.contains(ipv6Gw1));
293 assertTrue(v6gws.contains(ipv6Gw2));
294 inOrder.verifyNoMoreInteractions();
Erik Kline32179ff2017-07-04 18:28:11 +0900295
296 // Add in some IPv6 upstream info. When there is a tethered downstream
297 // making use of the IPv6 prefix we would expect to see the /64 route
298 // removed from "local prefixes" and /128s added for the upstream IPv6
299 // addresses. This is not yet implemented, and for now we simply
300 // expect to see these /128s.
301 lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
302 // "2001:db8::/64" plus "assigned" ASCII in hex
303 lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
304 // "2001:db8::/64" plus "random" ASCII in hex
305 lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
306 offload.setUpstreamLinkProperties(lp);
307 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
308 localPrefixes = mStringArrayCaptor.getValue();
309 assertEquals(6, localPrefixes.size());
310 assertTrue(localPrefixes.contains("127.0.0.0/8"));
311 assertTrue(localPrefixes.contains("192.0.2.0/24"));
312 assertTrue(localPrefixes.contains("fe80::/64"));
313 assertTrue(localPrefixes.contains("2001:db8::/64"));
314 assertTrue(localPrefixes.contains("2001:db8::6173:7369:676e:6564/128"));
315 assertTrue(localPrefixes.contains("2001:db8::7261:6e64:6f6d/128"));
316 // The relevant parts of the LinkProperties have not changed, but at the
317 // moment we do not de-dup upstream LinkProperties this carefully.
318 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
319 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
320 v6gws = mStringArrayCaptor.getValue();
321 assertEquals(2, v6gws.size());
322 assertTrue(v6gws.contains(ipv6Gw1));
323 assertTrue(v6gws.contains(ipv6Gw2));
324 inOrder.verifyNoMoreInteractions();
325
326 // Completely identical LinkProperties updates are de-duped.
327 offload.setUpstreamLinkProperties(lp);
328 // This LinkProperties value does not differ from the default upstream.
329 // There should be no extraneous call to setUpstreamParameters().
330 inOrder.verify(mHardware, never()).setUpstreamParameters(
331 anyObject(), anyObject(), anyObject(), anyObject());
332 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900333 }
Erik Kline92c4db02017-05-31 10:21:32 +0900334}