blob: 293f8eae32d5e79fdab14f35cd20f71fe0e5319e [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;
Erik Kline5a7c8a02017-04-30 19:36:15 +090069 private IOffloadControl mOffloadControl;
Erik Klinef4b6e342017-04-25 19:19:59 +090070 private TetheringOffloadCallback mTetheringOffloadCallback;
71 private ControlCallback mControlCallback;
Erik Kline5a7c8a02017-04-30 19:36:15 +090072
markchien77c17be62019-09-25 14:33:39 +080073 /** The callback to notify status of offload management process. */
Erik Klinef4b6e342017-04-25 19:19:59 +090074 public static class ControlCallback {
markchien77c17be62019-09-25 14:33:39 +080075 /** Offload started. */
Erik Klinea0885002017-07-12 00:15:26 +090076 public void onStarted() {}
markchien77c17be62019-09-25 14:33:39 +080077 /**
78 * Offload stopped because an error has occurred in lower layer.
79 */
Erik Klinea0885002017-07-12 00:15:26 +090080 public void onStoppedError() {}
markchien77c17be62019-09-25 14:33:39 +080081 /**
82 * Offload stopped because the device has moved to a bearer on which hardware offload is
83 * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
84 * likely fail and cannot be presumed to be saved inside of the hardware management process.
85 * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
86 * offload again.
87 */
Erik Klinea0885002017-07-12 00:15:26 +090088 public void onStoppedUnsupported() {}
markchien77c17be62019-09-25 14:33:39 +080089 /** Indicate that offload is able to proivde support for this time. */
Erik Klinea0885002017-07-12 00:15:26 +090090 public void onSupportAvailable() {}
markchien77c17be62019-09-25 14:33:39 +080091 /** Offload stopped because of usage limit reached. */
Erik Klinea0885002017-07-12 00:15:26 +090092 public void onStoppedLimitReached() {}
Erik Klinef4b6e342017-04-25 19:19:59 +090093
markchien77c17be62019-09-25 14:33:39 +080094 /** Indicate to update NAT timeout. */
Erik Klinef4b6e342017-04-25 19:19:59 +090095 public void onNatTimeoutUpdate(int proto,
96 String srcAddr, int srcPort,
97 String dstAddr, int dstPort) {}
98 }
99
markchien77c17be62019-09-25 14:33:39 +0800100 /** The object which records Tx/Rx forwarded bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900101 public static class ForwardedStats {
102 public long rxBytes;
103 public long txBytes;
104
105 public ForwardedStats() {
106 rxBytes = 0;
107 txBytes = 0;
108 }
109
junyulaifb7fb592020-01-09 18:56:08 +0800110 @VisibleForTesting
111 public ForwardedStats(long rxBytes, long txBytes) {
112 this.rxBytes = rxBytes;
113 this.txBytes = txBytes;
114 }
115
markchien77c17be62019-09-25 14:33:39 +0800116 /** Add Tx/Rx bytes. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900117 public void add(ForwardedStats other) {
118 rxBytes += other.rxBytes;
119 txBytes += other.txBytes;
120 }
121
markchien77c17be62019-09-25 14:33:39 +0800122 /** Returns the string representation of this object. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900123 public String toString() {
124 return String.format("rx:%s tx:%s", rxBytes, txBytes);
125 }
126 }
127
Erik Klinef4b6e342017-04-25 19:19:59 +0900128 public OffloadHardwareInterface(Handler h, SharedLog log) {
129 mHandler = h;
130 mLog = log.forSubComponent(TAG);
131 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900132
markchien77c17be62019-09-25 14:33:39 +0800133 /** Get default value indicating whether offload is supported. */
Erik Klinec87cd412017-07-07 17:38:30 +0900134 public int getDefaultTetherOffloadDisabled() {
135 return DEFAULT_TETHER_OFFLOAD_DISABLED;
136 }
137
markchien0d5a36b2020-02-05 12:42:25 +0800138 /**
139 * Offload management process need to know conntrack rules to support NAT, but it may not have
140 * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
141 * share them with offload management process.
142 */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900143 public boolean initOffloadConfig() {
markchien0d5a36b2020-02-05 12:42:25 +0800144 IOffloadConfig offloadConfig;
145 try {
Treehugger Robotd07c0072020-04-21 15:16:43 +0000146 offloadConfig = IOffloadConfig.getService(true /*retry*/);
Mark Chiendbe4fa12020-04-27 09:12:37 +0000147 } catch (RemoteException | NoSuchElementException e) {
markchien0d5a36b2020-02-05 12:42:25 +0800148 mLog.e("getIOffloadConfig error " + e);
149 return false;
150 }
151 if (offloadConfig == null) {
152 mLog.e("Could not find IOffloadConfig service");
153 return false;
154 }
155 // Per the IConfigOffload definition:
156 //
157 // h1 provides a file descriptor bound to the following netlink groups
158 // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
159 //
160 // h2 provides a file descriptor bound to the following netlink groups
161 // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
162 final NativeHandle h1 = createConntrackSocket(
163 NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
164 if (h1 == null) return false;
165
166 final NativeHandle h2 = createConntrackSocket(
167 NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
168 if (h2 == null) {
169 closeFdInNativeHandle(h1);
170 return false;
171 }
172
173 final CbResults results = new CbResults();
174 try {
175 offloadConfig.setHandles(h1, h2,
176 (boolean success, String errMsg) -> {
177 results.mSuccess = success;
178 results.mErrMsg = errMsg;
179 });
180 } catch (RemoteException e) {
181 record("initOffloadConfig, setHandles fail", e);
182 return false;
183 }
184 // Explicitly close FDs.
185 closeFdInNativeHandle(h1);
186 closeFdInNativeHandle(h2);
187
188 record("initOffloadConfig, setHandles results:", results);
189 return results.mSuccess;
190 }
191
192 private void closeFdInNativeHandle(final NativeHandle h) {
193 try {
194 h.close();
195 } catch (IOException | IllegalStateException e) {
196 // IllegalStateException means fd is already closed, do nothing here.
197 // Also nothing we can do if IOException.
198 }
199 }
200
201 private NativeHandle createConntrackSocket(final int groups) {
202 FileDescriptor fd;
203 try {
204 fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
205 } catch (ErrnoException e) {
206 mLog.e("Unable to create conntrack socket " + e);
207 return null;
208 }
209
210 final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
211 try {
212 Os.bind(fd, sockAddr);
213 } catch (ErrnoException | SocketException e) {
214 mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
215 try {
216 SocketUtils.closeSocket(fd);
217 } catch (IOException ie) {
218 // Nothing we can do here
219 }
220 return null;
221 }
222 try {
223 Os.connect(fd, sockAddr);
224 } catch (ErrnoException | SocketException e) {
225 mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
226 try {
227 SocketUtils.closeSocket(fd);
228 } catch (IOException ie) {
229 // Nothing we can do here
230 }
231 return null;
232 }
233
234 return new NativeHandle(fd, true);
Erik Kline5a7c8a02017-04-30 19:36:15 +0900235 }
236
markchien77c17be62019-09-25 14:33:39 +0800237 /** Initialize the tethering offload HAL. */
Erik Klinef4b6e342017-04-25 19:19:59 +0900238 public boolean initOffloadControl(ControlCallback controlCb) {
239 mControlCallback = controlCb;
240
Erik Kline5a7c8a02017-04-30 19:36:15 +0900241 if (mOffloadControl == null) {
242 try {
Mark Chiendbe4fa12020-04-27 09:12:37 +0000243 mOffloadControl = IOffloadControl.getService(true /*retry*/);
244 } catch (RemoteException | NoSuchElementException e) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900245 mLog.e("tethering offload control not supported: " + e);
Erik Kline5a7c8a02017-04-30 19:36:15 +0900246 return false;
247 }
Erik Kline87b3bfd2017-09-11 16:33:27 +0900248 if (mOffloadControl == null) {
249 mLog.e("tethering IOffloadControl.getService() returned null");
250 return false;
251 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900252 }
253
Erik Kline248e7362017-07-04 13:39:48 +0900254 final String logmsg = String.format("initOffloadControl(%s)",
255 (controlCb == null) ? "null"
256 : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
257
Erik Klinea0885002017-07-12 00:15:26 +0900258 mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
Erik Klinef4b6e342017-04-25 19:19:59 +0900259 final CbResults results = new CbResults();
260 try {
261 mOffloadControl.initOffload(
262 mTetheringOffloadCallback,
263 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800264 results.mSuccess = success;
265 results.mErrMsg = errMsg;
Erik Klinef4b6e342017-04-25 19:19:59 +0900266 });
267 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900268 record(logmsg, e);
Erik Klinef4b6e342017-04-25 19:19:59 +0900269 return false;
270 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900271
Erik Kline248e7362017-07-04 13:39:48 +0900272 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800273 return results.mSuccess;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900274 }
275
markchien77c17be62019-09-25 14:33:39 +0800276 /** Stop IOffloadControl. */
Erik Kline5a7c8a02017-04-30 19:36:15 +0900277 public void stopOffloadControl() {
Erik Klinef4b6e342017-04-25 19:19:59 +0900278 if (mOffloadControl != null) {
279 try {
280 mOffloadControl.stopOffload(
281 (boolean success, String errMsg) -> {
282 if (!success) mLog.e("stopOffload failed: " + errMsg);
283 });
284 } catch (RemoteException e) {
285 mLog.e("failed to stopOffload: " + e);
286 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900287 }
288 mOffloadControl = null;
Erik Klinef4b6e342017-04-25 19:19:59 +0900289 mTetheringOffloadCallback = null;
290 mControlCallback = null;
Erik Kline248e7362017-07-04 13:39:48 +0900291 mLog.log("stopOffloadControl()");
Erik Klinef4b6e342017-04-25 19:19:59 +0900292 }
293
markchien77c17be62019-09-25 14:33:39 +0800294 /** Get Tx/Rx usage from last query. */
Erik Kline9a5b02a2017-07-12 15:46:54 +0900295 public ForwardedStats getForwardedStats(String upstream) {
296 final String logmsg = String.format("getForwardedStats(%s)", upstream);
297
298 final ForwardedStats stats = new ForwardedStats();
299 try {
300 mOffloadControl.getForwardedStats(
301 upstream,
302 (long rxBytes, long txBytes) -> {
303 stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
304 stats.txBytes = (txBytes > 0) ? txBytes : 0;
305 });
306 } catch (RemoteException e) {
307 record(logmsg, e);
308 return stats;
309 }
310
Erik Kline9a5b02a2017-07-12 15:46:54 +0900311 return stats;
312 }
313
markchien77c17be62019-09-25 14:33:39 +0800314 /** Set local prefixes to offload management process. */
Erik Kline32179ff2017-07-04 18:28:11 +0900315 public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
316 final String logmsg = String.format("setLocalPrefixes([%s])",
317 String.join(",", localPrefixes));
318
319 final CbResults results = new CbResults();
320 try {
321 mOffloadControl.setLocalPrefixes(localPrefixes,
322 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800323 results.mSuccess = success;
324 results.mErrMsg = errMsg;
Erik Kline32179ff2017-07-04 18:28:11 +0900325 });
326 } catch (RemoteException e) {
327 record(logmsg, e);
328 return false;
329 }
330
331 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800332 return results.mSuccess;
Erik Kline32179ff2017-07-04 18:28:11 +0900333 }
334
markchien77c17be62019-09-25 14:33:39 +0800335 /** Set data limit value to offload management process. */
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900336 public boolean setDataLimit(String iface, long limit) {
337
338 final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
339
340 final CbResults results = new CbResults();
341 try {
342 mOffloadControl.setDataLimit(
343 iface, limit,
344 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800345 results.mSuccess = success;
346 results.mErrMsg = errMsg;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +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;
Lorenzo Colitti62801ec2017-08-11 13:47:49 +0900355 }
356
markchien77c17be62019-09-25 14:33:39 +0800357 /** Set upstream parameters to offload management process. */
Erik Kline7990aef2017-06-01 20:11:25 +0900358 public boolean setUpstreamParameters(
359 String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
Erik Kline248e7362017-07-04 13:39:48 +0900360 iface = (iface != null) ? iface : NO_INTERFACE_NAME;
361 v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
362 v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
363 v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
364
365 final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
366 iface, v4addr, v4gateway, String.join(",", v6gws));
Erik Kline11854592017-06-15 18:06:34 +0900367
Erik Kline7990aef2017-06-01 20:11:25 +0900368 final CbResults results = new CbResults();
369 try {
370 mOffloadControl.setUpstreamParameters(
371 iface, v4addr, v4gateway, v6gws,
372 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800373 results.mSuccess = success;
374 results.mErrMsg = errMsg;
Erik Kline7990aef2017-06-01 20:11:25 +0900375 });
376 } catch (RemoteException e) {
Erik Kline248e7362017-07-04 13:39:48 +0900377 record(logmsg, e);
Erik Kline7990aef2017-06-01 20:11:25 +0900378 return false;
379 }
380
Erik Kline248e7362017-07-04 13:39:48 +0900381 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800382 return results.mSuccess;
Erik Kline7990aef2017-06-01 20:11:25 +0900383 }
384
markchien77c17be62019-09-25 14:33:39 +0800385 /** Add downstream prefix to offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900386 public boolean addDownstreamPrefix(String ifname, String prefix) {
387 final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
388
389 final CbResults results = new CbResults();
390 try {
391 mOffloadControl.addDownstream(ifname, prefix,
392 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800393 results.mSuccess = success;
394 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900395 });
396 } catch (RemoteException e) {
397 record(logmsg, e);
398 return false;
399 }
400
401 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800402 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900403 }
404
markchien77c17be62019-09-25 14:33:39 +0800405 /** Remove downstream prefix from offload management process. */
Erik Klineed962a82017-07-06 19:49:35 +0900406 public boolean removeDownstreamPrefix(String ifname, String prefix) {
407 final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
408
409 final CbResults results = new CbResults();
410 try {
411 mOffloadControl.removeDownstream(ifname, prefix,
412 (boolean success, String errMsg) -> {
markchien77c17be62019-09-25 14:33:39 +0800413 results.mSuccess = success;
414 results.mErrMsg = errMsg;
Erik Klineed962a82017-07-06 19:49:35 +0900415 });
416 } catch (RemoteException e) {
417 record(logmsg, e);
418 return false;
419 }
420
421 record(logmsg, results);
markchien77c17be62019-09-25 14:33:39 +0800422 return results.mSuccess;
Erik Klineed962a82017-07-06 19:49:35 +0900423 }
424
Erik Kline248e7362017-07-04 13:39:48 +0900425 private void record(String msg, Throwable t) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900426 mLog.e(msg + YIELDS + "exception: " + t);
Erik Kline248e7362017-07-04 13:39:48 +0900427 }
428
429 private void record(String msg, CbResults results) {
Erik Kline9a5b02a2017-07-12 15:46:54 +0900430 final String logmsg = msg + YIELDS + results;
markchien77c17be62019-09-25 14:33:39 +0800431 if (!results.mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900432 mLog.e(logmsg);
433 } else {
434 mLog.log(logmsg);
435 }
436 }
437
Erik Klinef4b6e342017-04-25 19:19:59 +0900438 private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
439 public final Handler handler;
440 public final ControlCallback controlCb;
Erik Klinea0885002017-07-12 00:15:26 +0900441 public final SharedLog log;
Erik Klinef4b6e342017-04-25 19:19:59 +0900442
markchien77c17be62019-09-25 14:33:39 +0800443 TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
Erik Klinef4b6e342017-04-25 19:19:59 +0900444 handler = h;
445 controlCb = cb;
Erik Klinea0885002017-07-12 00:15:26 +0900446 log = sharedLog;
Erik Klinef4b6e342017-04-25 19:19:59 +0900447 }
448
449 @Override
450 public void onEvent(int event) {
Erik Klinea0885002017-07-12 00:15:26 +0900451 handler.post(() -> {
452 switch (event) {
453 case OffloadCallbackEvent.OFFLOAD_STARTED:
454 controlCb.onStarted();
455 break;
456 case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
457 controlCb.onStoppedError();
458 break;
459 case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
460 controlCb.onStoppedUnsupported();
461 break;
462 case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
463 controlCb.onSupportAvailable();
464 break;
465 case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
466 controlCb.onStoppedLimitReached();
467 break;
468 default:
469 log.e("Unsupported OffloadCallbackEvent: " + event);
470 }
471 });
Erik Klinef4b6e342017-04-25 19:19:59 +0900472 }
473
474 @Override
475 public void updateTimeout(NatTimeoutUpdate params) {
476 handler.post(() -> {
markchien77c17be62019-09-25 14:33:39 +0800477 controlCb.onNatTimeoutUpdate(
Erik Kline7a65bc62017-06-19 11:33:59 +0900478 networkProtocolToOsConstant(params.proto),
Erik Kline11854592017-06-15 18:06:34 +0900479 params.src.addr, uint16(params.src.port),
480 params.dst.addr, uint16(params.dst.port));
Erik Klinef4b6e342017-04-25 19:19:59 +0900481 });
482 }
483 }
484
Erik Kline7a65bc62017-06-19 11:33:59 +0900485 private static int networkProtocolToOsConstant(int proto) {
486 switch (proto) {
487 case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
488 case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
489 default:
490 // The caller checks this value and will log an error. Just make
491 // sure it won't collide with valid OsContants.IPPROTO_* values.
492 return -Math.abs(proto);
493 }
494 }
495
Erik Klinef4b6e342017-04-25 19:19:59 +0900496 private static class CbResults {
markchien77c17be62019-09-25 14:33:39 +0800497 boolean mSuccess;
498 String mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900499
Erik Kline0f27eed2018-05-29 19:24:43 +0900500 @Override
Erik Kline248e7362017-07-04 13:39:48 +0900501 public String toString() {
markchien77c17be62019-09-25 14:33:39 +0800502 if (mSuccess) {
Erik Kline248e7362017-07-04 13:39:48 +0900503 return "ok";
504 } else {
markchien77c17be62019-09-25 14:33:39 +0800505 return "fail: " + mErrMsg;
Erik Kline248e7362017-07-04 13:39:48 +0900506 }
507 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900508 }
509}