blob: 01339a4a2c33d8f9f8a9249de1fb860a4c4c475c [file] [log] [blame]
Erik Kline5a7c8a02017-04-30 19:36:15 +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
Erik Kline11854592017-06-15 18:06:34 +090019import static com.android.internal.util.BitUtils.uint16;
20
Erik Kline5a7c8a02017-04-30 19:36:15 +090021import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090022import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
23import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
Erik Kline7a65bc62017-06-19 11:33:59 +090024import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
Erik Klinea0885002017-07-12 00:15:26 +090025import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
markchien77c17be62019-09-25 14:33:39 +080026import android.net.util.SharedLog;
Erik Klinef4b6e342017-04-25 19:19:59 +090027import android.os.Handler;
Erik Kline5a7c8a02017-04-30 19:36:15 +090028import android.os.RemoteException;
Erik Kline7a65bc62017-06-19 11:33:59 +090029import android.system.OsConstants;
Erik Kline5a7c8a02017-04-30 19:36:15 +090030
Erik Kline7990aef2017-06-01 20:11:25 +090031import java.util.ArrayList;
32
Erik Kline5a7c8a02017-04-30 19:36:15 +090033
34/**
35 * Capture tethering dependencies, for injection.
36 *
37 * @hide
38 */
39public class OffloadHardwareInterface {
40 private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
Erik Kline9a5b02a2017-07-12 15:46:54 +090041 private static final String YIELDS = " -> ";
Erik Klinec87cd412017-07-07 17:38:30 +090042 // Change this value to control whether tether offload is enabled or
43 // disabled by default in the absence of an explicit Settings value.
44 // See accompanying unittest to distinguish 0 from non-0 values.
Erik Kline0d7f7852017-08-14 07:12:16 +000045 private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 0;
Erik Kline11854592017-06-15 18:06:34 +090046 private static final String NO_INTERFACE_NAME = "";
47 private static final String NO_IPV4_ADDRESS = "";
48 private static final String NO_IPV4_GATEWAY = "";
Erik Kline5a7c8a02017-04-30 19:36:15 +090049
50 private static native boolean configOffload();
51
Erik Klinef4b6e342017-04-25 19:19:59 +090052 private final Handler mHandler;
53 private final SharedLog mLog;
Erik Kline5a7c8a02017-04-30 19:36:15 +090054 private IOffloadControl mOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090055 private TetheringOffloadCallback mTetheringOffloadCallback;
56 private ControlCallback mControlCallback;
Erik Kline5a7c8a02017-04-30 19:36:15 +090057
markchien77c17be62019-09-25 14:33:39 +080058 /** The callback to notify status of offload management process. */
Erik Klinef4b6e342017-04-25 19:19:59 +090059 public static class ControlCallback {
markchien77c17be62019-09-25 14:33:39 +080060 /** Offload started. */
Erik Klinea0885002017-07-12 00:15:26 +090061 public void onStarted() {}
markchien77c17be62019-09-25 14:33:39 +080062 /**
63 * Offload stopped because an error has occurred in lower layer.
64 */
Erik Klinea0885002017-07-12 00:15:26 +090065 public void onStoppedError() {}
markchien77c17be62019-09-25 14:33:39 +080066 /**
67 * Offload stopped because the device has moved to a bearer on which hardware offload is
68 * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
69 * likely fail and cannot be presumed to be saved inside of the hardware management process.
70 * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
71 * offload again.
72 */
Erik Klinea0885002017-07-12 00:15:26 +090073 public void onStoppedUnsupported() {}
markchien77c17be62019-09-25 14:33:39 +080074 /** Indicate that offload is able to proivde support for this time. */
Erik Klinea0885002017-07-12 00:15:26 +090075 public void onSupportAvailable() {}
markchien77c17be62019-09-25 14:33:39 +080076 /** Offload stopped because of usage limit reached. */
Erik Klinea0885002017-07-12 00:15:26 +090077 public void onStoppedLimitReached() {}
Erik Klinef4b6e342017-04-25 19:19:59 +090078
markchien77c17be62019-09-25 14:33:39 +080079 /** Indicate to update NAT timeout. */
Erik Klinef4b6e342017-04-25 19:19:59 +090080 public void onNatTimeoutUpdate(int proto,
81 String srcAddr, int srcPort,
82 String dstAddr, int dstPort) {}
83 }
84
markchien77c17be62019-09-25 14:33:39 +080085 /** The object which records Tx/Rx forwarded bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +090086 public static class ForwardedStats {
87 public long rxBytes;
88 public long txBytes;
89
90 public ForwardedStats() {
91 rxBytes = 0;
92 txBytes = 0;
93 }
94
markchien77c17be62019-09-25 14:33:39 +080095 /** Add Tx/Rx bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +090096 public void add(ForwardedStats other) {
97 rxBytes += other.rxBytes;
98 txBytes += other.txBytes;
99 }
100
markchien77c17be62019-09-25 14:33:39 +0800101 /** Returns the string representation of this object. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900102 public String toString() {
103 return String.format("rx:%s tx:%s", rxBytes, txBytes);
104 }
105 }
106
Erik Klinef4b6e342017-04-25 19:19:59 +0900107 public OffloadHardwareInterface(Handler h, SharedLog log) {
108 mHandler = h;
109 mLog = log.forSubComponent(TAG);
110 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900111
markchien77c17be62019-09-25 14:33:39 +0800112 /** Get default value indicating whether offload is supported. */
Erik Klinec87cd412017-07-07 17:38:30 +0900113 public int getDefaultTetherOffloadDisabled() {
114 return DEFAULT_TETHER_OFFLOAD_DISABLED;
115 }
116
markchien77c17be62019-09-25 14:33:39 +0800117 /** Configure offload management process. */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900118 public boolean initOffloadConfig() {
119 return configOffload();
120 }
121
markchien77c17be62019-09-25 14:33:39 +0800122 /** Initialize the tethering offload HAL. */
Erik Klinef4b6e342017-04-25 19:19:59 +0900123 public boolean initOffloadControl(ControlCallback controlCb) {
124 mControlCallback = controlCb;
125
Erik Kline5a7c8a02017-04-30 19:36:15 +0900126 if (mOffloadControl == null) {
127 try {
128 mOffloadControl = IOffloadControl.getService();
129 } catch (RemoteException e) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900130 mLog.e("tethering offload control not supported: " + e);
Erik Kline5a7c8a02017-04-30 19:36:15 +0900131 return false;
132 }
Erik Kline87b3bfd2017-09-11 16:33:27 +0900133 if (mOffloadControl == null) {
134 mLog.e("tethering IOffloadControl.getService() returned null");
135 return false;
136 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900137 }
138
Erik Kline248e7362017-07-04 13:39:48 +0900139 final String logmsg = String.format("initOffloadControl(%s)",
140 (controlCb == null) ? "null"
141 : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
142
Erik Klinea0885002017-07-12 00:15:26 +0900143 mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
Erik Klinef4b6e342017-04-25 19:19:59 +0900144 final CbResults results = new CbResults();
145 try {
146 mOffloadControl.initOffload(
147 mTetheringOffloadCallback,
148 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800149 results.mSuccess = success;
150 results.mErrMsg = errMsg;
Erik Klinef4b6e342017-04-25 19:19:59 +0900151 });
152 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900153 record(logmsg, e);
Erik Klinef4b6e342017-04-25 19:19:59 +0900154 return false;
155 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900156
Erik Kline248e7362017-07-04 13:39:48 +0900157 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800158 return results.mSuccess;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900159 }
160
markchien77c17be62019-09-25 14:33:39 +0800161 /** Stop IOffloadControl. */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900162 public void stopOffloadControl() {
Erik Klinef4b6e342017-04-25 19:19:59 +0900163 if (mOffloadControl != null) {
164 try {
165 mOffloadControl.stopOffload(
166 (boolean success, String errMsg) -> {
167 if (!success) mLog.e("stopOffload failed: " + errMsg);
168 });
169 } catch (RemoteException e) {
170 mLog.e("failed to stopOffload: " + e);
171 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900172 }
173 mOffloadControl = null;
Erik Klinef4b6e342017-04-25 19:19:59 +0900174 mTetheringOffloadCallback = null;
175 mControlCallback = null;
Erik Kline248e7362017-07-04 13:39:48 +0900176 mLog.log("stopOffloadControl()");
Erik Klinef4b6e342017-04-25 19:19:59 +0900177 }
178
markchien77c17be62019-09-25 14:33:39 +0800179 /** Get Tx/Rx usage from last query. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900180 public ForwardedStats getForwardedStats(String upstream) {
181 final String logmsg = String.format("getForwardedStats(%s)", upstream);
182
183 final ForwardedStats stats = new ForwardedStats();
184 try {
185 mOffloadControl.getForwardedStats(
186 upstream,
187 (long rxBytes, long txBytes) -> {
188 stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
189 stats.txBytes = (txBytes > 0) ? txBytes : 0;
190 });
191 } catch (RemoteException e) {
192 record(logmsg, e);
193 return stats;
194 }
195
196 mLog.log(logmsg + YIELDS + stats);
197 return stats;
198 }
199
markchien77c17be62019-09-25 14:33:39 +0800200 /** Set local prefixes to offload management process. */
Erik Kline32179ff2017-07-04 18:28:11 +0900201 public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
202 final String logmsg = String.format("setLocalPrefixes([%s])",
203 String.join(",", localPrefixes));
204
205 final CbResults results = new CbResults();
206 try {
207 mOffloadControl.setLocalPrefixes(localPrefixes,
208 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800209 results.mSuccess = success;
210 results.mErrMsg = errMsg;
Erik Kline32179ff2017-07-04 18:28:11 +0900211 });
212 } catch (RemoteException e) {
213 record(logmsg, e);
214 return false;
215 }
216
217 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800218 return results.mSuccess;
Erik Kline32179ff2017-07-04 18:28:11 +0900219 }
220
markchien77c17be62019-09-25 14:33:39 +0800221 /** Set data limit value to offload management process. */
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900222 public boolean setDataLimit(String iface, long limit) {
223
224 final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
225
226 final CbResults results = new CbResults();
227 try {
228 mOffloadControl.setDataLimit(
229 iface, limit,
230 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800231 results.mSuccess = success;
232 results.mErrMsg = errMsg;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900233 });
234 } catch (RemoteException e) {
235 record(logmsg, e);
236 return false;
237 }
238
239 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800240 return results.mSuccess;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900241 }
242
markchien77c17be62019-09-25 14:33:39 +0800243 /** Set upstream parameters to offload management process. */
Erik Kline7990aef2017-06-01 20:11:25 +0900244 public boolean setUpstreamParameters(
245 String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
Erik Kline248e7362017-07-04 13:39:48 +0900246 iface = (iface != null) ? iface : NO_INTERFACE_NAME;
247 v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
248 v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
249 v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
250
251 final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
252 iface, v4addr, v4gateway, String.join(",", v6gws));
Erik Kline11854592017-06-15 18:06:34 +0900253
Erik Kline7990aef2017-06-01 20:11:25 +0900254 final CbResults results = new CbResults();
255 try {
256 mOffloadControl.setUpstreamParameters(
257 iface, v4addr, v4gateway, v6gws,
258 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800259 results.mSuccess = success;
260 results.mErrMsg = errMsg;
Erik Kline7990aef2017-06-01 20:11:25 +0900261 });
262 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900263 record(logmsg, e);
Erik Kline7990aef2017-06-01 20:11:25 +0900264 return false;
265 }
266
Erik Kline248e7362017-07-04 13:39:48 +0900267 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800268 return results.mSuccess;
Erik Kline7990aef2017-06-01 20:11:25 +0900269 }
270
markchien77c17be62019-09-25 14:33:39 +0800271 /** Add downstream prefix to offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900272 public boolean addDownstreamPrefix(String ifname, String prefix) {
273 final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
274
275 final CbResults results = new CbResults();
276 try {
277 mOffloadControl.addDownstream(ifname, prefix,
278 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800279 results.mSuccess = success;
280 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900281 });
282 } catch (RemoteException e) {
283 record(logmsg, e);
284 return false;
285 }
286
287 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800288 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900289 }
290
markchien77c17be62019-09-25 14:33:39 +0800291 /** Remove downstream prefix from offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900292 public boolean removeDownstreamPrefix(String ifname, String prefix) {
293 final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
294
295 final CbResults results = new CbResults();
296 try {
297 mOffloadControl.removeDownstream(ifname, prefix,
298 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800299 results.mSuccess = success;
300 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900301 });
302 } catch (RemoteException e) {
303 record(logmsg, e);
304 return false;
305 }
306
307 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800308 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900309 }
310
Erik Kline248e7362017-07-04 13:39:48 +0900311 private void record(String msg, Throwable t) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900312 mLog.e(msg + YIELDS + "exception: " + t);
Erik Kline248e7362017-07-04 13:39:48 +0900313 }
314
315 private void record(String msg, CbResults results) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900316 final String logmsg = msg + YIELDS + results;
markchien77c17be62019-09-25 14:33:39 +0800317 if (!results.mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900318 mLog.e(logmsg);
319 } else {
320 mLog.log(logmsg);
321 }
322 }
323
Erik Klinef4b6e342017-04-25 19:19:59 +0900324 private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
325 public final Handler handler;
326 public final ControlCallback controlCb;
Erik Klinea0885002017-07-12 00:15:26 +0900327 public final SharedLog log;
Erik Klinef4b6e342017-04-25 19:19:59 +0900328
markchien77c17be62019-09-25 14:33:39 +0800329 TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900330 handler = h;
331 controlCb = cb;
Erik Klinea0885002017-07-12 00:15:26 +0900332 log = sharedLog;
Erik Klinef4b6e342017-04-25 19:19:59 +0900333 }
334
335 @Override
336 public void onEvent(int event) {
Erik Klinea0885002017-07-12 00:15:26 +0900337 handler.post(() -> {
338 switch (event) {
339 case OffloadCallbackEvent.OFFLOAD_STARTED:
340 controlCb.onStarted();
341 break;
342 case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
343 controlCb.onStoppedError();
344 break;
345 case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
346 controlCb.onStoppedUnsupported();
347 break;
348 case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
349 controlCb.onSupportAvailable();
350 break;
351 case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
352 controlCb.onStoppedLimitReached();
353 break;
354 default:
355 log.e("Unsupported OffloadCallbackEvent: " + event);
356 }
357 });
Erik Klinef4b6e342017-04-25 19:19:59 +0900358 }
359
360 @Override
361 public void updateTimeout(NatTimeoutUpdate params) {
362 handler.post(() -> {
markchien77c17be62019-09-25 14:33:39 +0800363 controlCb.onNatTimeoutUpdate(
Erik Kline7a65bc62017-06-19 11:33:59 +0900364 networkProtocolToOsConstant(params.proto),
Erik Kline11854592017-06-15 18:06:34 +0900365 params.src.addr, uint16(params.src.port),
366 params.dst.addr, uint16(params.dst.port));
Erik Klinef4b6e342017-04-25 19:19:59 +0900367 });
368 }
369 }
370
Erik Kline7a65bc62017-06-19 11:33:59 +0900371 private static int networkProtocolToOsConstant(int proto) {
372 switch (proto) {
373 case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
374 case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
375 default:
376 // The caller checks this value and will log an error. Just make
377 // sure it won't collide with valid OsContants.IPPROTO_* values.
378 return -Math.abs(proto);
379 }
380 }
381
Erik Klinef4b6e342017-04-25 19:19:59 +0900382 private static class CbResults {
markchien77c17be62019-09-25 14:33:39 +0800383 boolean mSuccess;
384 String mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900385
Erik Kline0f27eed2018-05-29 19:24:43 +0900386 @Override
Erik Kline248e7362017-07-04 13:39:48 +0900387 public String toString() {
markchien77c17be62019-09-25 14:33:39 +0800388 if (mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900389 return "ok";
390 } else {
markchien77c17be62019-09-25 14:33:39 +0800391 return "fail: " + mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900392 }
393 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900394 }
395}