blob: 5accb452d10a8f5edefdfc5939cd69e0bf9abc3d [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
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +090019import static android.net.NetworkUtils.numericToInetAddress;
Erik Kline0f27eed2018-05-29 19:24:43 +090020import static android.net.util.NetworkConstants.asByte;
21import static android.net.util.NetworkConstants.FF;
Erik Kline94ae4c92017-06-13 21:32:10 +090022import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
23
Christopher Wileyd2896662016-05-19 11:54:54 -070024import android.net.ConnectivityManager;
Erik Kline94ae4c92017-06-13 21:32:10 +090025import android.net.INetd;
Christopher Wileyd2896662016-05-19 11:54:54 -070026import android.net.INetworkStatsService;
27import android.net.InterfaceConfiguration;
Erik Kline94ae4c92017-06-13 21:32:10 +090028import android.net.IpPrefix;
Christopher Wileyd2896662016-05-19 11:54:54 -070029import android.net.LinkAddress;
Erik Kline1eb8c692016-07-08 17:21:26 +090030import android.net.LinkProperties;
Erik Kline94ae4c92017-06-13 21:32:10 +090031import android.net.RouteInfo;
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +090032import android.net.dhcp.DhcpServer;
33import android.net.dhcp.DhcpServingParams;
Erik Klined3c0b5e2017-09-03 20:38:29 +090034import android.net.ip.InterfaceController;
Erik Kline94ae4c92017-06-13 21:32:10 +090035import android.net.ip.RouterAdvertisementDaemon;
36import android.net.ip.RouterAdvertisementDaemon.RaParams;
Erik Kline8bd00d52017-12-08 17:47:50 +090037import android.net.util.InterfaceParams;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +090038import android.net.util.InterfaceSet;
Erik Kline7747fd42017-05-12 16:52:48 +090039import android.net.util.SharedLog;
Christopher Wileyd2896662016-05-19 11:54:54 -070040import android.os.INetworkManagementService;
41import android.os.Looper;
42import android.os.Message;
Erik Kline94ae4c92017-06-13 21:32:10 +090043import android.os.RemoteException;
44import android.os.ServiceSpecificException;
Christopher Wileyd2896662016-05-19 11:54:54 -070045import android.util.Log;
Erik Kline94ae4c92017-06-13 21:32:10 +090046import android.util.Slog;
Christopher Wileyd2896662016-05-19 11:54:54 -070047import android.util.SparseArray;
48
Christopher Wileyd2896662016-05-19 11:54:54 -070049import com.android.internal.util.MessageUtils;
50import com.android.internal.util.Protocol;
51import com.android.internal.util.State;
52import com.android.internal.util.StateMachine;
53
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +090054import java.net.Inet4Address;
Erik Kline94ae4c92017-06-13 21:32:10 +090055import java.net.Inet6Address;
Christopher Wileyd2896662016-05-19 11:54:54 -070056import java.net.InetAddress;
Erik Kline94ae4c92017-06-13 21:32:10 +090057import java.net.UnknownHostException;
58import java.util.ArrayList;
59import java.util.HashSet;
60import java.util.Objects;
61import java.util.Random;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +090062import java.util.Set;
Christopher Wileyd2896662016-05-19 11:54:54 -070063
64/**
Erik Klinedd4d5822017-06-12 18:20:08 +090065 * Provides the interface to IP-layer serving functionality for a given network
66 * interface, e.g. for tethering or "local-only hotspot" mode.
Christopher Wileyd2896662016-05-19 11:54:54 -070067 *
Erik Klinedd4d5822017-06-12 18:20:08 +090068 * @hide
Christopher Wileyd2896662016-05-19 11:54:54 -070069 */
Mitchell Wills7040b4e2016-05-23 16:40:10 -070070public class TetherInterfaceStateMachine extends StateMachine {
Erik Kline94ae4c92017-06-13 21:32:10 +090071 private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
Erik Kline0f27eed2018-05-29 19:24:43 +090072 private static final byte DOUG_ADAMS = (byte) 42;
Erik Kline94ae4c92017-06-13 21:32:10 +090073
Christopher Wileyd2896662016-05-19 11:54:54 -070074 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
75 private static final int USB_PREFIX_LENGTH = 24;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -070076 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
77 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
Christopher Wileyd2896662016-05-19 11:54:54 -070078
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +090079 // TODO: have PanService use some visible version of this constant
80 private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
81 private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
82
83 // TODO: have this configurable
84 private static final int DHCP_LEASE_TIME_SECS = 3600;
85
Christopher Wileyd2896662016-05-19 11:54:54 -070086 private final static String TAG = "TetherInterfaceSM";
87 private final static boolean DBG = false;
88 private final static boolean VDBG = false;
89 private static final Class[] messageClasses = {
Mitchell Wills7040b4e2016-05-23 16:40:10 -070090 TetherInterfaceStateMachine.class
Christopher Wileyd2896662016-05-19 11:54:54 -070091 };
92 private static final SparseArray<String> sMagicDecoderRing =
93 MessageUtils.findMessageNames(messageClasses);
94
95 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100;
Christopher Wileyd2896662016-05-19 11:54:54 -070096 // request from the user that it wants to tether
97 public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2;
98 // request from the user that it wants to untether
99 public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3;
100 // notification that this interface is down
101 public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4;
Christopher Wileyd2896662016-05-19 11:54:54 -0700102 // notification from the master SM that it had trouble enabling IP Forwarding
103 public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7;
104 // notification from the master SM that it had trouble disabling IP Forwarding
105 public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
106 // notification from the master SM that it had trouble starting tethering
107 public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9;
108 // notification from the master SM that it had trouble stopping tethering
109 public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10;
110 // notification from the master SM that it had trouble setting the DNS forwarders
111 public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11;
112 // the upstream connection has changed
113 public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12;
Erik Kline1eb8c692016-07-08 17:21:26 +0900114 // new IPv6 tethering parameters need to be processed
115 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13;
Christopher Wileyd2896662016-05-19 11:54:54 -0700116
117 private final State mInitialState;
Erik Klineea9cc482017-03-10 19:35:34 +0900118 private final State mLocalHotspotState;
Christopher Wileyd2896662016-05-19 11:54:54 -0700119 private final State mTetheredState;
120 private final State mUnavailableState;
121
Erik Kline7747fd42017-05-12 16:52:48 +0900122 private final SharedLog mLog;
Christopher Wileyd2896662016-05-19 11:54:54 -0700123 private final INetworkManagementService mNMService;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900124 private final INetd mNetd;
Christopher Wileyd2896662016-05-19 11:54:54 -0700125 private final INetworkStatsService mStatsService;
126 private final IControlsTethering mTetherController;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900127 private final InterfaceController mInterfaceCtrl;
Christopher Wileyd2896662016-05-19 11:54:54 -0700128
Christopher Wileyd2896662016-05-19 11:54:54 -0700129 private final String mIfaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700130 private final int mInterfaceType;
Erik Klineab6439b2017-06-06 19:24:21 +0900131 private final LinkProperties mLinkProperties;
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900132 private final boolean mUsingLegacyDhcp;
Christopher Wileyd2896662016-05-19 11:54:54 -0700133
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900134 private final TetheringDependencies mDeps;
135
Christopher Wileyd2896662016-05-19 11:54:54 -0700136 private int mLastError;
Erik Klineb3bb26e2017-07-06 19:49:35 +0900137 private int mServingMode;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900138 private InterfaceSet mUpstreamIfaceSet; // may change over time
Erik Kline8bd00d52017-12-08 17:47:50 +0900139 private InterfaceParams mInterfaceParams;
Erik Klinedd4d5822017-06-12 18:20:08 +0900140 // TODO: De-duplicate this with mLinkProperties above. Currently, these link
141 // properties are those selected by the IPv6TetheringCoordinator and relayed
142 // to us. By comparison, mLinkProperties contains the addresses and directly
143 // connected routes that have been formed from these properties iff. we have
144 // succeeded in configuring them and are able to announce them within Router
145 // Advertisements (otherwise, we do not add them to mLinkProperties at all).
Erik Kline94ae4c92017-06-13 21:32:10 +0900146 private LinkProperties mLastIPv6LinkProperties;
147 private RouterAdvertisementDaemon mRaDaemon;
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900148 private DhcpServer mDhcpServer;
Erik Kline94ae4c92017-06-13 21:32:10 +0900149 private RaParams mLastRaParams;
Christopher Wileyd2896662016-05-19 11:54:54 -0700150
Erik Kline7747fd42017-05-12 16:52:48 +0900151 public TetherInterfaceStateMachine(
152 String ifaceName, Looper looper, int interfaceType, SharedLog log,
153 INetworkManagementService nMService, INetworkStatsService statsService,
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900154 IControlsTethering tetherController, boolean usingLegacyDhcp,
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900155 TetheringDependencies deps) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700156 super(ifaceName, looper);
Erik Kline7747fd42017-05-12 16:52:48 +0900157 mLog = log.forSubComponent(ifaceName);
Christopher Wileyd2896662016-05-19 11:54:54 -0700158 mNMService = nMService;
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900159 mNetd = deps.getNetdService();
Christopher Wileyd2896662016-05-19 11:54:54 -0700160 mStatsService = statsService;
161 mTetherController = tetherController;
Erik Klined3c0b5e2017-09-03 20:38:29 +0900162 mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
Christopher Wileyd2896662016-05-19 11:54:54 -0700163 mIfaceName = ifaceName;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700164 mInterfaceType = interfaceType;
Erik Klineab6439b2017-06-06 19:24:21 +0900165 mLinkProperties = new LinkProperties();
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900166 mUsingLegacyDhcp = usingLegacyDhcp;
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900167 mDeps = deps;
Erik Klinedd4d5822017-06-12 18:20:08 +0900168 resetLinkProperties();
Christopher Wileyd985dde2016-05-31 10:44:35 -0700169 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineb3bb26e2017-07-06 19:49:35 +0900170 mServingMode = IControlsTethering.STATE_AVAILABLE;
Christopher Wileyd2896662016-05-19 11:54:54 -0700171
172 mInitialState = new InitialState();
Erik Klineea9cc482017-03-10 19:35:34 +0900173 mLocalHotspotState = new LocalHotspotState();
Christopher Wileyd2896662016-05-19 11:54:54 -0700174 mTetheredState = new TetheredState();
Christopher Wileyd2896662016-05-19 11:54:54 -0700175 mUnavailableState = new UnavailableState();
Erik Klineea9cc482017-03-10 19:35:34 +0900176 addState(mInitialState);
Erik Klinef79a34d2017-04-13 22:54:34 +0900177 addState(mLocalHotspotState);
178 addState(mTetheredState);
Christopher Wileyd2896662016-05-19 11:54:54 -0700179 addState(mUnavailableState);
180
181 setInitialState(mInitialState);
182 }
183
Erik Kline216af6d2017-04-27 20:57:23 +0900184 public String interfaceName() { return mIfaceName; }
185
186 public int interfaceType() { return mInterfaceType; }
187
188 public int lastError() { return mLastError; }
Erik Kline1eb8c692016-07-08 17:21:26 +0900189
Erik Klineb3bb26e2017-07-06 19:49:35 +0900190 public int servingMode() { return mServingMode; }
191
Erik Kline5acb4e32017-07-04 18:28:11 +0900192 public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
193
Erik Klineab6439b2017-06-06 19:24:21 +0900194 public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
195
Erik Kline218c2262017-06-09 16:36:29 +0900196 public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
197
Erik Kline94ae4c92017-06-13 21:32:10 +0900198 /**
199 * Internals.
200 */
201
Erik Klinedd4d5822017-06-12 18:20:08 +0900202 private boolean startIPv4() { return configureIPv4(true); }
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700203
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900204 private boolean startDhcp(Inet4Address addr, int prefixLen) {
205 if (mUsingLegacyDhcp) {
206 return true;
207 }
208
209 final InterfaceParams ifaceParams = mDeps.getInterfaceParams(mIfaceName);
210 if (ifaceParams == null) {
211 Log.e(TAG, "Failed to find interface params for DHCPv4");
212 return false;
213 }
214 final DhcpServingParams params;
215 try {
216 params = new DhcpServingParams.Builder()
217 .setDefaultRouters(addr)
218 .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
219 .setDnsServers(addr)
220 .setServerAddr(new LinkAddress(addr, prefixLen))
Remi NGUYEN VAN6557a242018-07-13 17:42:39 +0900221 .setMetered(true)
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900222 .build();
223 // TODO: also advertise link MTU
224 } catch (DhcpServingParams.InvalidParameterException e) {
225 Log.e(TAG, "Invalid DHCP parameters", e);
226 return false;
227 }
228
229 mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), ifaceParams, params,
230 mLog.forSubComponent("DHCP"));
231 mDhcpServer.start();
232 return true;
233 }
234
235 private void stopDhcp() {
236 if (mDhcpServer != null) {
237 mDhcpServer.stop();
238 mDhcpServer = null;
239 }
240 }
241
242 private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) {
243 if (enable) {
244 return startDhcp(addr, prefixLen);
245 } else {
246 stopDhcp();
247 return true;
248 }
249 }
250
Erik Klinef8bba5b2018-05-18 16:09:24 +0900251 private void stopIPv4() {
252 configureIPv4(false);
253 // NOTE: All of configureIPv4() will be refactored out of existence
254 // into calls to InterfaceController, shared with startIPv4().
255 mInterfaceCtrl.clearIPv4Address();
256 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900257
Erik Klined3c0b5e2017-09-03 20:38:29 +0900258 // TODO: Refactor this in terms of calls to InterfaceController.
Erik Klinedd4d5822017-06-12 18:20:08 +0900259 private boolean configureIPv4(boolean enabled) {
260 if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
261
262 // TODO: Replace this hard-coded information with dynamically selected
263 // config passed down to us by a higher layer IP-coordinating element.
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700264 String ipAsString = null;
265 int prefixLen = 0;
266 if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
267 ipAsString = USB_NEAR_IFACE_ADDR;
268 prefixLen = USB_PREFIX_LENGTH;
269 } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
Erik Kline0f27eed2018-05-29 19:24:43 +0900270 ipAsString = getRandomWifiIPv4Address();
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700271 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
272 } else {
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900273 // BT configures the interface elsewhere: only start DHCP.
274 final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
275 return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700276 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700277
Erik Klinedd4d5822017-06-12 18:20:08 +0900278 final LinkAddress linkAddr;
Christopher Wileyd2896662016-05-19 11:54:54 -0700279 try {
Erik Klinedd4d5822017-06-12 18:20:08 +0900280 final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
281 if (ifcg == null) {
282 mLog.e("Received null interface config");
283 return false;
Christopher Wileyd2896662016-05-19 11:54:54 -0700284 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900285
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900286 InetAddress addr = numericToInetAddress(ipAsString);
Erik Klinedd4d5822017-06-12 18:20:08 +0900287 linkAddr = new LinkAddress(addr, prefixLen);
288 ifcg.setLinkAddress(linkAddr);
289 if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
290 // The WiFi stack has ownership of the interface up/down state.
291 // It is unclear whether the Bluetooth or USB stacks will manage their own
292 // state.
293 ifcg.ignoreInterfaceUpDownStatus();
294 } else {
295 if (enabled) {
296 ifcg.setInterfaceUp();
297 } else {
298 ifcg.setInterfaceDown();
299 }
300 }
301 ifcg.clearFlag("running");
302 mNMService.setInterfaceConfig(mIfaceName, ifcg);
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900303
304 if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
305 return false;
306 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700307 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900308 mLog.e("Error configuring interface " + e);
Christopher Wileyd2896662016-05-19 11:54:54 -0700309 return false;
310 }
311
Erik Klinedd4d5822017-06-12 18:20:08 +0900312 // Directly-connected route.
313 final RouteInfo route = new RouteInfo(linkAddr);
314 if (enabled) {
315 mLinkProperties.addLinkAddress(linkAddr);
316 mLinkProperties.addRoute(route);
317 } else {
318 mLinkProperties.removeLinkAddress(linkAddr);
319 mLinkProperties.removeRoute(route);
320 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700321 return true;
322 }
323
Erik Kline0f27eed2018-05-29 19:24:43 +0900324 private String getRandomWifiIPv4Address() {
325 try {
Remi NGUYEN VANe3bb5c52018-06-12 15:57:04 +0900326 byte[] bytes = numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
Erik Kline0f27eed2018-05-29 19:24:43 +0900327 bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
328 return InetAddress.getByAddress(bytes).getHostAddress();
329 } catch (Exception e) {
330 return WIFI_HOST_IFACE_ADDR;
331 }
332 }
333
Erik Kline94ae4c92017-06-13 21:32:10 +0900334 private boolean startIPv6() {
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900335 mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
Erik Kline8bd00d52017-12-08 17:47:50 +0900336 if (mInterfaceParams == null) {
337 mLog.e("Failed to find InterfaceParams");
Erik Kline94ae4c92017-06-13 21:32:10 +0900338 stopIPv6();
339 return false;
340 }
341
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900342 mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
Erik Kline94ae4c92017-06-13 21:32:10 +0900343 if (!mRaDaemon.start()) {
344 stopIPv6();
345 return false;
346 }
347
348 return true;
349 }
350
351 private void stopIPv6() {
Erik Kline8bd00d52017-12-08 17:47:50 +0900352 mInterfaceParams = null;
Erik Kline94ae4c92017-06-13 21:32:10 +0900353 setRaParams(null);
354
355 if (mRaDaemon != null) {
356 mRaDaemon.stop();
357 mRaDaemon = null;
358 }
359 }
360
361 // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
362 // LinkProperties. These have extraneous data filtered out and only the
363 // necessary prefixes included (per its prefix distribution policy).
364 //
365 // TODO: Evaluate using a data structure than is more directly suited to
366 // communicating only the relevant information.
367 private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) {
368 if (mRaDaemon == null) return;
369
370 // Avoid unnecessary work on spurious updates.
371 if (Objects.equals(mLastIPv6LinkProperties, v6only)) {
372 return;
373 }
374
375 RaParams params = null;
376
377 if (v6only != null) {
378 params = new RaParams();
379 params.mtu = v6only.getMtu();
380 params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
381
382 for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
383 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
384
385 final IpPrefix prefix = new IpPrefix(
386 linkAddr.getAddress(), linkAddr.getPrefixLength());
387 params.prefixes.add(prefix);
388
389 final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
390 if (dnsServer != null) {
391 params.dnses.add(dnsServer);
392 }
393 }
394 }
395 // If v6only is null, we pass in null to setRaParams(), which handles
396 // deprecation of any existing RA data.
397
398 setRaParams(params);
399 mLastIPv6LinkProperties = v6only;
400 }
401
Erik Klinedd4d5822017-06-12 18:20:08 +0900402 private void configureLocalIPv6Routes(
Erik Kline94ae4c92017-06-13 21:32:10 +0900403 HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
404 // [1] Remove the routes that are deprecated.
405 if (!deprecatedPrefixes.isEmpty()) {
406 final ArrayList<RouteInfo> toBeRemoved =
407 getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
408 try {
409 final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
410 if (removalFailures > 0) {
411 mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
412 removalFailures));
413 }
414 } catch (RemoteException e) {
415 mLog.e("Failed to remove IPv6 routes from local table: " + e);
416 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900417
418 for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
Erik Kline94ae4c92017-06-13 21:32:10 +0900419 }
420
421 // [2] Add only the routes that have not previously been added.
422 if (newPrefixes != null && !newPrefixes.isEmpty()) {
423 HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone();
424 if (mLastRaParams != null) {
425 addedPrefixes.removeAll(mLastRaParams.prefixes);
426 }
427
428 if (mLastRaParams == null || mLastRaParams.prefixes.isEmpty()) {
429 // We need to be able to send unicast RAs, and clients might
430 // like to ping the default router's link-local address. Note
431 // that we never remove the link-local route from the network
432 // until Tethering disables tethering on the interface. We
433 // only need to add the link-local prefix once, but in the
434 // event we add it more than once netd silently ignores EEXIST.
435 addedPrefixes.add(LINK_LOCAL_PREFIX);
436 }
437
438 if (!addedPrefixes.isEmpty()) {
439 final ArrayList<RouteInfo> toBeAdded =
440 getLocalRoutesFor(mIfaceName, addedPrefixes);
441 try {
442 // It's safe to call addInterfaceToLocalNetwork() even if
443 // the interface is already in the local_network. Note also
444 // that adding routes that already exist does not cause an
445 // error (EEXIST is silently ignored).
446 mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
Sehee Parka1874cc2018-06-19 20:07:37 +0900447 } catch (Exception e) {
Erik Kline94ae4c92017-06-13 21:32:10 +0900448 mLog.e("Failed to add IPv6 routes to local table: " + e);
449 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900450
451 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
Erik Kline94ae4c92017-06-13 21:32:10 +0900452 }
453 }
454 }
455
Erik Klinedd4d5822017-06-12 18:20:08 +0900456 private void configureLocalIPv6Dns(
Erik Kline94ae4c92017-06-13 21:32:10 +0900457 HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900458 // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located?
459 if (mNetd == null) {
Erik Kline94ae4c92017-06-13 21:32:10 +0900460 if (newDnses != null) newDnses.clear();
461 mLog.e("No netd service instance available; not setting local IPv6 addresses");
462 return;
463 }
464
465 // [1] Remove deprecated local DNS IP addresses.
466 if (!deprecatedDnses.isEmpty()) {
467 for (Inet6Address dns : deprecatedDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900468 if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) {
469 mLog.e("Failed to remove local dns IP " + dns);
Erik Kline94ae4c92017-06-13 21:32:10 +0900470 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900471
472 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
Erik Kline94ae4c92017-06-13 21:32:10 +0900473 }
474 }
475
476 // [2] Add only the local DNS IP addresses that have not previously been added.
477 if (newDnses != null && !newDnses.isEmpty()) {
478 final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone();
479 if (mLastRaParams != null) {
480 addedDnses.removeAll(mLastRaParams.dnses);
481 }
482
483 for (Inet6Address dns : addedDnses) {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900484 if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) {
485 mLog.e("Failed to add local dns IP " + dns);
Erik Kline94ae4c92017-06-13 21:32:10 +0900486 newDnses.remove(dns);
487 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900488
489 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
Erik Kline94ae4c92017-06-13 21:32:10 +0900490 }
491 }
492
493 try {
Erik Klined3c0b5e2017-09-03 20:38:29 +0900494 mNetd.tetherApplyDnsInterfaces();
Erik Kline94ae4c92017-06-13 21:32:10 +0900495 } catch (ServiceSpecificException | RemoteException e) {
496 mLog.e("Failed to update local DNS caching server");
497 if (newDnses != null) newDnses.clear();
498 }
499 }
500
501 private void setRaParams(RaParams newParams) {
502 if (mRaDaemon != null) {
503 final RaParams deprecatedParams =
504 RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
505
Erik Klinedd4d5822017-06-12 18:20:08 +0900506 configureLocalIPv6Routes(deprecatedParams.prefixes,
Erik Kline94ae4c92017-06-13 21:32:10 +0900507 (newParams != null) ? newParams.prefixes : null);
508
Erik Klinedd4d5822017-06-12 18:20:08 +0900509 configureLocalIPv6Dns(deprecatedParams.dnses,
Erik Kline94ae4c92017-06-13 21:32:10 +0900510 (newParams != null) ? newParams.dnses : null);
511
512 mRaDaemon.buildNewRa(deprecatedParams, newParams);
513 }
514
515 mLastRaParams = newParams;
516 }
517
Erik Klineb4df3f42017-07-06 16:40:06 +0900518 private void logMessage(State state, int what) {
519 mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
Christopher Wileyd2896662016-05-19 11:54:54 -0700520 }
521
Erik Klineea9cc482017-03-10 19:35:34 +0900522 private void sendInterfaceState(int newInterfaceState) {
Erik Klineb3bb26e2017-07-06 19:49:35 +0900523 mServingMode = newInterfaceState;
Erik Klineab6439b2017-06-06 19:24:21 +0900524 mTetherController.updateInterfaceState(
525 TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
Erik Klinedd4d5822017-06-12 18:20:08 +0900526 sendLinkProperties();
527 }
528
529 private void sendLinkProperties() {
Erik Klineab6439b2017-06-06 19:24:21 +0900530 mTetherController.updateLinkProperties(
531 TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
Erik Klineea9cc482017-03-10 19:35:34 +0900532 }
533
Erik Klinedd4d5822017-06-12 18:20:08 +0900534 private void resetLinkProperties() {
535 mLinkProperties.clear();
536 mLinkProperties.setInterfaceName(mIfaceName);
537 }
538
Christopher Wileyd2896662016-05-19 11:54:54 -0700539 class InitialState extends State {
540 @Override
541 public void enter() {
Erik Klineea9cc482017-03-10 19:35:34 +0900542 sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
Christopher Wileyd2896662016-05-19 11:54:54 -0700543 }
544
545 @Override
546 public boolean processMessage(Message message) {
Erik Klineb4df3f42017-07-06 16:40:06 +0900547 logMessage(this, message.what);
Christopher Wileyd2896662016-05-19 11:54:54 -0700548 switch (message.what) {
549 case CMD_TETHER_REQUESTED:
Christopher Wileyd985dde2016-05-31 10:44:35 -0700550 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineea9cc482017-03-10 19:35:34 +0900551 switch (message.arg1) {
Erik Klineca41be72017-04-20 22:59:16 +0900552 case IControlsTethering.STATE_LOCAL_ONLY:
Erik Klineea9cc482017-03-10 19:35:34 +0900553 transitionTo(mLocalHotspotState);
554 break;
555 case IControlsTethering.STATE_TETHERED:
556 transitionTo(mTetheredState);
557 break;
558 default:
Erik Kline7747fd42017-05-12 16:52:48 +0900559 mLog.e("Invalid tethering interface serving state specified.");
Erik Klineea9cc482017-03-10 19:35:34 +0900560 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700561 break;
562 case CMD_INTERFACE_DOWN:
563 transitionTo(mUnavailableState);
564 break;
Erik Kline1eb8c692016-07-08 17:21:26 +0900565 case CMD_IPV6_TETHER_UPDATE:
Erik Kline94ae4c92017-06-13 21:32:10 +0900566 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
Erik Kline1eb8c692016-07-08 17:21:26 +0900567 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700568 default:
Erik Klineab6439b2017-06-06 19:24:21 +0900569 return NOT_HANDLED;
Christopher Wileyd2896662016-05-19 11:54:54 -0700570 }
Erik Klineab6439b2017-06-06 19:24:21 +0900571 return HANDLED;
Christopher Wileyd2896662016-05-19 11:54:54 -0700572 }
573 }
574
Erik Klinef79a34d2017-04-13 22:54:34 +0900575 class BaseServingState extends State {
Christopher Wileyd2896662016-05-19 11:54:54 -0700576 @Override
577 public void enter() {
Erik Klinedd4d5822017-06-12 18:20:08 +0900578 if (!startIPv4()) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700579 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
Christopher Wiley5c0b10a2016-05-31 14:43:08 -0700580 return;
Christopher Wileyd2896662016-05-19 11:54:54 -0700581 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700582
Christopher Wileyd2896662016-05-19 11:54:54 -0700583 try {
584 mNMService.tetherInterface(mIfaceName);
585 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900586 mLog.e("Error Tethering: " + e);
Christopher Wileyd985dde2016-05-31 10:44:35 -0700587 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700588 return;
589 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900590
Erik Kline94ae4c92017-06-13 21:32:10 +0900591 if (!startIPv6()) {
592 mLog.e("Failed to startIPv6");
Erik Klinef79a34d2017-04-13 22:54:34 +0900593 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
594 return;
Erik Kline1eb8c692016-07-08 17:21:26 +0900595 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700596 }
597
Christopher Wileye10bfc02016-05-23 16:17:30 -0700598 @Override
599 public void exit() {
Christopher Wileye10bfc02016-05-23 16:17:30 -0700600 // Note that at this point, we're leaving the tethered state. We can fail any
601 // of these operations, but it doesn't really change that we have to try them
602 // all in sequence.
Erik Kline94ae4c92017-06-13 21:32:10 +0900603 stopIPv6();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700604
605 try {
606 mNMService.untetherInterface(mIfaceName);
Erik Klinef79a34d2017-04-13 22:54:34 +0900607 } catch (Exception e) {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700608 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
Erik Kline7747fd42017-05-12 16:52:48 +0900609 mLog.e("Failed to untether interface: " + e);
Christopher Wileye10bfc02016-05-23 16:17:30 -0700610 }
611
Erik Klinedd4d5822017-06-12 18:20:08 +0900612 stopIPv4();
613
614 resetLinkProperties();
Christopher Wileye10bfc02016-05-23 16:17:30 -0700615 }
616
Erik Klineea9cc482017-03-10 19:35:34 +0900617 @Override
618 public boolean processMessage(Message message) {
Erik Klineb4df3f42017-07-06 16:40:06 +0900619 logMessage(this, message.what);
Erik Klineea9cc482017-03-10 19:35:34 +0900620 switch (message.what) {
621 case CMD_TETHER_UNREQUESTED:
622 transitionTo(mInitialState);
623 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
624 break;
625 case CMD_INTERFACE_DOWN:
626 transitionTo(mUnavailableState);
627 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
628 break;
629 case CMD_IPV6_TETHER_UPDATE:
Erik Kline94ae4c92017-06-13 21:32:10 +0900630 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
Erik Klinedd4d5822017-06-12 18:20:08 +0900631 sendLinkProperties();
Erik Klineea9cc482017-03-10 19:35:34 +0900632 break;
633 case CMD_IP_FORWARDING_ENABLE_ERROR:
634 case CMD_IP_FORWARDING_DISABLE_ERROR:
635 case CMD_START_TETHERING_ERROR:
636 case CMD_STOP_TETHERING_ERROR:
637 case CMD_SET_DNS_FORWARDERS_ERROR:
638 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
639 transitionTo(mInitialState);
640 break;
641 default:
642 return false;
643 }
644 return true;
645 }
646 }
647
Erik Klinef79a34d2017-04-13 22:54:34 +0900648 // Handling errors in BaseServingState.enter() by transitioning is
649 // problematic because transitioning during a multi-state jump yields
650 // a Log.wtf(). Ultimately, there should be only one ServingState,
651 // and forwarding and NAT rules should be handled by a coordinating
652 // functional element outside of TetherInterfaceStateMachine.
653 class LocalHotspotState extends BaseServingState {
Erik Klineea9cc482017-03-10 19:35:34 +0900654 @Override
655 public void enter() {
Erik Klinef79a34d2017-04-13 22:54:34 +0900656 super.enter();
657 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
658 transitionTo(mInitialState);
659 }
660
Erik Klineea9cc482017-03-10 19:35:34 +0900661 if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
Erik Klineca41be72017-04-20 22:59:16 +0900662 sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
Erik Klineea9cc482017-03-10 19:35:34 +0900663 }
664
665 @Override
666 public boolean processMessage(Message message) {
Erik Klinef79a34d2017-04-13 22:54:34 +0900667 if (super.processMessage(message)) return true;
668
Erik Klineb4df3f42017-07-06 16:40:06 +0900669 logMessage(this, message.what);
Erik Klineea9cc482017-03-10 19:35:34 +0900670 switch (message.what) {
671 case CMD_TETHER_REQUESTED:
Erik Kline7747fd42017-05-12 16:52:48 +0900672 mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
Erik Klineea9cc482017-03-10 19:35:34 +0900673 break;
674 case CMD_TETHER_CONNECTION_CHANGED:
675 // Ignored in local hotspot state.
676 break;
677 default:
678 return false;
679 }
680 return true;
681 }
682 }
683
Erik Klinef79a34d2017-04-13 22:54:34 +0900684 // Handling errors in BaseServingState.enter() by transitioning is
685 // problematic because transitioning during a multi-state jump yields
686 // a Log.wtf(). Ultimately, there should be only one ServingState,
687 // and forwarding and NAT rules should be handled by a coordinating
688 // functional element outside of TetherInterfaceStateMachine.
689 class TetheredState extends BaseServingState {
Erik Klineea9cc482017-03-10 19:35:34 +0900690 @Override
691 public void enter() {
Erik Klinef79a34d2017-04-13 22:54:34 +0900692 super.enter();
693 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
694 transitionTo(mInitialState);
695 }
696
Erik Klineea9cc482017-03-10 19:35:34 +0900697 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
698 sendInterfaceState(IControlsTethering.STATE_TETHERED);
699 }
700
701 @Override
702 public void exit() {
703 cleanupUpstream();
Erik Klinef79a34d2017-04-13 22:54:34 +0900704 super.exit();
Erik Klineea9cc482017-03-10 19:35:34 +0900705 }
706
Christopher Wileyd2896662016-05-19 11:54:54 -0700707 private void cleanupUpstream() {
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900708 if (mUpstreamIfaceSet == null) return;
Erik Kline8ea45482017-02-13 17:28:53 +0900709
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900710 for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
711 mUpstreamIfaceSet = null;
Erik Kline8ea45482017-02-13 17:28:53 +0900712 }
713
714 private void cleanupUpstreamInterface(String upstreamIface) {
715 // Note that we don't care about errors here.
716 // Sometimes interfaces are gone before we get
717 // to remove their rules, which generates errors.
718 // Just do the best we can.
719 try {
720 // About to tear down NAT; gather remaining statistics.
721 mStatsService.forceUpdate();
722 } catch (Exception e) {
723 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
Christopher Wileyd2896662016-05-19 11:54:54 -0700724 }
Erik Kline8ea45482017-02-13 17:28:53 +0900725 try {
726 mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
727 } catch (Exception e) {
728 if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
729 }
730 try {
731 mNMService.disableNat(mIfaceName, upstreamIface);
732 } catch (Exception e) {
733 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
734 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700735 }
736
737 @Override
738 public boolean processMessage(Message message) {
Erik Klinef79a34d2017-04-13 22:54:34 +0900739 if (super.processMessage(message)) return true;
740
Erik Klineb4df3f42017-07-06 16:40:06 +0900741 logMessage(this, message.what);
Christopher Wileyd2896662016-05-19 11:54:54 -0700742 switch (message.what) {
Erik Klineea9cc482017-03-10 19:35:34 +0900743 case CMD_TETHER_REQUESTED:
Erik Kline7747fd42017-05-12 16:52:48 +0900744 mLog.e("CMD_TETHER_REQUESTED while already tethering.");
Christopher Wileyd2896662016-05-19 11:54:54 -0700745 break;
746 case CMD_TETHER_CONNECTION_CHANGED:
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900747 final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
748 if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700749 if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
750 break;
751 }
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900752
753 if (newUpstreamIfaceSet == null) {
754 cleanupUpstream();
755 break;
756 }
757
758 for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
759 cleanupUpstreamInterface(removed);
760 }
761
762 final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet);
763 // This makes the call to cleanupUpstream() in the error
764 // path for any interface neatly cleanup all the interfaces.
765 mUpstreamIfaceSet = newUpstreamIfaceSet;
766
767 for (String ifname : added) {
Christopher Wileyd2896662016-05-19 11:54:54 -0700768 try {
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900769 mNMService.enableNat(mIfaceName, ifname);
770 mNMService.startInterfaceForwarding(mIfaceName, ifname);
Christopher Wileyd2896662016-05-19 11:54:54 -0700771 } catch (Exception e) {
Erik Kline7747fd42017-05-12 16:52:48 +0900772 mLog.e("Exception enabling NAT: " + e);
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900773 cleanupUpstream();
Christopher Wileyd985dde2016-05-31 10:44:35 -0700774 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
Christopher Wileyd2896662016-05-19 11:54:54 -0700775 transitionTo(mInitialState);
776 return true;
777 }
778 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700779 break;
Christopher Wileyd2896662016-05-19 11:54:54 -0700780 default:
Erik Klinedd4d5822017-06-12 18:20:08 +0900781 return false;
Christopher Wileyd2896662016-05-19 11:54:54 -0700782 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900783 return true;
Christopher Wileyd2896662016-05-19 11:54:54 -0700784 }
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900785
786 private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
787 if (mUpstreamIfaceSet == null && newIfaces == null) return true;
788 if (mUpstreamIfaceSet != null && newIfaces != null) {
789 return mUpstreamIfaceSet.equals(newIfaces);
790 }
791 return false;
792 }
793
794 private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
795 if (mUpstreamIfaceSet == null) return new HashSet<>();
796
797 final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
798 removed.removeAll(newIfaces.ifnames);
799 return removed;
800 }
801
802 private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
803 final HashSet<String> added = new HashSet<>(newIfaces.ifnames);
804 if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
805 return added;
806 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700807 }
808
Christopher Wiley9ad83ab2016-05-20 17:51:27 -0700809 /**
810 * This state is terminal for the per interface state machine. At this
811 * point, the master state machine should have removed this interface
812 * specific state machine from its list of possible recipients of
813 * tethering requests. The state machine itself will hang around until
814 * the garbage collector finds it.
815 */
Christopher Wileyd2896662016-05-19 11:54:54 -0700816 class UnavailableState extends State {
817 @Override
818 public void enter() {
Christopher Wileyd985dde2016-05-31 10:44:35 -0700819 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
Erik Klineea9cc482017-03-10 19:35:34 +0900820 sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
Christopher Wileyd2896662016-05-19 11:54:54 -0700821 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700822 }
Erik Kline94ae4c92017-06-13 21:32:10 +0900823
824 // Accumulate routes representing "prefixes to be assigned to the local
825 // interface", for subsequent modification of local_network routing.
826 private static ArrayList<RouteInfo> getLocalRoutesFor(
827 String ifname, HashSet<IpPrefix> prefixes) {
828 final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>();
829 for (IpPrefix ipp : prefixes) {
830 localRoutes.add(new RouteInfo(ipp, null, ifname));
831 }
832 return localRoutes;
833 }
834
835 // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
836 private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
837 final byte[] dnsBytes = localPrefix.getRawAddress();
Erik Kline0f27eed2018-05-29 19:24:43 +0900838 dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
Erik Kline94ae4c92017-06-13 21:32:10 +0900839 try {
840 return Inet6Address.getByAddress(null, dnsBytes, 0);
841 } catch (UnknownHostException e) {
842 Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix);
843 return null;
844 }
845 }
846
Erik Kline0f27eed2018-05-29 19:24:43 +0900847 private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
Erik Kline94ae4c92017-06-13 21:32:10 +0900848 final byte random = (byte) (new Random()).nextInt();
Erik Kline0f27eed2018-05-29 19:24:43 +0900849 for (int value : excluded) {
850 if (random == value) return dflt;
851 }
852 return random;
Erik Kline94ae4c92017-06-13 21:32:10 +0900853 }
Christopher Wileyd2896662016-05-19 11:54:54 -0700854}