blob: fe92204c25c8a858d97094c402a5c88bc958a3e9 [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
markchien503be612020-04-12 21:41:29 +080017package com.android.networkstack.tethering;
Erik Kline5a7c8a02017-04-30 19:36:15 +090018
markchien986750b2019-12-06 15:24:53 +080019import static android.net.util.TetheringUtils.uint16;
Erik Kline11854592017-06-15 18:06:34 +090020
markchien0d5a36b2020-02-05 12:42:25 +080021import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
Erik Kline5a7c8a02017-04-30 19:36:15 +090022import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090023import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
24import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
Erik Kline7a65bc62017-06-19 11:33:59 +090025import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
Erik Klinea0885002017-07-12 00:15:26 +090026import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
markchien0d5a36b2020-02-05 12:42:25 +080027import android.net.netlink.NetlinkSocket;
markchien77c17be62019-09-25 14:33:39 +080028import android.net.util.SharedLog;
markchien0d5a36b2020-02-05 12:42:25 +080029import android.net.util.SocketUtils;
Erik Klinef4b6e342017-04-25 19:19:59 +090030import android.os.Handler;
markchien0d5a36b2020-02-05 12:42:25 +080031import android.os.NativeHandle;
Erik Kline5a7c8a02017-04-30 19:36:15 +090032import android.os.RemoteException;
markchien0d5a36b2020-02-05 12:42:25 +080033import android.system.ErrnoException;
34import android.system.Os;
Erik Kline7a65bc62017-06-19 11:33:59 +090035import android.system.OsConstants;
Erik Kline5a7c8a02017-04-30 19:36:15 +090036
junyulaifb7fb592020-01-09 18:56:08 +080037import com.android.internal.annotations.VisibleForTesting;
38
markchien0d5a36b2020-02-05 12:42:25 +080039import java.io.FileDescriptor;
40import java.io.IOException;
41import java.net.SocketAddress;
42import java.net.SocketException;
Erik Kline7990aef2017-06-01 20:11:25 +090043import java.util.ArrayList;
Mark Chiendbe4fa12020-04-27 09:12:37 +000044import java.util.NoSuchElementException;
Erik Kline7990aef2017-06-01 20:11:25 +090045
Erik Kline5a7c8a02017-04-30 19:36:15 +090046
47/**
48 * Capture tethering dependencies, for injection.
49 *
50 * @hide
51 */
52public class OffloadHardwareInterface {
53 private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
Erik Kline9a5b02a2017-07-12 15:46:54 +090054 private static final String YIELDS = " -> ";
Erik Klinec87cd412017-07-07 17:38:30 +090055 // Change this value to control whether tether offload is enabled or
56 // disabled by default in the absence of an explicit Settings value.
57 // See accompanying unittest to distinguish 0 from non-0 values.
Erik Kline0d7f7852017-08-14 07:12:16 +000058 private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 0;
Erik Kline11854592017-06-15 18:06:34 +090059 private static final String NO_INTERFACE_NAME = "";
60 private static final String NO_IPV4_ADDRESS = "";
61 private static final String NO_IPV4_GATEWAY = "";
markchien0d5a36b2020-02-05 12:42:25 +080062 // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
63 private static final int NF_NETLINK_CONNTRACK_NEW = 1;
64 private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
65 private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
Erik Kline5a7c8a02017-04-30 19:36:15 +090066
Erik Klinef4b6e342017-04-25 19:19:59 +090067 private final Handler mHandler;
68 private final SharedLog mLog;
Mark Chien56f007b2020-05-13 09:13:59 +000069 private final Dependencies mDeps;
Erik Kline5a7c8a02017-04-30 19:36:15 +090070 private IOffloadControl mOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090071 private TetheringOffloadCallback mTetheringOffloadCallback;
72 private ControlCallback mControlCallback;
Erik Kline5a7c8a02017-04-30 19:36:15 +090073
markchien77c17be62019-09-25 14:33:39 +080074 /** The callback to notify status of offload management process. */
Erik Klinef4b6e342017-04-25 19:19:59 +090075 public static class ControlCallback {
markchien77c17be62019-09-25 14:33:39 +080076 /** Offload started. */
Erik Klinea0885002017-07-12 00:15:26 +090077 public void onStarted() {}
markchien77c17be62019-09-25 14:33:39 +080078 /**
79 * Offload stopped because an error has occurred in lower layer.
80 */
Erik Klinea0885002017-07-12 00:15:26 +090081 public void onStoppedError() {}
markchien77c17be62019-09-25 14:33:39 +080082 /**
83 * Offload stopped because the device has moved to a bearer on which hardware offload is
84 * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
85 * likely fail and cannot be presumed to be saved inside of the hardware management process.
86 * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
87 * offload again.
88 */
Erik Klinea0885002017-07-12 00:15:26 +090089 public void onStoppedUnsupported() {}
markchien77c17be62019-09-25 14:33:39 +080090 /** Indicate that offload is able to proivde support for this time. */
Erik Klinea0885002017-07-12 00:15:26 +090091 public void onSupportAvailable() {}
markchien77c17be62019-09-25 14:33:39 +080092 /** Offload stopped because of usage limit reached. */
Erik Klinea0885002017-07-12 00:15:26 +090093 public void onStoppedLimitReached() {}
Erik Klinef4b6e342017-04-25 19:19:59 +090094
markchien77c17be62019-09-25 14:33:39 +080095 /** Indicate to update NAT timeout. */
Erik Klinef4b6e342017-04-25 19:19:59 +090096 public void onNatTimeoutUpdate(int proto,
97 String srcAddr, int srcPort,
98 String dstAddr, int dstPort) {}
99 }
100
markchien77c17be62019-09-25 14:33:39 +0800101 /** The object which records Tx/Rx forwarded bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900102 public static class ForwardedStats {
103 public long rxBytes;
104 public long txBytes;
105
106 public ForwardedStats() {
107 rxBytes = 0;
108 txBytes = 0;
109 }
110
junyulaifb7fb592020-01-09 18:56:08 +0800111 @VisibleForTesting
112 public ForwardedStats(long rxBytes, long txBytes) {
113 this.rxBytes = rxBytes;
114 this.txBytes = txBytes;
115 }
116
markchien77c17be62019-09-25 14:33:39 +0800117 /** Add Tx/Rx bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900118 public void add(ForwardedStats other) {
119 rxBytes += other.rxBytes;
120 txBytes += other.txBytes;
121 }
122
markchien77c17be62019-09-25 14:33:39 +0800123 /** Returns the string representation of this object. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900124 public String toString() {
125 return String.format("rx:%s tx:%s", rxBytes, txBytes);
126 }
127 }
128
Erik Klinef4b6e342017-04-25 19:19:59 +0900129 public OffloadHardwareInterface(Handler h, SharedLog log) {
Mark Chien56f007b2020-05-13 09:13:59 +0000130 this(h, log, new Dependencies(log));
131 }
132
133 OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900134 mHandler = h;
135 mLog = log.forSubComponent(TAG);
Mark Chien56f007b2020-05-13 09:13:59 +0000136 mDeps = deps;
137 }
138
139 /** Capture OffloadHardwareInterface dependencies, for injection. */
140 static class Dependencies {
141 private final SharedLog mLog;
142
143 Dependencies(SharedLog log) {
144 mLog = log;
145 }
146
147 public IOffloadConfig getOffloadConfig() {
148 try {
149 return IOffloadConfig.getService(true /*retry*/);
150 } catch (RemoteException | NoSuchElementException e) {
151 mLog.e("getIOffloadConfig error " + e);
152 return null;
153 }
154 }
155
156 public IOffloadControl getOffloadControl() {
157 try {
158 return IOffloadControl.getService(true /*retry*/);
159 } catch (RemoteException | NoSuchElementException e) {
160 mLog.e("tethering offload control not supported: " + e);
161 return null;
162 }
163 }
164
165 public NativeHandle createConntrackSocket(final int groups) {
166 final FileDescriptor fd;
167 try {
168 fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
169 } catch (ErrnoException e) {
170 mLog.e("Unable to create conntrack socket " + e);
171 return null;
172 }
173
174 final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
175 try {
176 Os.bind(fd, sockAddr);
177 } catch (ErrnoException | SocketException e) {
178 mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
179 try {
180 SocketUtils.closeSocket(fd);
181 } catch (IOException ie) {
182 // Nothing we can do here
183 }
184 return null;
185 }
186 try {
187 Os.connect(fd, sockAddr);
188 } catch (ErrnoException | SocketException e) {
189 mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
190 try {
191 SocketUtils.closeSocket(fd);
192 } catch (IOException ie) {
193 // Nothing we can do here
194 }
195 return null;
196 }
197
198 return new NativeHandle(fd, true);
199 }
Erik Klinef4b6e342017-04-25 19:19:59 +0900200 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900201
markchien77c17be62019-09-25 14:33:39 +0800202 /** Get default value indicating whether offload is supported. */
Erik Klinec87cd412017-07-07 17:38:30 +0900203 public int getDefaultTetherOffloadDisabled() {
204 return DEFAULT_TETHER_OFFLOAD_DISABLED;
205 }
206
markchien0d5a36b2020-02-05 12:42:25 +0800207 /**
208 * Offload management process need to know conntrack rules to support NAT, but it may not have
209 * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
210 * share them with offload management process.
211 */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900212 public boolean initOffloadConfig() {
Mark Chien56f007b2020-05-13 09:13:59 +0000213 final IOffloadConfig offloadConfig = mDeps.getOffloadConfig();
markchien0d5a36b2020-02-05 12:42:25 +0800214 if (offloadConfig == null) {
215 mLog.e("Could not find IOffloadConfig service");
216 return false;
217 }
218 // Per the IConfigOffload definition:
219 //
220 // h1 provides a file descriptor bound to the following netlink groups
221 // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
222 //
223 // h2 provides a file descriptor bound to the following netlink groups
224 // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
Mark Chien56f007b2020-05-13 09:13:59 +0000225 final NativeHandle h1 = mDeps.createConntrackSocket(
markchien0d5a36b2020-02-05 12:42:25 +0800226 NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
227 if (h1 == null) return false;
228
Mark Chien56f007b2020-05-13 09:13:59 +0000229 final NativeHandle h2 = mDeps.createConntrackSocket(
markchien0d5a36b2020-02-05 12:42:25 +0800230 NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
231 if (h2 == null) {
232 closeFdInNativeHandle(h1);
233 return false;
234 }
235
236 final CbResults results = new CbResults();
237 try {
238 offloadConfig.setHandles(h1, h2,
239 (boolean success, String errMsg) -> {
240 results.mSuccess = success;
241 results.mErrMsg = errMsg;
242 });
243 } catch (RemoteException e) {
244 record("initOffloadConfig, setHandles fail", e);
245 return false;
246 }
247 // Explicitly close FDs.
248 closeFdInNativeHandle(h1);
249 closeFdInNativeHandle(h2);
250
251 record("initOffloadConfig, setHandles results:", results);
252 return results.mSuccess;
253 }
254
255 private void closeFdInNativeHandle(final NativeHandle h) {
256 try {
257 h.close();
258 } catch (IOException | IllegalStateException e) {
259 // IllegalStateException means fd is already closed, do nothing here.
260 // Also nothing we can do if IOException.
261 }
262 }
263
markchien77c17be62019-09-25 14:33:39 +0800264 /** Initialize the tethering offload HAL. */
Erik Klinef4b6e342017-04-25 19:19:59 +0900265 public boolean initOffloadControl(ControlCallback controlCb) {
266 mControlCallback = controlCb;
267
Erik Kline5a7c8a02017-04-30 19:36:15 +0900268 if (mOffloadControl == null) {
Mark Chien56f007b2020-05-13 09:13:59 +0000269 mOffloadControl = mDeps.getOffloadControl();
Erik Kline87b3bfd2017-09-11 16:33:27 +0900270 if (mOffloadControl == null) {
271 mLog.e("tethering IOffloadControl.getService() returned null");
272 return false;
273 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900274 }
275
Erik Kline248e7362017-07-04 13:39:48 +0900276 final String logmsg = String.format("initOffloadControl(%s)",
277 (controlCb == null) ? "null"
278 : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
279
Erik Klinea0885002017-07-12 00:15:26 +0900280 mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
Erik Klinef4b6e342017-04-25 19:19:59 +0900281 final CbResults results = new CbResults();
282 try {
283 mOffloadControl.initOffload(
284 mTetheringOffloadCallback,
285 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800286 results.mSuccess = success;
287 results.mErrMsg = errMsg;
Erik Klinef4b6e342017-04-25 19:19:59 +0900288 });
289 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900290 record(logmsg, e);
Erik Klinef4b6e342017-04-25 19:19:59 +0900291 return false;
292 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900293
Erik Kline248e7362017-07-04 13:39:48 +0900294 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800295 return results.mSuccess;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900296 }
297
markchien77c17be62019-09-25 14:33:39 +0800298 /** Stop IOffloadControl. */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900299 public void stopOffloadControl() {
Erik Klinef4b6e342017-04-25 19:19:59 +0900300 if (mOffloadControl != null) {
301 try {
302 mOffloadControl.stopOffload(
303 (boolean success, String errMsg) -> {
304 if (!success) mLog.e("stopOffload failed: " + errMsg);
305 });
306 } catch (RemoteException e) {
307 mLog.e("failed to stopOffload: " + e);
308 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900309 }
310 mOffloadControl = null;
Erik Klinef4b6e342017-04-25 19:19:59 +0900311 mTetheringOffloadCallback = null;
312 mControlCallback = null;
Erik Kline248e7362017-07-04 13:39:48 +0900313 mLog.log("stopOffloadControl()");
Erik Klinef4b6e342017-04-25 19:19:59 +0900314 }
315
markchien77c17be62019-09-25 14:33:39 +0800316 /** Get Tx/Rx usage from last query. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900317 public ForwardedStats getForwardedStats(String upstream) {
318 final String logmsg = String.format("getForwardedStats(%s)", upstream);
319
320 final ForwardedStats stats = new ForwardedStats();
321 try {
322 mOffloadControl.getForwardedStats(
323 upstream,
324 (long rxBytes, long txBytes) -> {
325 stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
326 stats.txBytes = (txBytes > 0) ? txBytes : 0;
327 });
328 } catch (RemoteException e) {
329 record(logmsg, e);
330 return stats;
331 }
332
Erik Kline9a5b02a2017-07-12 15:46:54 +0900333 return stats;
334 }
335
markchien77c17be62019-09-25 14:33:39 +0800336 /** Set local prefixes to offload management process. */
Erik Kline32179ff2017-07-04 18:28:11 +0900337 public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
338 final String logmsg = String.format("setLocalPrefixes([%s])",
339 String.join(",", localPrefixes));
340
341 final CbResults results = new CbResults();
342 try {
343 mOffloadControl.setLocalPrefixes(localPrefixes,
344 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800345 results.mSuccess = success;
346 results.mErrMsg = errMsg;
Erik Kline32179ff2017-07-04 18:28:11 +0900347 });
348 } catch (RemoteException e) {
349 record(logmsg, e);
350 return false;
351 }
352
353 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800354 return results.mSuccess;
Erik Kline32179ff2017-07-04 18:28:11 +0900355 }
356
markchien77c17be62019-09-25 14:33:39 +0800357 /** Set data limit value to offload management process. */
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900358 public boolean setDataLimit(String iface, long limit) {
359
360 final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
361
362 final CbResults results = new CbResults();
363 try {
364 mOffloadControl.setDataLimit(
365 iface, limit,
366 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800367 results.mSuccess = success;
368 results.mErrMsg = errMsg;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900369 });
370 } catch (RemoteException e) {
371 record(logmsg, e);
372 return false;
373 }
374
375 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800376 return results.mSuccess;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900377 }
378
markchien77c17be62019-09-25 14:33:39 +0800379 /** Set upstream parameters to offload management process. */
Erik Kline7990aef2017-06-01 20:11:25 +0900380 public boolean setUpstreamParameters(
381 String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
Erik Kline248e7362017-07-04 13:39:48 +0900382 iface = (iface != null) ? iface : NO_INTERFACE_NAME;
383 v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
384 v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
385 v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
386
387 final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
388 iface, v4addr, v4gateway, String.join(",", v6gws));
Erik Kline11854592017-06-15 18:06:34 +0900389
Erik Kline7990aef2017-06-01 20:11:25 +0900390 final CbResults results = new CbResults();
391 try {
392 mOffloadControl.setUpstreamParameters(
393 iface, v4addr, v4gateway, v6gws,
394 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800395 results.mSuccess = success;
396 results.mErrMsg = errMsg;
Erik Kline7990aef2017-06-01 20:11:25 +0900397 });
398 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900399 record(logmsg, e);
Erik Kline7990aef2017-06-01 20:11:25 +0900400 return false;
401 }
402
Erik Kline248e7362017-07-04 13:39:48 +0900403 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800404 return results.mSuccess;
Erik Kline7990aef2017-06-01 20:11:25 +0900405 }
406
markchien77c17be62019-09-25 14:33:39 +0800407 /** Add downstream prefix to offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900408 public boolean addDownstreamPrefix(String ifname, String prefix) {
409 final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
410
411 final CbResults results = new CbResults();
412 try {
413 mOffloadControl.addDownstream(ifname, prefix,
414 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800415 results.mSuccess = success;
416 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900417 });
418 } catch (RemoteException e) {
419 record(logmsg, e);
420 return false;
421 }
422
423 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800424 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900425 }
426
markchien77c17be62019-09-25 14:33:39 +0800427 /** Remove downstream prefix from offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900428 public boolean removeDownstreamPrefix(String ifname, String prefix) {
429 final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
430
431 final CbResults results = new CbResults();
432 try {
433 mOffloadControl.removeDownstream(ifname, prefix,
434 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800435 results.mSuccess = success;
436 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900437 });
438 } catch (RemoteException e) {
439 record(logmsg, e);
440 return false;
441 }
442
443 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800444 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900445 }
446
Erik Kline248e7362017-07-04 13:39:48 +0900447 private void record(String msg, Throwable t) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900448 mLog.e(msg + YIELDS + "exception: " + t);
Erik Kline248e7362017-07-04 13:39:48 +0900449 }
450
451 private void record(String msg, CbResults results) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900452 final String logmsg = msg + YIELDS + results;
markchien77c17be62019-09-25 14:33:39 +0800453 if (!results.mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900454 mLog.e(logmsg);
455 } else {
456 mLog.log(logmsg);
457 }
458 }
459
Erik Klinef4b6e342017-04-25 19:19:59 +0900460 private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
461 public final Handler handler;
462 public final ControlCallback controlCb;
Erik Klinea0885002017-07-12 00:15:26 +0900463 public final SharedLog log;
Erik Klinef4b6e342017-04-25 19:19:59 +0900464
markchien77c17be62019-09-25 14:33:39 +0800465 TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900466 handler = h;
467 controlCb = cb;
Erik Klinea0885002017-07-12 00:15:26 +0900468 log = sharedLog;
Erik Klinef4b6e342017-04-25 19:19:59 +0900469 }
470
471 @Override
472 public void onEvent(int event) {
Erik Klinea0885002017-07-12 00:15:26 +0900473 handler.post(() -> {
474 switch (event) {
475 case OffloadCallbackEvent.OFFLOAD_STARTED:
476 controlCb.onStarted();
477 break;
478 case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
479 controlCb.onStoppedError();
480 break;
481 case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
482 controlCb.onStoppedUnsupported();
483 break;
484 case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
485 controlCb.onSupportAvailable();
486 break;
487 case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
488 controlCb.onStoppedLimitReached();
489 break;
490 default:
491 log.e("Unsupported OffloadCallbackEvent: " + event);
492 }
493 });
Erik Klinef4b6e342017-04-25 19:19:59 +0900494 }
495
496 @Override
497 public void updateTimeout(NatTimeoutUpdate params) {
498 handler.post(() -> {
markchien77c17be62019-09-25 14:33:39 +0800499 controlCb.onNatTimeoutUpdate(
Erik Kline7a65bc62017-06-19 11:33:59 +0900500 networkProtocolToOsConstant(params.proto),
Erik Kline11854592017-06-15 18:06:34 +0900501 params.src.addr, uint16(params.src.port),
502 params.dst.addr, uint16(params.dst.port));
Erik Klinef4b6e342017-04-25 19:19:59 +0900503 });
504 }
505 }
506
Erik Kline7a65bc62017-06-19 11:33:59 +0900507 private static int networkProtocolToOsConstant(int proto) {
508 switch (proto) {
509 case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
510 case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
511 default:
512 // The caller checks this value and will log an error. Just make
513 // sure it won't collide with valid OsContants.IPPROTO_* values.
514 return -Math.abs(proto);
515 }
516 }
517
Erik Klinef4b6e342017-04-25 19:19:59 +0900518 private static class CbResults {
markchien77c17be62019-09-25 14:33:39 +0800519 boolean mSuccess;
520 String mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900521
Erik Kline0f27eed2018-05-29 19:24:43 +0900522 @Override
Erik Kline248e7362017-07-04 13:39:48 +0900523 public String toString() {
markchien77c17be62019-09-25 14:33:39 +0800524 if (mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900525 return "ok";
526 } else {
markchien77c17be62019-09-25 14:33:39 +0800527 return "fail: " + mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900528 }
529 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900530 }
531}