blob: 37221a971ad19e34ee96b11dce212e50ba5ba889 [file] [log] [blame]
Christopher Wileyd2896662016-05-19 11:54:54 -07001/*
2 * Copyright (C) 2016 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
19import android.net.ConnectivityManager;
20import android.net.INetworkStatsService;
21import android.net.InterfaceConfiguration;
22import android.net.LinkAddress;
Erik Kline1eb8c692016-07-08 17:21:26 +090023import android.net.LinkProperties;
Christopher Wileyd2896662016-05-19 11:54:54 -070024import android.net.NetworkUtils;
25import android.os.INetworkManagementService;
26import android.os.Looper;
27import android.os.Message;
28import android.util.Log;
29import android.util.SparseArray;
30
Christopher Wileyd2896662016-05-19 11:54:54 -070031import com.android.internal.util.MessageUtils;
32import com.android.internal.util.Protocol;
33import com.android.internal.util.State;
34import com.android.internal.util.StateMachine;
35
36import java.net.InetAddress;
37
38/**
39 * @hide
40 *
41 * Tracks the eligibility of a given network interface for tethering.
42 */
Mitchell Wills7040b4e2016-05-23 16:40:10 -070043public class TetherInterfaceStateMachine extends StateMachine {
Christopher Wileyd2896662016-05-19 11:54:54 -070044 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
45 private static final int USB_PREFIX_LENGTH = 24;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -070046 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
47 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
Christopher Wileyd2896662016-05-19 11:54:54 -070048
49 private final static String TAG = "TetherInterfaceSM";
50 private final static boolean DBG = false;
51 private final static boolean VDBG = false;
52 private static final Class[] messageClasses = {
Mitchell Wills7040b4e2016-05-23 16:40:10 -070053 TetherInterfaceStateMachine.class
Christopher Wileyd2896662016-05-19 11:54:54 -070054 };
55 private static final SparseArray<String> sMagicDecoderRing =
56 MessageUtils.findMessageNames(messageClasses);
57
58 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100;
Christopher Wileyd2896662016-05-19 11:54:54 -070059 // request from the user that it wants to tether
60 public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2;
61 // request from the user that it wants to untether
62 public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3;
63 // notification that this interface is down
64 public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4;
Christopher Wileyd2896662016-05-19 11:54:54 -070065 // notification from the master SM that it had trouble enabling IP Forwarding
66 public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7;
67 // notification from the master SM that it had trouble disabling IP Forwarding
68 public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
69 // notification from the master SM that it had trouble starting tethering
70 public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9;
71 // notification from the master SM that it had trouble stopping tethering
72 public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10;
73 // notification from the master SM that it had trouble setting the DNS forwarders
74 public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11;
75 // the upstream connection has changed
76 public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12;
Erik Kline1eb8c692016-07-08 17:21:26 +090077 // new IPv6 tethering parameters need to be processed
78 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13;
Christopher Wileyd2896662016-05-19 11:54:54 -070079
80 private final State mInitialState;
Christopher Wileyd2896662016-05-19 11:54:54 -070081 private final State mTetheredState;
82 private final State mUnavailableState;
83
84 private final INetworkManagementService mNMService;
85 private final INetworkStatsService mStatsService;
86 private final IControlsTethering mTetherController;
87
Christopher Wileyd2896662016-05-19 11:54:54 -070088 private final String mIfaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -070089 private final int mInterfaceType;
Erik Kline1eb8c692016-07-08 17:21:26 +090090 private final IPv6TetheringInterfaceServices mIPv6TetherSvc;
Christopher Wileyd2896662016-05-19 11:54:54 -070091
Christopher Wileyd2896662016-05-19 11:54:54 -070092 private int mLastError;
93 private String mMyUpstreamIfaceName; // may change over time
94
Christopher Wiley5c0b10a2016-05-31 14:43:08 -070095 public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
Christopher Wileyd2896662016-05-19 11:54:54 -070096 INetworkManagementService nMService, INetworkStatsService statsService,
Lorenzo Colitti14422332016-10-28 17:45:55 +090097 IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
Christopher Wileyd2896662016-05-19 11:54:54 -070098 super(ifaceName, looper);
99 mNMService = nMService;
100 mStatsService = statsService;
101 mTetherController = tetherController;
102 mIfaceName = ifaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700103 mInterfaceType = interfaceType;
Lorenzo Colitti14422332016-10-28 17:45:55 +0900104 mIPv6TetherSvc = ipv6Svc;
Christopher Wileyd985dde2016-05-31 10:44:35 -0700105 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700106
107 mInitialState = new InitialState();
108 addState(mInitialState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700109 mTetheredState = new TetheredState();
110 addState(mTetheredState);
111 mUnavailableState = new UnavailableState();
112 addState(mUnavailableState);
113
114 setInitialState(mInitialState);
115 }
116
Erik Kline1eb8c692016-07-08 17:21:26 +0900117 public int interfaceType() {
118 return mInterfaceType;
119 }
120
Christopher Wileyd2896662016-05-19 11:54:54 -0700121 // configured when we start tethering and unconfig'd on error or conclusion
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700122 private boolean configureIfaceIp(boolean enabled) {
123 if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
124
125 String ipAsString = null;
126 int prefixLen = 0;
127 if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
128 ipAsString = USB_NEAR_IFACE_ADDR;
129 prefixLen = USB_PREFIX_LENGTH;
130 } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
131 ipAsString = WIFI_HOST_IFACE_ADDR;
132 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
133 } else {
134 // Nothing to do, BT does this elsewhere.
135 return true;
136 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700137
138 InterfaceConfiguration ifcg = null;
139 try {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700140 ifcg = mNMService.getInterfaceConfig(mIfaceName);
Christopher Wileyd2896662016-05-19 11:54:54 -0700141 if (ifcg != null) {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700142 InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
143 ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
Christopher Wileyce5d9132016-09-13 12:07:58 -0700144 if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
145 // The WiFi stack has ownership of the interface up/down state.
146 // It is unclear whether the bluetooth or USB stacks will manage their own
147 // state.
148 ifcg.ignoreInterfaceUpDownStatus();
Christopher Wileyd2896662016-05-19 11:54:54 -0700149 } else {
Christopher Wileyce5d9132016-09-13 12:07:58 -0700150 if (enabled) {
151 ifcg.setInterfaceUp();
152 } else {
153 ifcg.setInterfaceDown();
154 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700155 }
156 ifcg.clearFlag("running");
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700157 mNMService.setInterfaceConfig(mIfaceName, ifcg);
Christopher Wileyd2896662016-05-19 11:54:54 -0700158 }
159 } catch (Exception e) {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700160 Log.e(TAG, "Error configuring interface " + mIfaceName, e);
Christopher Wileyd2896662016-05-19 11:54:54 -0700161 return false;
162 }
163
164 return true;
165 }
166
167 private void maybeLogMessage(State state, int what) {
168 if (DBG) {
169 Log.d(TAG, state.getName() + " got " +
170 sMagicDecoderRing.get(what, Integer.toString(what)));
171 }
172 }
173
174 class InitialState extends State {
175 @Override
176 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700177 mTetherController.notifyInterfaceStateChange(
178 mIfaceName, TetherInterfaceStateMachine.this,
179 IControlsTethering.STATE_AVAILABLE, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700180 }
181
182 @Override
183 public boolean processMessage(Message message) {
184 maybeLogMessage(this, message.what);
185 boolean retValue = true;
186 switch (message.what) {
187 case CMD_TETHER_REQUESTED:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700188 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Christopher Wiley3b1d9222016-05-20 16:44:04 -0700189 transitionTo(mTetheredState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700190 break;
191 case CMD_INTERFACE_DOWN:
192 transitionTo(mUnavailableState);
193 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900194 case CMD_IPV6_TETHER_UPDATE:
195 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
196 (LinkProperties) message.obj);
197 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700198 default:
199 retValue = false;
200 break;
201 }
202 return retValue;
203 }
204 }
205
Christopher Wiley3b1d9222016-05-20 16:44:04 -0700206 class TetheredState extends State {
Christopher Wileyd2896662016-05-19 11:54:54 -0700207 @Override
208 public void enter() {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700209 if (!configureIfaceIp(true)) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700210 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700211 transitionTo(mInitialState);
212 return;
Christopher Wileyd2896662016-05-19 11:54:54 -0700213 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700214
Christopher Wileyd2896662016-05-19 11:54:54 -0700215 try {
216 mNMService.tetherInterface(mIfaceName);
217 } catch (Exception e) {
218 Log.e(TAG, "Error Tethering: " + e.toString());
Christopher Wileyd985dde2016-05-31 10:44:35 -0700219 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700220 transitionTo(mInitialState);
221 return;
222 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900223
224 if (!mIPv6TetherSvc.start()) {
225 Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
226 }
227
Christopher Wileyd2896662016-05-19 11:54:54 -0700228 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
Christopher Wileyd985dde2016-05-31 10:44:35 -0700229 mTetherController.notifyInterfaceStateChange(
230 mIfaceName, TetherInterfaceStateMachine.this,
231 IControlsTethering.STATE_TETHERED, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700232 }
233
Christopher Wileye10bfc02016-05-23 16:17:30 -0700234 @Override
235 public void exit() {
Christopher Wileye10bfc02016-05-23 16:17:30 -0700236 // Note that at this point, we're leaving the tethered state. We can fail any
237 // of these operations, but it doesn't really change that we have to try them
238 // all in sequence.
Erik Kline1eb8c692016-07-08 17:21:26 +0900239 mIPv6TetherSvc.stop();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700240 cleanupUpstream();
241
242 try {
243 mNMService.untetherInterface(mIfaceName);
244 } catch (Exception ee) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700245 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
Christopher Wileye10bfc02016-05-23 16:17:30 -0700246 Log.e(TAG, "Failed to untether interface: " + ee.toString());
247 }
248
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700249 configureIfaceIp(false);
Christopher Wileye10bfc02016-05-23 16:17:30 -0700250 }
251
Christopher Wileyd2896662016-05-19 11:54:54 -0700252 private void cleanupUpstream() {
253 if (mMyUpstreamIfaceName != null) {
254 // note that we don't care about errors here.
255 // sometimes interfaces are gone before we get
256 // to remove their rules, which generates errors.
257 // just do the best we can.
258 try {
259 // about to tear down NAT; gather remaining statistics
260 mStatsService.forceUpdate();
261 } catch (Exception e) {
262 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
263 }
264 try {
265 mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
266 } catch (Exception e) {
267 if (VDBG) Log.e(
268 TAG, "Exception in removeInterfaceForward: " + e.toString());
269 }
270 try {
271 mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
272 } catch (Exception e) {
273 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
274 }
275 mMyUpstreamIfaceName = null;
276 }
277 return;
278 }
279
280 @Override
281 public boolean processMessage(Message message) {
282 maybeLogMessage(this, message.what);
283 boolean retValue = true;
Christopher Wileyd2896662016-05-19 11:54:54 -0700284 switch (message.what) {
285 case CMD_TETHER_UNREQUESTED:
Christopher Wileye10bfc02016-05-23 16:17:30 -0700286 transitionTo(mInitialState);
287 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
288 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700289 case CMD_INTERFACE_DOWN:
Christopher Wileye10bfc02016-05-23 16:17:30 -0700290 transitionTo(mUnavailableState);
291 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
Christopher Wileyd2896662016-05-19 11:54:54 -0700292 break;
293 case CMD_TETHER_CONNECTION_CHANGED:
294 String newUpstreamIfaceName = (String)(message.obj);
295 if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
296 (mMyUpstreamIfaceName != null &&
297 mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
298 if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
299 break;
300 }
301 cleanupUpstream();
302 if (newUpstreamIfaceName != null) {
303 try {
304 mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
305 mNMService.startInterfaceForwarding(mIfaceName,
306 newUpstreamIfaceName);
307 } catch (Exception e) {
308 Log.e(TAG, "Exception enabling Nat: " + e.toString());
Christopher Wileyd985dde2016-05-31 10:44:35 -0700309 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700310 transitionTo(mInitialState);
311 return true;
312 }
313 }
314 mMyUpstreamIfaceName = newUpstreamIfaceName;
315 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900316 case CMD_IPV6_TETHER_UPDATE:
317 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
318 (LinkProperties) message.obj);
319 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700320 case CMD_IP_FORWARDING_ENABLE_ERROR:
321 case CMD_IP_FORWARDING_DISABLE_ERROR:
322 case CMD_START_TETHERING_ERROR:
323 case CMD_STOP_TETHERING_ERROR:
324 case CMD_SET_DNS_FORWARDERS_ERROR:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700325 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
326 transitionTo(mInitialState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700327 break;
328 default:
329 retValue = false;
330 break;
331 }
332 return retValue;
333 }
334 }
335
Christopher Wiley9ad83ab2016-05-20 17:51:27 -0700336 /**
337 * This state is terminal for the per interface state machine. At this
338 * point, the master state machine should have removed this interface
339 * specific state machine from its list of possible recipients of
340 * tethering requests. The state machine itself will hang around until
341 * the garbage collector finds it.
342 */
Christopher Wileyd2896662016-05-19 11:54:54 -0700343 class UnavailableState extends State {
344 @Override
345 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700346 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
347 mTetherController.notifyInterfaceStateChange(
348 mIfaceName, TetherInterfaceStateMachine.this,
349 IControlsTethering.STATE_UNAVAILABLE, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700350 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700351 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700352}