blob: 9e7cb939cdf02515799f321b27a86af33f19adb4 [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,
97 IControlsTethering tetherController) {
98 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;
Erik Kline1eb8c692016-07-08 17:21:26 +0900104 mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService);
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 Wileyd2896662016-05-19 11:54:54 -0700144 if (enabled) {
145 ifcg.setInterfaceUp();
146 } else {
147 ifcg.setInterfaceDown();
148 }
149 ifcg.clearFlag("running");
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700150 mNMService.setInterfaceConfig(mIfaceName, ifcg);
Christopher Wileyd2896662016-05-19 11:54:54 -0700151 }
152 } catch (Exception e) {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700153 Log.e(TAG, "Error configuring interface " + mIfaceName, e);
Christopher Wileyd2896662016-05-19 11:54:54 -0700154 return false;
155 }
156
157 return true;
158 }
159
160 private void maybeLogMessage(State state, int what) {
161 if (DBG) {
162 Log.d(TAG, state.getName() + " got " +
163 sMagicDecoderRing.get(what, Integer.toString(what)));
164 }
165 }
166
167 class InitialState extends State {
168 @Override
169 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700170 mTetherController.notifyInterfaceStateChange(
171 mIfaceName, TetherInterfaceStateMachine.this,
172 IControlsTethering.STATE_AVAILABLE, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700173 }
174
175 @Override
176 public boolean processMessage(Message message) {
177 maybeLogMessage(this, message.what);
178 boolean retValue = true;
179 switch (message.what) {
180 case CMD_TETHER_REQUESTED:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700181 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Christopher Wiley3b1d9222016-05-20 16:44:04 -0700182 transitionTo(mTetheredState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700183 break;
184 case CMD_INTERFACE_DOWN:
185 transitionTo(mUnavailableState);
186 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900187 case CMD_IPV6_TETHER_UPDATE:
188 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
189 (LinkProperties) message.obj);
190 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700191 default:
192 retValue = false;
193 break;
194 }
195 return retValue;
196 }
197 }
198
Christopher Wiley3b1d9222016-05-20 16:44:04 -0700199 class TetheredState extends State {
Christopher Wileyd2896662016-05-19 11:54:54 -0700200 @Override
201 public void enter() {
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700202 if (!configureIfaceIp(true)) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700203 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700204 transitionTo(mInitialState);
205 return;
Christopher Wileyd2896662016-05-19 11:54:54 -0700206 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700207
Christopher Wileyd2896662016-05-19 11:54:54 -0700208 try {
209 mNMService.tetherInterface(mIfaceName);
210 } catch (Exception e) {
211 Log.e(TAG, "Error Tethering: " + e.toString());
Christopher Wileyd985dde2016-05-31 10:44:35 -0700212 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700213 transitionTo(mInitialState);
214 return;
215 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900216
217 if (!mIPv6TetherSvc.start()) {
218 Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
219 }
220
Christopher Wileyd2896662016-05-19 11:54:54 -0700221 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
Christopher Wileyd985dde2016-05-31 10:44:35 -0700222 mTetherController.notifyInterfaceStateChange(
223 mIfaceName, TetherInterfaceStateMachine.this,
224 IControlsTethering.STATE_TETHERED, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700225 }
226
Christopher Wileye10bfc02016-05-23 16:17:30 -0700227 @Override
228 public void exit() {
Christopher Wileye10bfc02016-05-23 16:17:30 -0700229 // Note that at this point, we're leaving the tethered state. We can fail any
230 // of these operations, but it doesn't really change that we have to try them
231 // all in sequence.
Erik Kline1eb8c692016-07-08 17:21:26 +0900232 mIPv6TetherSvc.stop();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700233 cleanupUpstream();
234
235 try {
236 mNMService.untetherInterface(mIfaceName);
237 } catch (Exception ee) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700238 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
Christopher Wileye10bfc02016-05-23 16:17:30 -0700239 Log.e(TAG, "Failed to untether interface: " + ee.toString());
240 }
241
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700242 configureIfaceIp(false);
Christopher Wileye10bfc02016-05-23 16:17:30 -0700243 }
244
Christopher Wileyd2896662016-05-19 11:54:54 -0700245 private void cleanupUpstream() {
246 if (mMyUpstreamIfaceName != null) {
247 // note that we don't care about errors here.
248 // sometimes interfaces are gone before we get
249 // to remove their rules, which generates errors.
250 // just do the best we can.
251 try {
252 // about to tear down NAT; gather remaining statistics
253 mStatsService.forceUpdate();
254 } catch (Exception e) {
255 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
256 }
257 try {
258 mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
259 } catch (Exception e) {
260 if (VDBG) Log.e(
261 TAG, "Exception in removeInterfaceForward: " + e.toString());
262 }
263 try {
264 mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
265 } catch (Exception e) {
266 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
267 }
268 mMyUpstreamIfaceName = null;
269 }
270 return;
271 }
272
273 @Override
274 public boolean processMessage(Message message) {
275 maybeLogMessage(this, message.what);
276 boolean retValue = true;
Christopher Wileyd2896662016-05-19 11:54:54 -0700277 switch (message.what) {
278 case CMD_TETHER_UNREQUESTED:
Christopher Wileye10bfc02016-05-23 16:17:30 -0700279 transitionTo(mInitialState);
280 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
281 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700282 case CMD_INTERFACE_DOWN:
Christopher Wileye10bfc02016-05-23 16:17:30 -0700283 transitionTo(mUnavailableState);
284 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
Christopher Wileyd2896662016-05-19 11:54:54 -0700285 break;
286 case CMD_TETHER_CONNECTION_CHANGED:
287 String newUpstreamIfaceName = (String)(message.obj);
288 if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
289 (mMyUpstreamIfaceName != null &&
290 mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
291 if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
292 break;
293 }
294 cleanupUpstream();
295 if (newUpstreamIfaceName != null) {
296 try {
297 mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
298 mNMService.startInterfaceForwarding(mIfaceName,
299 newUpstreamIfaceName);
300 } catch (Exception e) {
301 Log.e(TAG, "Exception enabling Nat: " + e.toString());
Christopher Wileyd985dde2016-05-31 10:44:35 -0700302 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700303 transitionTo(mInitialState);
304 return true;
305 }
306 }
307 mMyUpstreamIfaceName = newUpstreamIfaceName;
308 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900309 case CMD_IPV6_TETHER_UPDATE:
310 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties(
311 (LinkProperties) message.obj);
312 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700313 case CMD_IP_FORWARDING_ENABLE_ERROR:
314 case CMD_IP_FORWARDING_DISABLE_ERROR:
315 case CMD_START_TETHERING_ERROR:
316 case CMD_STOP_TETHERING_ERROR:
317 case CMD_SET_DNS_FORWARDERS_ERROR:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700318 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
319 transitionTo(mInitialState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700320 break;
321 default:
322 retValue = false;
323 break;
324 }
325 return retValue;
326 }
327 }
328
Christopher Wiley9ad83ab2016-05-20 17:51:27 -0700329 /**
330 * This state is terminal for the per interface state machine. At this
331 * point, the master state machine should have removed this interface
332 * specific state machine from its list of possible recipients of
333 * tethering requests. The state machine itself will hang around until
334 * the garbage collector finds it.
335 */
Christopher Wileyd2896662016-05-19 11:54:54 -0700336 class UnavailableState extends State {
337 @Override
338 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700339 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
340 mTetherController.notifyInterfaceStateChange(
341 mIfaceName, TetherInterfaceStateMachine.this,
342 IControlsTethering.STATE_UNAVAILABLE, mLastError);
Christopher Wileyd2896662016-05-19 11:54:54 -0700343 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700344 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700345}