blob: 20ec20681ce22ff9dd61e4a574c296bfd921bdca [file] [log] [blame]
Erik Klinee0cce212017-03-06 14:05:23 +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 Kline92c4db02017-05-31 10:21:32 +090019import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
20
21import android.content.ContentResolver;
Erik Kline3a5278f2017-06-24 19:29:10 +090022import android.net.IpPrefix;
Erik Klinee0cce212017-03-06 14:05:23 +090023import android.net.LinkProperties;
Erik Kline7990aef2017-06-01 20:11:25 +090024import android.net.RouteInfo;
Erik Kline7747fd42017-05-12 16:52:48 +090025import android.net.util.SharedLog;
Erik Kline92c4db02017-05-31 10:21:32 +090026import android.os.Handler;
27import android.provider.Settings;
Erik Klinee0cce212017-03-06 14:05:23 +090028
Erik Kline7990aef2017-06-01 20:11:25 +090029import java.net.Inet4Address;
30import java.net.InetAddress;
31import java.util.ArrayList;
Erik Kline3a5278f2017-06-24 19:29:10 +090032import java.util.Set;
Erik Kline7990aef2017-06-01 20:11:25 +090033
Erik Klinee0cce212017-03-06 14:05:23 +090034/**
Erik Kline5a7c8a02017-04-30 19:36:15 +090035 * A class to encapsulate the business logic of programming the tethering
36 * hardware offload interface.
Erik Klinee0cce212017-03-06 14:05:23 +090037 *
38 * @hide
39 */
40public class OffloadController {
41 private static final String TAG = OffloadController.class.getSimpleName();
42
43 private final Handler mHandler;
Erik Kline5a7c8a02017-04-30 19:36:15 +090044 private final OffloadHardwareInterface mHwInterface;
Erik Kline92c4db02017-05-31 10:21:32 +090045 private final ContentResolver mContentResolver;
Erik Kline7747fd42017-05-12 16:52:48 +090046 private final SharedLog mLog;
Erik Kline5a7c8a02017-04-30 19:36:15 +090047 private boolean mConfigInitialized;
48 private boolean mControlInitialized;
Erik Klinee0cce212017-03-06 14:05:23 +090049 private LinkProperties mUpstreamLinkProperties;
Erik Kline3a5278f2017-06-24 19:29:10 +090050 private Set<IpPrefix> mExemptPrefixes;
Erik Klinee0cce212017-03-06 14:05:23 +090051
Erik Kline92c4db02017-05-31 10:21:32 +090052 public OffloadController(Handler h, OffloadHardwareInterface hwi,
53 ContentResolver contentResolver, SharedLog log) {
Erik Klinee0cce212017-03-06 14:05:23 +090054 mHandler = h;
Erik Kline5a7c8a02017-04-30 19:36:15 +090055 mHwInterface = hwi;
Erik Kline92c4db02017-05-31 10:21:32 +090056 mContentResolver = contentResolver;
Erik Kline7747fd42017-05-12 16:52:48 +090057 mLog = log.forSubComponent(TAG);
Erik Klinee0cce212017-03-06 14:05:23 +090058 }
59
60 public void start() {
Erik Kline6a64c152017-07-06 12:38:48 +090061 if (started()) return;
62
63 if (isOffloadDisabled()) {
64 mLog.i("tethering offload disabled");
65 return;
66 }
Erik Kline5a7c8a02017-04-30 19:36:15 +090067
68 if (!mConfigInitialized) {
69 mConfigInitialized = mHwInterface.initOffloadConfig();
70 if (!mConfigInitialized) {
Erik Kline7747fd42017-05-12 16:52:48 +090071 mLog.i("tethering offload config not supported");
Erik Klinef4b6e342017-04-25 19:19:59 +090072 stop();
Erik Kline5a7c8a02017-04-30 19:36:15 +090073 return;
74 }
75 }
76
Erik Klinef4b6e342017-04-25 19:19:59 +090077 mControlInitialized = mHwInterface.initOffloadControl(
78 new OffloadHardwareInterface.ControlCallback() {
79 @Override
80 public void onOffloadEvent(int event) {
81 mLog.log("got offload event: " + event);
82 }
83
84 @Override
85 public void onNatTimeoutUpdate(int proto,
86 String srcAddr, int srcPort,
87 String dstAddr, int dstPort) {
88 mLog.log(String.format("NAT timeout update: %s (%s,%s) -> (%s,%s)",
89 proto, srcAddr, srcPort, dstAddr, dstPort));
90 }
91 });
92 if (!mControlInitialized) {
93 mLog.i("tethering offload control not supported");
94 stop();
95 }
Erik Kline7fd696c2017-06-12 18:20:08 +090096 mLog.log("tethering offload started");
Erik Klinee0cce212017-03-06 14:05:23 +090097 }
98
99 public void stop() {
Erik Kline7fd696c2017-06-12 18:20:08 +0900100 final boolean wasStarted = started();
Erik Klinee0cce212017-03-06 14:05:23 +0900101 mUpstreamLinkProperties = null;
Erik Kline5a7c8a02017-04-30 19:36:15 +0900102 mHwInterface.stopOffloadControl();
103 mControlInitialized = false;
104 mConfigInitialized = false;
Erik Kline7fd696c2017-06-12 18:20:08 +0900105 if (wasStarted) mLog.log("tethering offload stopped");
Erik Klinee0cce212017-03-06 14:05:23 +0900106 }
107
108 public void setUpstreamLinkProperties(LinkProperties lp) {
Erik Kline5a7c8a02017-04-30 19:36:15 +0900109 if (!started()) return;
110
Erik Kline7990aef2017-06-01 20:11:25 +0900111 mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
112 // TODO: examine return code and decide what to do if programming
113 // upstream parameters fails (probably just wait for a subsequent
114 // onOffloadEvent() callback to tell us offload is available again and
115 // then reapply all state).
116 pushUpstreamParameters();
Erik Klinee0cce212017-03-06 14:05:23 +0900117 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900118
Erik Kline3a5278f2017-06-24 19:29:10 +0900119 public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
120 if (!started()) return;
121
122 mExemptPrefixes = exemptPrefixes;
123 // TODO:
124 // - add IP addresses from all downstream link properties
125 // - add routes from all non-tethering downstream link properties
126 // - remove any 64share prefixes
127 // - push this to the HAL
128 }
129
Erik Kline6e9a1012017-06-06 19:24:21 +0900130 public void notifyDownstreamLinkProperties(LinkProperties lp) {
131 if (!started()) return;
132
133 // TODO: Cache LinkProperties on a per-ifname basis and compute the
134 // deltas, calling addDownstream()/removeDownstream() accordingly.
135 }
136
137 public void removeDownstreamInterface(String ifname) {
138 if (!started()) return;
139
140 // TODO: Check cache for LinkProperties of ifname and, if present,
141 // call removeDownstream() accordingly.
142 }
Erik Kline5a7c8a02017-04-30 19:36:15 +0900143
Erik Kline92c4db02017-05-31 10:21:32 +0900144 private boolean isOffloadDisabled() {
145 // Defaults to |false| if not present.
146 return (Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0) != 0);
147 }
148
Erik Kline5a7c8a02017-04-30 19:36:15 +0900149 private boolean started() {
150 return mConfigInitialized && mControlInitialized;
151 }
Erik Kline7990aef2017-06-01 20:11:25 +0900152
153 private boolean pushUpstreamParameters() {
154 if (mUpstreamLinkProperties == null) {
155 return mHwInterface.setUpstreamParameters(null, null, null, null);
156 }
157
158 // A stacked interface cannot be an upstream for hardware offload.
159 // Consequently, we examine only the primary interface name, look at
160 // getAddresses() rather than getAllAddresses(), and check getRoutes()
161 // rather than getAllRoutes().
162 final String iface = mUpstreamLinkProperties.getInterfaceName();
163 final ArrayList<String> v6gateways = new ArrayList<>();
164 String v4addr = null;
165 String v4gateway = null;
166
167 for (InetAddress ip : mUpstreamLinkProperties.getAddresses()) {
168 if (ip instanceof Inet4Address) {
169 v4addr = ip.getHostAddress();
170 break;
171 }
172 }
173
174 // Find the gateway addresses of all default routes of either address family.
175 for (RouteInfo ri : mUpstreamLinkProperties.getRoutes()) {
176 if (!ri.hasGateway()) continue;
177
178 final String gateway = ri.getGateway().getHostAddress();
179 if (ri.isIPv4Default()) {
180 v4gateway = gateway;
181 } else if (ri.isIPv6Default()) {
182 v6gateways.add(gateway);
183 }
184 }
185
Erik Kline11854592017-06-15 18:06:34 +0900186 return mHwInterface.setUpstreamParameters(
187 iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
Erik Kline7990aef2017-06-01 20:11:25 +0900188 }
Erik Klinee0cce212017-03-06 14:05:23 +0900189}