blob: fbee86a84f850bd280ad4d690e59208aa6ce4fce [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
Erik Kline0f27eed2018-05-29 19:24:43 +090019import static android.net.util.NetworkConstants.asByte;
20import static android.net.util.NetworkConstants.FF;
Erik Kline94ae4c92017-06-13 21:32:10 +090021import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
22
Christopher Wileyd2896662016-05-19 11:54:54 -070023import android.net.ConnectivityManager;
Erik Kline94ae4c92017-06-13 21:32:10 +090024import android.net.INetd;
Christopher Wileyd2896662016-05-19 11:54:54 -070025import android.net.INetworkStatsService;
26import android.net.InterfaceConfiguration;
Erik Kline94ae4c92017-06-13 21:32:10 +090027import android.net.IpPrefix;
Christopher Wileyd2896662016-05-19 11:54:54 -070028import android.net.LinkAddress;
Erik Kline1eb8c692016-07-08 17:21:26 +090029import android.net.LinkProperties;
Christopher Wileyd2896662016-05-19 11:54:54 -070030import android.net.NetworkUtils;
Erik Kline94ae4c92017-06-13 21:32:10 +090031import android.net.RouteInfo;
Erik Klined3c0b5e2017-09-03 20:38:29 +090032import android.net.ip.InterfaceController;
Erik Kline94ae4c92017-06-13 21:32:10 +090033import android.net.ip.RouterAdvertisementDaemon;
34import android.net.ip.RouterAdvertisementDaemon.RaParams;
Erik Kline8bd00d52017-12-08 17:47:50 +090035import android.net.util.InterfaceParams;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +090036import android.net.util.InterfaceSet;
Erik Kline7747fd42017-05-12 16:52:48 +090037import android.net.util.SharedLog;
Christopher Wileyd2896662016-05-19 11:54:54 -070038import android.os.INetworkManagementService;
39import android.os.Looper;
40import android.os.Message;
Erik Kline94ae4c92017-06-13 21:32:10 +090041import android.os.RemoteException;
42import android.os.ServiceSpecificException;
Christopher Wileyd2896662016-05-19 11:54:54 -070043import android.util.Log;
Erik Kline94ae4c92017-06-13 21:32:10 +090044import android.util.Slog;
Christopher Wileyd2896662016-05-19 11:54:54 -070045import android.util.SparseArray;
46
Christopher Wileyd2896662016-05-19 11:54:54 -070047import com.android.internal.util.MessageUtils;
48import com.android.internal.util.Protocol;
49import com.android.internal.util.State;
50import com.android.internal.util.StateMachine;
51
Erik Kline94ae4c92017-06-13 21:32:10 +090052import java.net.Inet6Address;
Christopher Wileyd2896662016-05-19 11:54:54 -070053import java.net.InetAddress;
Erik Kline94ae4c92017-06-13 21:32:10 +090054import java.net.UnknownHostException;
55import java.util.ArrayList;
56import java.util.HashSet;
57import java.util.Objects;
58import java.util.Random;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +090059import java.util.Set;
Christopher Wileyd2896662016-05-19 11:54:54 -070060
61/**
Erik Klinedd4d5822017-06-12 18:20:08 +090062 * Provides the interface to IP-layer serving functionality for a given network
63 * interface, e.g. for tethering or "local-only hotspot" mode.
Christopher Wileyd2896662016-05-19 11:54:54 -070064 *
Erik Klinedd4d5822017-06-12 18:20:08 +090065 * @hide
Christopher Wileyd2896662016-05-19 11:54:54 -070066 */
Mitchell Wills7040b4e2016-05-23 16:40:10 -070067public class TetherInterfaceStateMachine extends StateMachine {
Erik Kline94ae4c92017-06-13 21:32:10 +090068 private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
Erik Kline0f27eed2018-05-29 19:24:43 +090069 private static final byte DOUG_ADAMS = (byte) 42;
Erik Kline94ae4c92017-06-13 21:32:10 +090070
Christopher Wileyd2896662016-05-19 11:54:54 -070071 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
72 private static final int USB_PREFIX_LENGTH = 24;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -070073 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
74 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
Christopher Wileyd2896662016-05-19 11:54:54 -070075
76 private final static String TAG = "TetherInterfaceSM";
77 private final static boolean DBG = false;
78 private final static boolean VDBG = false;
79 private static final Class[] messageClasses = {
Mitchell Wills7040b4e2016-05-23 16:40:10 -070080 TetherInterfaceStateMachine.class
Christopher Wileyd2896662016-05-19 11:54:54 -070081 };
82 private static final SparseArray<String> sMagicDecoderRing =
83 MessageUtils.findMessageNames(messageClasses);
84
85 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100;
Christopher Wileyd2896662016-05-19 11:54:54 -070086 // request from the user that it wants to tether
87 public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2;
88 // request from the user that it wants to untether
89 public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3;
90 // notification that this interface is down
91 public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4;
Christopher Wileyd2896662016-05-19 11:54:54 -070092 // notification from the master SM that it had trouble enabling IP Forwarding
93 public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7;
94 // notification from the master SM that it had trouble disabling IP Forwarding
95 public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
96 // notification from the master SM that it had trouble starting tethering
97 public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9;
98 // notification from the master SM that it had trouble stopping tethering
99 public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10;
100 // notification from the master SM that it had trouble setting the DNS forwarders
101 public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11;
102 // the upstream connection has changed
103 public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12;
Erik Kline1eb8c692016-07-08 17:21:26 +0900104 // new IPv6 tethering parameters need to be processed
105 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13;
Christopher Wileyd2896662016-05-19 11:54:54 -0700106
107 private final State mInitialState;
Erik Klineea9cc482017-03-10 19:35:34 +0900108 private final State mLocalHotspotState;
Christopher Wileyd2896662016-05-19 11:54:54 -0700109 private final State mTetheredState;
110 private final State mUnavailableState;
111
Erik Kline7747fd42017-05-12 16:52:48 +0900112 private final SharedLog mLog;
Christopher Wileyd2896662016-05-19 11:54:54 -0700113 private final INetworkManagementService mNMService;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900114 private final INetd mNetd;
Christopher Wileyd2896662016-05-19 11:54:54 -0700115 private final INetworkStatsService mStatsService;
116 private final IControlsTethering mTetherController;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900117 private final InterfaceController mInterfaceCtrl;
Christopher Wileyd2896662016-05-19 11:54:54 -0700118
Christopher Wileyd2896662016-05-19 11:54:54 -0700119 private final String mIfaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700120 private final int mInterfaceType;
Erik Klineab6439b2017-06-06 19:24:21 +0900121 private final LinkProperties mLinkProperties;
Christopher Wileyd2896662016-05-19 11:54:54 -0700122
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900123 private final TetheringDependencies mDeps;
124
Christopher Wileyd2896662016-05-19 11:54:54 -0700125 private int mLastError;
Erik Klineb3bb26e2017-07-06 19:49:35 +0900126 private int mServingMode;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900127 private InterfaceSet mUpstreamIfaceSet; // may change over time
Erik Kline8bd00d52017-12-08 17:47:50 +0900128 private InterfaceParams mInterfaceParams;
Erik Klinedd4d5822017-06-12 18:20:08 +0900129 // TODO: De-duplicate this with mLinkProperties above. Currently, these link
130 // properties are those selected by the IPv6TetheringCoordinator and relayed
131 // to us. By comparison, mLinkProperties contains the addresses and directly
132 // connected routes that have been formed from these properties iff. we have
133 // succeeded in configuring them and are able to announce them within Router
134 // Advertisements (otherwise, we do not add them to mLinkProperties at all).
Erik Kline94ae4c92017-06-13 21:32:10 +0900135 private LinkProperties mLastIPv6LinkProperties;
136 private RouterAdvertisementDaemon mRaDaemon;
137 private RaParams mLastRaParams;
Christopher Wileyd2896662016-05-19 11:54:54 -0700138
Erik Kline7747fd42017-05-12 16:52:48 +0900139 public TetherInterfaceStateMachine(
140 String ifaceName, Looper looper, int interfaceType, SharedLog log,
141 INetworkManagementService nMService, INetworkStatsService statsService,
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900142 IControlsTethering tetherController,
143 TetheringDependencies deps) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700144 super(ifaceName, looper);
Erik Kline7747fd42017-05-12 16:52:48 +0900145 mLog = log.forSubComponent(ifaceName);
Christopher Wileyd2896662016-05-19 11:54:54 -0700146 mNMService = nMService;
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900147 mNetd = deps.getNetdService();
Christopher Wileyd2896662016-05-19 11:54:54 -0700148 mStatsService = statsService;
149 mTetherController = tetherController;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900150 mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
Christopher Wileyd2896662016-05-19 11:54:54 -0700151 mIfaceName = ifaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700152 mInterfaceType = interfaceType;
Erik Klineab6439b2017-06-06 19:24:21 +0900153 mLinkProperties = new LinkProperties();
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900154 mDeps = deps;
Erik Klinedd4d5822017-06-12 18:20:08 +0900155 resetLinkProperties();
Christopher Wileyd985dde2016-05-31 10:44:35 -0700156 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineb3bb26e2017-07-06 19:49:35 +0900157 mServingMode = IControlsTethering.STATE_AVAILABLE;
Christopher Wileyd2896662016-05-19 11:54:54 -0700158
159 mInitialState = new InitialState();
Erik Klineea9cc482017-03-10 19:35:34 +0900160 mLocalHotspotState = new LocalHotspotState();
Christopher Wileyd2896662016-05-19 11:54:54 -0700161 mTetheredState = new TetheredState();
Christopher Wileyd2896662016-05-19 11:54:54 -0700162 mUnavailableState = new UnavailableState();
Erik Klineea9cc482017-03-10 19:35:34 +0900163 addState(mInitialState);
Erik Klinef79a34d2017-04-13 22:54:34 +0900164 addState(mLocalHotspotState);
165 addState(mTetheredState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700166 addState(mUnavailableState);
167
168 setInitialState(mInitialState);
169 }
170
Erik Kline216af6d2017-04-27 20:57:23 +0900171 public String interfaceName() { return mIfaceName; }
172
173 public int interfaceType() { return mInterfaceType; }
174
175 public int lastError() { return mLastError; }
Erik Kline1eb8c692016-07-08 17:21:26 +0900176
Erik Klineb3bb26e2017-07-06 19:49:35 +0900177 public int servingMode() { return mServingMode; }
178
Erik Kline5acb4e32017-07-04 18:28:11 +0900179 public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
180
Erik Klineab6439b2017-06-06 19:24:21 +0900181 public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
182
Erik Kline218c2262017-06-09 16:36:29 +0900183 public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
184
Erik Kline94ae4c92017-06-13 21:32:10 +0900185 /**
186 * Internals.
187 */
188
Erik Klinedd4d5822017-06-12 18:20:08 +0900189 private boolean startIPv4() { return configureIPv4(true); }
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700190
Erik Klinef8bba5b2018-05-18 16:09:24 +0900191 private void stopIPv4() {
192 configureIPv4(false);
193 // NOTE: All of configureIPv4() will be refactored out of existence
194 // into calls to InterfaceController, shared with startIPv4().
195 mInterfaceCtrl.clearIPv4Address();
196 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900197
Erik Klined3c0b5e2017-09-03 20:38:29 +0900198 // TODO: Refactor this in terms of calls to InterfaceController.
Erik Klinedd4d5822017-06-12 18:20:08 +0900199 private boolean configureIPv4(boolean enabled) {
200 if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
201
202 // TODO: Replace this hard-coded information with dynamically selected
203 // config passed down to us by a higher layer IP-coordinating element.
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700204 String ipAsString = null;
205 int prefixLen = 0;
206 if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
207 ipAsString = USB_NEAR_IFACE_ADDR;
208 prefixLen = USB_PREFIX_LENGTH;
209 } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
Erik Kline0f27eed2018-05-29 19:24:43 +0900210 ipAsString = getRandomWifiIPv4Address();
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700211 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
212 } else {
213 // Nothing to do, BT does this elsewhere.
214 return true;
215 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700216
Erik Klinedd4d5822017-06-12 18:20:08 +0900217 final LinkAddress linkAddr;
Christopher Wileyd2896662016-05-19 11:54:54 -0700218 try {
Erik Klinedd4d5822017-06-12 18:20:08 +0900219 final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
220 if (ifcg == null) {
221 mLog.e("Received null interface config");
222 return false;
Christopher Wileyd2896662016-05-19 11:54:54 -0700223 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900224
225 InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
226 linkAddr = new LinkAddress(addr, prefixLen);
227 ifcg.setLinkAddress(linkAddr);
228 if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
229 // The WiFi stack has ownership of the interface up/down state.
230 // It is unclear whether the Bluetooth or USB stacks will manage their own
231 // state.
232 ifcg.ignoreInterfaceUpDownStatus();
233 } else {
234 if (enabled) {
235 ifcg.setInterfaceUp();
236 } else {
237 ifcg.setInterfaceDown();
238 }
239 }
240 ifcg.clearFlag("running");
241 mNMService.setInterfaceConfig(mIfaceName, ifcg);
Christopher Wileyd2896662016-05-19 11:54:54 -0700242 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900243 mLog.e("Error configuring interface " + e);
Christopher Wileyd2896662016-05-19 11:54:54 -0700244 return false;
245 }
246
Erik Klinedd4d5822017-06-12 18:20:08 +0900247 // Directly-connected route.
248 final RouteInfo route = new RouteInfo(linkAddr);
249 if (enabled) {
250 mLinkProperties.addLinkAddress(linkAddr);
251 mLinkProperties.addRoute(route);
252 } else {
253 mLinkProperties.removeLinkAddress(linkAddr);
254 mLinkProperties.removeRoute(route);
255 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700256 return true;
257 }
258
Erik Kline0f27eed2018-05-29 19:24:43 +0900259 private String getRandomWifiIPv4Address() {
260 try {
261 byte[] bytes = NetworkUtils.numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
262 bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
263 return InetAddress.getByAddress(bytes).getHostAddress();
264 } catch (Exception e) {
265 return WIFI_HOST_IFACE_ADDR;
266 }
267 }
268
Erik Kline94ae4c92017-06-13 21:32:10 +0900269 private boolean startIPv6() {
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900270 mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
Erik Kline8bd00d52017-12-08 17:47:50 +0900271 if (mInterfaceParams == null) {
272 mLog.e("Failed to find InterfaceParams");
Erik Kline94ae4c92017-06-13 21:32:10 +0900273 stopIPv6();
274 return false;
275 }
276
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900277 mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
Erik Kline94ae4c92017-06-13 21:32:10 +0900278 if (!mRaDaemon.start()) {
279 stopIPv6();
280 return false;
281 }
282
283 return true;
284 }
285
286 private void stopIPv6() {
Erik Kline8bd00d52017-12-08 17:47:50 +0900287 mInterfaceParams = null;
Erik Kline94ae4c92017-06-13 21:32:10 +0900288 setRaParams(null);
289
290 if (mRaDaemon != null) {
291 mRaDaemon.stop();
292 mRaDaemon = null;
293 }
294 }
295
296 // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
297 // LinkProperties. These have extraneous data filtered out and only the
298 // necessary prefixes included (per its prefix distribution policy).
299 //
300 // TODO: Evaluate using a data structure than is more directly suited to
301 // communicating only the relevant information.
302 private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) {
303 if (mRaDaemon == null) return;
304
305 // Avoid unnecessary work on spurious updates.
306 if (Objects.equals(mLastIPv6LinkProperties, v6only)) {
307 return;
308 }
309
310 RaParams params = null;
311
312 if (v6only != null) {
313 params = new RaParams();
314 params.mtu = v6only.getMtu();
315 params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
316
317 for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
318 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
319
320 final IpPrefix prefix = new IpPrefix(
321 linkAddr.getAddress(), linkAddr.getPrefixLength());
322 params.prefixes.add(prefix);
323
324 final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
325 if (dnsServer != null) {
326 params.dnses.add(dnsServer);
327 }
328 }
329 }
330 // If v6only is null, we pass in null to setRaParams(), which handles
331 // deprecation of any existing RA data.
332
333 setRaParams(params);
334 mLastIPv6LinkProperties = v6only;
335 }
336
Erik Klinedd4d5822017-06-12 18:20:08 +0900337 private void configureLocalIPv6Routes(
Erik Kline94ae4c92017-06-13 21:32:10 +0900338 HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
339 // [1] Remove the routes that are deprecated.
340 if (!deprecatedPrefixes.isEmpty()) {
341 final ArrayList<RouteInfo> toBeRemoved =
342 getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
343 try {
344 final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
345 if (removalFailures > 0) {
346 mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
347 removalFailures));
348 }
349 } catch (RemoteException e) {
350 mLog.e("Failed to remove IPv6 routes from local table: " + e);
351 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900352
353 for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
Erik Kline94ae4c92017-06-13 21:32:10 +0900354 }
355
356 // [2] Add only the routes that have not previously been added.
357 if (newPrefixes != null && !newPrefixes.isEmpty()) {
358 HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone();
359 if (mLastRaParams != null) {
360 addedPrefixes.removeAll(mLastRaParams.prefixes);
361 }
362
363 if (mLastRaParams == null || mLastRaParams.prefixes.isEmpty()) {
364 // We need to be able to send unicast RAs, and clients might
365 // like to ping the default router's link-local address. Note
366 // that we never remove the link-local route from the network
367 // until Tethering disables tethering on the interface. We
368 // only need to add the link-local prefix once, but in the
369 // event we add it more than once netd silently ignores EEXIST.
370 addedPrefixes.add(LINK_LOCAL_PREFIX);
371 }
372
373 if (!addedPrefixes.isEmpty()) {
374 final ArrayList<RouteInfo> toBeAdded =
375 getLocalRoutesFor(mIfaceName, addedPrefixes);
376 try {
377 // It's safe to call addInterfaceToLocalNetwork() even if
378 // the interface is already in the local_network. Note also
379 // that adding routes that already exist does not cause an
380 // error (EEXIST is silently ignored).
381 mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
382 } catch (RemoteException e) {
383 mLog.e("Failed to add IPv6 routes to local table: " + e);
384 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900385
386 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
Erik Kline94ae4c92017-06-13 21:32:10 +0900387 }
388 }
389 }
390
Erik Klinedd4d5822017-06-12 18:20:08 +0900391 private void configureLocalIPv6Dns(
Erik Kline94ae4c92017-06-13 21:32:10 +0900392 HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900393 // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located?
394 if (mNetd == null) {
Erik Kline94ae4c92017-06-13 21:32:10 +0900395 if (newDnses != null) newDnses.clear();
396 mLog.e("No netd service instance available; not setting local IPv6 addresses");
397 return;
398 }
399
400 // [1] Remove deprecated local DNS IP addresses.
401 if (!deprecatedDnses.isEmpty()) {
402 for (Inet6Address dns : deprecatedDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900403 if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) {
404 mLog.e("Failed to remove local dns IP " + dns);
Erik Kline94ae4c92017-06-13 21:32:10 +0900405 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900406
407 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
Erik Kline94ae4c92017-06-13 21:32:10 +0900408 }
409 }
410
411 // [2] Add only the local DNS IP addresses that have not previously been added.
412 if (newDnses != null && !newDnses.isEmpty()) {
413 final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone();
414 if (mLastRaParams != null) {
415 addedDnses.removeAll(mLastRaParams.dnses);
416 }
417
418 for (Inet6Address dns : addedDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900419 if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) {
420 mLog.e("Failed to add local dns IP " + dns);
Erik Kline94ae4c92017-06-13 21:32:10 +0900421 newDnses.remove(dns);
422 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900423
424 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
Erik Kline94ae4c92017-06-13 21:32:10 +0900425 }
426 }
427
428 try {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900429 mNetd.tetherApplyDnsInterfaces();
Erik Kline94ae4c92017-06-13 21:32:10 +0900430 } catch (ServiceSpecificException | RemoteException e) {
431 mLog.e("Failed to update local DNS caching server");
432 if (newDnses != null) newDnses.clear();
433 }
434 }
435
436 private void setRaParams(RaParams newParams) {
437 if (mRaDaemon != null) {
438 final RaParams deprecatedParams =
439 RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
440
Erik Klinedd4d5822017-06-12 18:20:08 +0900441 configureLocalIPv6Routes(deprecatedParams.prefixes,
Erik Kline94ae4c92017-06-13 21:32:10 +0900442 (newParams != null) ? newParams.prefixes : null);
443
Erik Klinedd4d5822017-06-12 18:20:08 +0900444 configureLocalIPv6Dns(deprecatedParams.dnses,
Erik Kline94ae4c92017-06-13 21:32:10 +0900445 (newParams != null) ? newParams.dnses : null);
446
447 mRaDaemon.buildNewRa(deprecatedParams, newParams);
448 }
449
450 mLastRaParams = newParams;
451 }
452
Erik Klineb4df3f42017-07-06 16:40:06 +0900453 private void logMessage(State state, int what) {
454 mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
Christopher Wileyd2896662016-05-19 11:54:54 -0700455 }
456
Erik Klineea9cc482017-03-10 19:35:34 +0900457 private void sendInterfaceState(int newInterfaceState) {
Erik Klineb3bb26e2017-07-06 19:49:35 +0900458 mServingMode = newInterfaceState;
Erik Klineab6439b2017-06-06 19:24:21 +0900459 mTetherController.updateInterfaceState(
460 TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
Erik Klinedd4d5822017-06-12 18:20:08 +0900461 sendLinkProperties();
462 }
463
464 private void sendLinkProperties() {
Erik Klineab6439b2017-06-06 19:24:21 +0900465 mTetherController.updateLinkProperties(
466 TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
Erik Klineea9cc482017-03-10 19:35:34 +0900467 }
468
Erik Klinedd4d5822017-06-12 18:20:08 +0900469 private void resetLinkProperties() {
470 mLinkProperties.clear();
471 mLinkProperties.setInterfaceName(mIfaceName);
472 }
473
Christopher Wileyd2896662016-05-19 11:54:54 -0700474 class InitialState extends State {
475 @Override
476 public void enter() {
Erik Klineea9cc482017-03-10 19:35:34 +0900477 sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
Christopher Wileyd2896662016-05-19 11:54:54 -0700478 }
479
480 @Override
481 public boolean processMessage(Message message) {
Erik Klineb4df3f42017-07-06 16:40:06 +0900482 logMessage(this, message.what);
Christopher Wileyd2896662016-05-19 11:54:54 -0700483 switch (message.what) {
484 case CMD_TETHER_REQUESTED:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700485 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineea9cc482017-03-10 19:35:34 +0900486 switch (message.arg1) {
Erik Klineca41be72017-04-20 22:59:16 +0900487 case IControlsTethering.STATE_LOCAL_ONLY:
Erik Klineea9cc482017-03-10 19:35:34 +0900488 transitionTo(mLocalHotspotState);
489 break;
490 case IControlsTethering.STATE_TETHERED:
491 transitionTo(mTetheredState);
492 break;
493 default:
Erik Kline7747fd42017-05-12 16:52:48 +0900494 mLog.e("Invalid tethering interface serving state specified.");
Erik Klineea9cc482017-03-10 19:35:34 +0900495 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700496 break;
497 case CMD_INTERFACE_DOWN:
498 transitionTo(mUnavailableState);
499 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900500 case CMD_IPV6_TETHER_UPDATE:
Erik Kline94ae4c92017-06-13 21:32:10 +0900501 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
Erik Kline1eb8c692016-07-08 17:21:26 +0900502 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700503 default:
Erik Klineab6439b2017-06-06 19:24:21 +0900504 return NOT_HANDLED;
Christopher Wileyd2896662016-05-19 11:54:54 -0700505 }
Erik Klineab6439b2017-06-06 19:24:21 +0900506 return HANDLED;
Christopher Wileyd2896662016-05-19 11:54:54 -0700507 }
508 }
509
Erik Klinef79a34d2017-04-13 22:54:34 +0900510 class BaseServingState extends State {
Christopher Wileyd2896662016-05-19 11:54:54 -0700511 @Override
512 public void enter() {
Erik Klinedd4d5822017-06-12 18:20:08 +0900513 if (!startIPv4()) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700514 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700515 return;
Christopher Wileyd2896662016-05-19 11:54:54 -0700516 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700517
Christopher Wileyd2896662016-05-19 11:54:54 -0700518 try {
519 mNMService.tetherInterface(mIfaceName);
520 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900521 mLog.e("Error Tethering: " + e);
Christopher Wileyd985dde2016-05-31 10:44:35 -0700522 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700523 return;
524 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900525
Erik Kline94ae4c92017-06-13 21:32:10 +0900526 if (!startIPv6()) {
527 mLog.e("Failed to startIPv6");
Erik Klinef79a34d2017-04-13 22:54:34 +0900528 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
529 return;
Erik Kline1eb8c692016-07-08 17:21:26 +0900530 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700531 }
532
Christopher Wileye10bfc02016-05-23 16:17:30 -0700533 @Override
534 public void exit() {
Christopher Wileye10bfc02016-05-23 16:17:30 -0700535 // Note that at this point, we're leaving the tethered state. We can fail any
536 // of these operations, but it doesn't really change that we have to try them
537 // all in sequence.
Erik Kline94ae4c92017-06-13 21:32:10 +0900538 stopIPv6();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700539
540 try {
541 mNMService.untetherInterface(mIfaceName);
Erik Klinef79a34d2017-04-13 22:54:34 +0900542 } catch (Exception e) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700543 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
Erik Kline7747fd42017-05-12 16:52:48 +0900544 mLog.e("Failed to untether interface: " + e);
Christopher Wileye10bfc02016-05-23 16:17:30 -0700545 }
546
Erik Klinedd4d5822017-06-12 18:20:08 +0900547 stopIPv4();
548
549 resetLinkProperties();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700550 }
551
Erik Klineea9cc482017-03-10 19:35:34 +0900552 @Override
553 public boolean processMessage(Message message) {
Erik Klineb4df3f42017-07-06 16:40:06 +0900554 logMessage(this, message.what);
Erik Klineea9cc482017-03-10 19:35:34 +0900555 switch (message.what) {
556 case CMD_TETHER_UNREQUESTED:
557 transitionTo(mInitialState);
558 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
559 break;
560 case CMD_INTERFACE_DOWN:
561 transitionTo(mUnavailableState);
562 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
563 break;
564 case CMD_IPV6_TETHER_UPDATE:
Erik Kline94ae4c92017-06-13 21:32:10 +0900565 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
Erik Klinedd4d5822017-06-12 18:20:08 +0900566 sendLinkProperties();
Erik Klineea9cc482017-03-10 19:35:34 +0900567 break;
568 case CMD_IP_FORWARDING_ENABLE_ERROR:
569 case CMD_IP_FORWARDING_DISABLE_ERROR:
570 case CMD_START_TETHERING_ERROR:
571 case CMD_STOP_TETHERING_ERROR:
572 case CMD_SET_DNS_FORWARDERS_ERROR:
573 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
574 transitionTo(mInitialState);
575 break;
576 default:
577 return false;
578 }
579 return true;
580 }
581 }
582
Erik Klinef79a34d2017-04-13 22:54:34 +0900583 // Handling errors in BaseServingState.enter() by transitioning is
584 // problematic because transitioning during a multi-state jump yields
585 // a Log.wtf(). Ultimately, there should be only one ServingState,
586 // and forwarding and NAT rules should be handled by a coordinating
587 // functional element outside of TetherInterfaceStateMachine.
588 class LocalHotspotState extends BaseServingState {
Erik Klineea9cc482017-03-10 19:35:34 +0900589 @Override
590 public void enter() {
Erik Klinef79a34d2017-04-13 22:54:34 +0900591 super.enter();
592 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
593 transitionTo(mInitialState);
594 }
595
Erik Klineea9cc482017-03-10 19:35:34 +0900596 if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
Erik Klineca41be72017-04-20 22:59:16 +0900597 sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900598 }
599
600 @Override
601 public boolean processMessage(Message message) {
Erik Klinef79a34d2017-04-13 22:54:34 +0900602 if (super.processMessage(message)) return true;
603
Erik Klineb4df3f42017-07-06 16:40:06 +0900604 logMessage(this, message.what);
Erik Klineea9cc482017-03-10 19:35:34 +0900605 switch (message.what) {
606 case CMD_TETHER_REQUESTED:
Erik Kline7747fd42017-05-12 16:52:48 +0900607 mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
Erik Klineea9cc482017-03-10 19:35:34 +0900608 break;
609 case CMD_TETHER_CONNECTION_CHANGED:
610 // Ignored in local hotspot state.
611 break;
612 default:
613 return false;
614 }
615 return true;
616 }
617 }
618
Erik Klinef79a34d2017-04-13 22:54:34 +0900619 // Handling errors in BaseServingState.enter() by transitioning is
620 // problematic because transitioning during a multi-state jump yields
621 // a Log.wtf(). Ultimately, there should be only one ServingState,
622 // and forwarding and NAT rules should be handled by a coordinating
623 // functional element outside of TetherInterfaceStateMachine.
624 class TetheredState extends BaseServingState {
Erik Klineea9cc482017-03-10 19:35:34 +0900625 @Override
626 public void enter() {
Erik Klinef79a34d2017-04-13 22:54:34 +0900627 super.enter();
628 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
629 transitionTo(mInitialState);
630 }
631
Erik Klineea9cc482017-03-10 19:35:34 +0900632 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
633 sendInterfaceState(IControlsTethering.STATE_TETHERED);
634 }
635
636 @Override
637 public void exit() {
638 cleanupUpstream();
Erik Klinef79a34d2017-04-13 22:54:34 +0900639 super.exit();
Erik Klineea9cc482017-03-10 19:35:34 +0900640 }
641
Christopher Wileyd2896662016-05-19 11:54:54 -0700642 private void cleanupUpstream() {
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900643 if (mUpstreamIfaceSet == null) return;
Erik Kline8ea45482017-02-13 17:28:53 +0900644
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900645 for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
646 mUpstreamIfaceSet = null;
Erik Kline8ea45482017-02-13 17:28:53 +0900647 }
648
649 private void cleanupUpstreamInterface(String upstreamIface) {
650 // Note that we don't care about errors here.
651 // Sometimes interfaces are gone before we get
652 // to remove their rules, which generates errors.
653 // Just do the best we can.
654 try {
655 // About to tear down NAT; gather remaining statistics.
656 mStatsService.forceUpdate();
657 } catch (Exception e) {
658 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
Christopher Wileyd2896662016-05-19 11:54:54 -0700659 }
Erik Kline8ea45482017-02-13 17:28:53 +0900660 try {
661 mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
662 } catch (Exception e) {
663 if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
664 }
665 try {
666 mNMService.disableNat(mIfaceName, upstreamIface);
667 } catch (Exception e) {
668 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
669 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700670 }
671
672 @Override
673 public boolean processMessage(Message message) {
Erik Klinef79a34d2017-04-13 22:54:34 +0900674 if (super.processMessage(message)) return true;
675
Erik Klineb4df3f42017-07-06 16:40:06 +0900676 logMessage(this, message.what);
Christopher Wileyd2896662016-05-19 11:54:54 -0700677 switch (message.what) {
Erik Klineea9cc482017-03-10 19:35:34 +0900678 case CMD_TETHER_REQUESTED:
Erik Kline7747fd42017-05-12 16:52:48 +0900679 mLog.e("CMD_TETHER_REQUESTED while already tethering.");
Christopher Wileyd2896662016-05-19 11:54:54 -0700680 break;
681 case CMD_TETHER_CONNECTION_CHANGED:
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900682 final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
683 if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700684 if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
685 break;
686 }
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900687
688 if (newUpstreamIfaceSet == null) {
689 cleanupUpstream();
690 break;
691 }
692
693 for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
694 cleanupUpstreamInterface(removed);
695 }
696
697 final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet);
698 // This makes the call to cleanupUpstream() in the error
699 // path for any interface neatly cleanup all the interfaces.
700 mUpstreamIfaceSet = newUpstreamIfaceSet;
701
702 for (String ifname : added) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700703 try {
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900704 mNMService.enableNat(mIfaceName, ifname);
705 mNMService.startInterfaceForwarding(mIfaceName, ifname);
Christopher Wileyd2896662016-05-19 11:54:54 -0700706 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900707 mLog.e("Exception enabling NAT: " + e);
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900708 cleanupUpstream();
Christopher Wileyd985dde2016-05-31 10:44:35 -0700709 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700710 transitionTo(mInitialState);
711 return true;
712 }
713 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700714 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700715 default:
Erik Klinedd4d5822017-06-12 18:20:08 +0900716 return false;
Christopher Wileyd2896662016-05-19 11:54:54 -0700717 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900718 return true;
Christopher Wileyd2896662016-05-19 11:54:54 -0700719 }
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900720
721 private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
722 if (mUpstreamIfaceSet == null && newIfaces == null) return true;
723 if (mUpstreamIfaceSet != null && newIfaces != null) {
724 return mUpstreamIfaceSet.equals(newIfaces);
725 }
726 return false;
727 }
728
729 private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
730 if (mUpstreamIfaceSet == null) return new HashSet<>();
731
732 final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
733 removed.removeAll(newIfaces.ifnames);
734 return removed;
735 }
736
737 private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
738 final HashSet<String> added = new HashSet<>(newIfaces.ifnames);
739 if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
740 return added;
741 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700742 }
743
Christopher Wiley9ad83ab2016-05-20 17:51:27 -0700744 /**
745 * This state is terminal for the per interface state machine. At this
746 * point, the master state machine should have removed this interface
747 * specific state machine from its list of possible recipients of
748 * tethering requests. The state machine itself will hang around until
749 * the garbage collector finds it.
750 */
Christopher Wileyd2896662016-05-19 11:54:54 -0700751 class UnavailableState extends State {
752 @Override
753 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700754 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineea9cc482017-03-10 19:35:34 +0900755 sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
Christopher Wileyd2896662016-05-19 11:54:54 -0700756 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700757 }
Erik Kline94ae4c92017-06-13 21:32:10 +0900758
759 // Accumulate routes representing "prefixes to be assigned to the local
760 // interface", for subsequent modification of local_network routing.
761 private static ArrayList<RouteInfo> getLocalRoutesFor(
762 String ifname, HashSet<IpPrefix> prefixes) {
763 final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>();
764 for (IpPrefix ipp : prefixes) {
765 localRoutes.add(new RouteInfo(ipp, null, ifname));
766 }
767 return localRoutes;
768 }
769
770 // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
771 private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
772 final byte[] dnsBytes = localPrefix.getRawAddress();
Erik Kline0f27eed2018-05-29 19:24:43 +0900773 dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
Erik Kline94ae4c92017-06-13 21:32:10 +0900774 try {
775 return Inet6Address.getByAddress(null, dnsBytes, 0);
776 } catch (UnknownHostException e) {
777 Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix);
778 return null;
779 }
780 }
781
Erik Kline0f27eed2018-05-29 19:24:43 +0900782 private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
Erik Kline94ae4c92017-06-13 21:32:10 +0900783 final byte random = (byte) (new Random()).nextInt();
Erik Kline0f27eed2018-05-29 19:24:43 +0900784 for (int value : excluded) {
785 if (random == value) return dflt;
786 }
787 return random;
Erik Kline94ae4c92017-06-13 21:32:10 +0900788 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700789}