blob: c543fad62dba3066bbefede654474d91f1162486 [file] [log] [blame]
Mark Chien56f007b2020-05-13 09:13:59 +00001/*
2 * Copyright (C) 2020 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.networkstack.tethering;
18
19import static android.net.util.TetheringUtils.uint16;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000020import static android.system.OsConstants.SOCK_STREAM;
21import static android.system.OsConstants.AF_UNIX;
Mark Chien56f007b2020-05-13 09:13:59 +000022
23import static org.junit.Assert.assertEquals;
24import static org.junit.Assert.assertNotNull;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000025import static org.junit.Assert.fail;
Mark Chien56f007b2020-05-13 09:13:59 +000026import static org.mockito.ArgumentMatchers.any;
27import static org.mockito.ArgumentMatchers.eq;
28import static org.mockito.Mockito.spy;
29import static org.mockito.Mockito.verify;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000030import static org.mockito.Mockito.when;
Mark Chien56f007b2020-05-13 09:13:59 +000031
32import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
33import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
34import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
35import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
36import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
37import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000038import android.net.netlink.StructNlMsgHdr;
Mark Chien56f007b2020-05-13 09:13:59 +000039import android.net.util.SharedLog;
40import android.os.Handler;
41import android.os.NativeHandle;
42import android.os.test.TestLooper;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000043import android.system.ErrnoException;
Mark Chien56f007b2020-05-13 09:13:59 +000044import android.system.OsConstants;
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000045import android.system.Os;
Mark Chien56f007b2020-05-13 09:13:59 +000046
47import androidx.test.filters.SmallTest;
48import androidx.test.runner.AndroidJUnit4;
49
50import org.junit.Before;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53import org.mockito.ArgumentCaptor;
54import org.mockito.Mock;
55import org.mockito.MockitoAnnotations;
56
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000057import java.io.FileDescriptor;
58import java.io.OutputStream;
59import java.nio.ByteBuffer;
Mark Chien56f007b2020-05-13 09:13:59 +000060import java.util.ArrayList;
61
62@RunWith(AndroidJUnit4.class)
63@SmallTest
64public final class OffloadHardwareInterfaceTest {
65 private static final String RMNET0 = "test_rmnet_data0";
66
67 private final TestLooper mTestLooper = new TestLooper();
68
69 private OffloadHardwareInterface mOffloadHw;
70 private ITetheringOffloadCallback mTetheringOffloadCallback;
71 private OffloadHardwareInterface.ControlCallback mControlCallback;
72
73 @Mock private IOffloadConfig mIOffloadConfig;
74 @Mock private IOffloadControl mIOffloadControl;
75 @Mock private NativeHandle mNativeHandle;
76
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +000077 // Random values to test Netlink message.
78 private static final short TEST_TYPE = 184;
79 private static final short TEST_FLAGS = 263;
80
Mark Chien56f007b2020-05-13 09:13:59 +000081 class MyDependencies extends OffloadHardwareInterface.Dependencies {
82 MyDependencies(SharedLog log) {
83 super(log);
84 }
85
86 @Override
87 public IOffloadConfig getOffloadConfig() {
88 return mIOffloadConfig;
89 }
90
91 @Override
92 public IOffloadControl getOffloadControl() {
93 return mIOffloadControl;
94 }
95
96 @Override
97 public NativeHandle createConntrackSocket(final int groups) {
98 return mNativeHandle;
99 }
100 }
101
102 @Before
103 public void setUp() {
104 MockitoAnnotations.initMocks(this);
105 final SharedLog log = new SharedLog("test");
106 mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
107 new MyDependencies(log));
108 mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
109 }
110
111 private void startOffloadHardwareInterface() throws Exception {
112 mOffloadHw.initOffloadConfig();
113 mOffloadHw.initOffloadControl(mControlCallback);
114 final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
115 ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
116 verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any());
117 mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue();
118 }
119
120 @Test
121 public void testGetForwardedStats() throws Exception {
122 startOffloadHardwareInterface();
123 final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
124 verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
125 assertNotNull(stats);
126 }
127
128 @Test
129 public void testSetLocalPrefixes() throws Exception {
130 startOffloadHardwareInterface();
131 final ArrayList<String> localPrefixes = new ArrayList<>();
132 localPrefixes.add("127.0.0.0/8");
133 localPrefixes.add("fe80::/64");
134 mOffloadHw.setLocalPrefixes(localPrefixes);
135 verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any());
136 }
137
138 @Test
139 public void testSetDataLimit() throws Exception {
140 startOffloadHardwareInterface();
141 final long limit = 12345;
142 mOffloadHw.setDataLimit(RMNET0, limit);
143 verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
144 }
145
146 @Test
147 public void testSetUpstreamParameters() throws Exception {
148 startOffloadHardwareInterface();
149 final String v4addr = "192.168.10.1";
150 final String v4gateway = "192.168.10.255";
151 final ArrayList<String> v6gws = new ArrayList<>(0);
152 v6gws.add("2001:db8::1");
153 mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws);
154 verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
155 eq(v6gws), any());
156
157 final ArgumentCaptor<ArrayList<String>> mArrayListCaptor =
158 ArgumentCaptor.forClass(ArrayList.class);
159 mOffloadHw.setUpstreamParameters(null, null, null, null);
160 verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""),
161 mArrayListCaptor.capture(), any());
162 assertEquals(mArrayListCaptor.getValue().size(), 0);
163 }
164
165 @Test
166 public void testUpdateDownstreamPrefix() throws Exception {
167 startOffloadHardwareInterface();
168 final String ifName = "wlan1";
169 final String prefix = "192.168.43.0/24";
170 mOffloadHw.addDownstreamPrefix(ifName, prefix);
171 verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any());
172
173 mOffloadHw.removeDownstreamPrefix(ifName, prefix);
174 verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any());
175 }
176
177 @Test
178 public void testTetheringOffloadCallback() throws Exception {
179 startOffloadHardwareInterface();
180
181 mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
182 mTestLooper.dispatchAll();
183 verify(mControlCallback).onStarted();
184
185 mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
186 mTestLooper.dispatchAll();
187 verify(mControlCallback).onStoppedError();
188
189 mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
190 mTestLooper.dispatchAll();
191 verify(mControlCallback).onStoppedUnsupported();
192
193 mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
194 mTestLooper.dispatchAll();
195 verify(mControlCallback).onSupportAvailable();
196
197 mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
198 mTestLooper.dispatchAll();
199 verify(mControlCallback).onStoppedLimitReached();
200
201 final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
202 mTetheringOffloadCallback.updateTimeout(tcpParams);
203 mTestLooper.dispatchAll();
204 verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
205 eq(tcpParams.src.addr),
206 eq(uint16(tcpParams.src.port)),
207 eq(tcpParams.dst.addr),
208 eq(uint16(tcpParams.dst.port)));
209
210 final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
211 mTetheringOffloadCallback.updateTimeout(udpParams);
212 mTestLooper.dispatchAll();
213 verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
214 eq(udpParams.src.addr),
215 eq(uint16(udpParams.src.port)),
216 eq(udpParams.dst.addr),
217 eq(uint16(udpParams.dst.port)));
218 }
219
Lorenzo Colitti8c2e6b82020-06-24 03:44:31 +0000220 @Test
221 public void testNetlinkMessage() throws Exception {
222 FileDescriptor writeSocket = new FileDescriptor();
223 FileDescriptor readSocket = new FileDescriptor();
224 try {
225 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writeSocket, readSocket);
226 } catch (ErrnoException e) {
227 fail();
228 return;
229 }
230 when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
231
232 mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
233
234 ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
235 int read = Os.read(readSocket, buffer);
236
237 buffer.flip();
238 assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
239 assertEquals(TEST_TYPE, buffer.getShort());
240 assertEquals(TEST_FLAGS, buffer.getShort());
241 assertEquals(1 /* seq */, buffer.getInt());
242 assertEquals(0 /* pid */, buffer.getInt());
243 }
244
Mark Chien56f007b2020-05-13 09:13:59 +0000245 private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
246 final NatTimeoutUpdate params = new NatTimeoutUpdate();
247 params.proto = proto;
248 params.src.addr = "192.168.43.200";
249 params.src.port = 100;
250 params.dst.addr = "172.50.46.169";
251 params.dst.port = 150;
252 return params;
253 }
254}