1 /* 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 17 package com.android.server.connectivity.tethering; 18 19 import static android.net.util.NetworkConstants.asByte; 20 import static android.net.util.NetworkConstants.FF; 21 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; 22 23 import android.net.ConnectivityManager; 24 import android.net.INetd; 25 import android.net.INetworkStatsService; 26 import android.net.InterfaceConfiguration; 27 import android.net.IpPrefix; 28 import android.net.LinkAddress; 29 import android.net.LinkProperties; 30 import android.net.NetworkUtils; 31 import android.net.RouteInfo; 32 import android.net.ip.InterfaceController; 33 import android.net.ip.RouterAdvertisementDaemon; 34 import android.net.ip.RouterAdvertisementDaemon.RaParams; 35 import android.net.util.InterfaceParams; 36 import android.net.util.InterfaceSet; 37 import android.net.util.SharedLog; 38 import android.os.INetworkManagementService; 39 import android.os.Looper; 40 import android.os.Message; 41 import android.os.RemoteException; 42 import android.os.ServiceSpecificException; 43 import android.util.Log; 44 import android.util.Slog; 45 import android.util.SparseArray; 46 47 import com.android.internal.util.MessageUtils; 48 import com.android.internal.util.Protocol; 49 import com.android.internal.util.State; 50 import com.android.internal.util.StateMachine; 51 52 import java.net.Inet6Address; 53 import java.net.InetAddress; 54 import java.net.UnknownHostException; 55 import java.util.ArrayList; 56 import java.util.HashSet; 57 import java.util.Objects; 58 import java.util.Random; 59 import java.util.Set; 60 61 /** 62 * Provides the interface to IP-layer serving functionality for a given network 63 * interface, e.g. for tethering or "local-only hotspot" mode. 64 * 65 * @hide 66 */ 67 public class TetherInterfaceStateMachine extends StateMachine { 68 private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); 69 private static final byte DOUG_ADAMS = (byte) 42; 70 71 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; 72 private static final int USB_PREFIX_LENGTH = 24; 73 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; 74 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; 75 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 = { 80 TetherInterfaceStateMachine.class 81 }; 82 private static final SparseArray<String> sMagicDecoderRing = 83 MessageUtils.findMessageNames(messageClasses); 84 85 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; 86 // 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; 92 // 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; 104 // new IPv6 tethering parameters need to be processed 105 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; 106 107 private final State mInitialState; 108 private final State mLocalHotspotState; 109 private final State mTetheredState; 110 private final State mUnavailableState; 111 112 private final SharedLog mLog; 113 private final INetworkManagementService mNMService; 114 private final INetd mNetd; 115 private final INetworkStatsService mStatsService; 116 private final IControlsTethering mTetherController; 117 private final InterfaceController mInterfaceCtrl; 118 119 private final String mIfaceName; 120 private final int mInterfaceType; 121 private final LinkProperties mLinkProperties; 122 123 private final TetheringDependencies mDeps; 124 125 private int mLastError; 126 private int mServingMode; 127 private InterfaceSet mUpstreamIfaceSet; // may change over time 128 private InterfaceParams mInterfaceParams; 129 // 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). 135 private LinkProperties mLastIPv6LinkProperties; 136 private RouterAdvertisementDaemon mRaDaemon; 137 private RaParams mLastRaParams; 138 139 public TetherInterfaceStateMachine( 140 String ifaceName, Looper looper, int interfaceType, SharedLog log, 141 INetworkManagementService nMService, INetworkStatsService statsService, 142 IControlsTethering tetherController, 143 TetheringDependencies deps) { 144 super(ifaceName, looper); 145 mLog = log.forSubComponent(ifaceName); 146 mNMService = nMService; 147 mNetd = deps.getNetdService(); 148 mStatsService = statsService; 149 mTetherController = tetherController; 150 mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog); 151 mIfaceName = ifaceName; 152 mInterfaceType = interfaceType; 153 mLinkProperties = new LinkProperties(); 154 mDeps = deps; 155 resetLinkProperties(); 156 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 157 mServingMode = IControlsTethering.STATE_AVAILABLE; 158 159 mInitialState = new InitialState(); 160 mLocalHotspotState = new LocalHotspotState(); 161 mTetheredState = new TetheredState(); 162 mUnavailableState = new UnavailableState(); 163 addState(mInitialState); 164 addState(mLocalHotspotState); 165 addState(mTetheredState); 166 addState(mUnavailableState); 167 168 setInitialState(mInitialState); 169 } 170 171 public String interfaceName() { return mIfaceName; } 172 173 public int interfaceType() { return mInterfaceType; } 174 175 public int lastError() { return mLastError; } 176 177 public int servingMode() { return mServingMode; } 178 179 public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); } 180 181 public void stop() { sendMessage(CMD_INTERFACE_DOWN); } 182 183 public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } 184 185 /** 186 * Internals. 187 */ 188 189 private boolean startIPv4() { return configureIPv4(true); } 190 191 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 } 197 198 // TODO: Refactor this in terms of calls to InterfaceController. 199 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. 204 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) { 210 ipAsString = getRandomWifiIPv4Address(); 211 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; 212 } else { 213 // Nothing to do, BT does this elsewhere. 214 return true; 215 } 216 217 final LinkAddress linkAddr; 218 try { 219 final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName); 220 if (ifcg == null) { 221 mLog.e("Received null interface config"); 222 return false; 223 } 224 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); 242 } catch (Exception e) { 243 mLog.e("Error configuring interface " + e); 244 return false; 245 } 246 247 // 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 } 256 return true; 257 } 258 259 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 269 private boolean startIPv6() { 270 mInterfaceParams = mDeps.getInterfaceParams(mIfaceName); 271 if (mInterfaceParams == null) { 272 mLog.e("Failed to find InterfaceParams"); 273 stopIPv6(); 274 return false; 275 } 276 277 mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams); 278 if (!mRaDaemon.start()) { 279 stopIPv6(); 280 return false; 281 } 282 283 return true; 284 } 285 286 private void stopIPv6() { 287 mInterfaceParams = null; 288 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 337 private void configureLocalIPv6Routes( 338 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 } 352 353 for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); 354 } 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 } 385 386 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); 387 } 388 } 389 } 390 391 private void configureLocalIPv6Dns( 392 HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) { 393 // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located? 394 if (mNetd == null) { 395 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) { 403 if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) { 404 mLog.e("Failed to remove local dns IP " + dns); 405 } 406 407 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH)); 408 } 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) { 419 if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) { 420 mLog.e("Failed to add local dns IP " + dns); 421 newDnses.remove(dns); 422 } 423 424 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH)); 425 } 426 } 427 428 try { 429 mNetd.tetherApplyDnsInterfaces(); 430 } 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 441 configureLocalIPv6Routes(deprecatedParams.prefixes, 442 (newParams != null) ? newParams.prefixes : null); 443 444 configureLocalIPv6Dns(deprecatedParams.dnses, 445 (newParams != null) ? newParams.dnses : null); 446 447 mRaDaemon.buildNewRa(deprecatedParams, newParams); 448 } 449 450 mLastRaParams = newParams; 451 } 452 453 private void logMessage(State state, int what) { 454 mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what))); 455 } 456 457 private void sendInterfaceState(int newInterfaceState) { 458 mServingMode = newInterfaceState; 459 mTetherController.updateInterfaceState( 460 TetherInterfaceStateMachine.this, newInterfaceState, mLastError); 461 sendLinkProperties(); 462 } 463 464 private void sendLinkProperties() { 465 mTetherController.updateLinkProperties( 466 TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties)); 467 } 468 469 private void resetLinkProperties() { 470 mLinkProperties.clear(); 471 mLinkProperties.setInterfaceName(mIfaceName); 472 } 473 474 class InitialState extends State { 475 @Override 476 public void enter() { 477 sendInterfaceState(IControlsTethering.STATE_AVAILABLE); 478 } 479 480 @Override 481 public boolean processMessage(Message message) { 482 logMessage(this, message.what); 483 switch (message.what) { 484 case CMD_TETHER_REQUESTED: 485 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 486 switch (message.arg1) { 487 case IControlsTethering.STATE_LOCAL_ONLY: 488 transitionTo(mLocalHotspotState); 489 break; 490 case IControlsTethering.STATE_TETHERED: 491 transitionTo(mTetheredState); 492 break; 493 default: 494 mLog.e("Invalid tethering interface serving state specified."); 495 } 496 break; 497 case CMD_INTERFACE_DOWN: 498 transitionTo(mUnavailableState); 499 break; 500 case CMD_IPV6_TETHER_UPDATE: 501 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); 502 break; 503 default: 504 return NOT_HANDLED; 505 } 506 return HANDLED; 507 } 508 } 509 510 class BaseServingState extends State { 511 @Override 512 public void enter() { 513 if (!startIPv4()) { 514 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; 515 return; 516 } 517 518 try { 519 mNMService.tetherInterface(mIfaceName); 520 } catch (Exception e) { 521 mLog.e("Error Tethering: " + e); 522 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; 523 return; 524 } 525 526 if (!startIPv6()) { 527 mLog.e("Failed to startIPv6"); 528 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted. 529 return; 530 } 531 } 532 533 @Override 534 public void exit() { 535 // 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. 538 stopIPv6(); 539 540 try { 541 mNMService.untetherInterface(mIfaceName); 542 } catch (Exception e) { 543 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; 544 mLog.e("Failed to untether interface: " + e); 545 } 546 547 stopIPv4(); 548 549 resetLinkProperties(); 550 } 551 552 @Override 553 public boolean processMessage(Message message) { 554 logMessage(this, message.what); 555 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: 565 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); 566 sendLinkProperties(); 567 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 583 // 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 { 589 @Override 590 public void enter() { 591 super.enter(); 592 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 593 transitionTo(mInitialState); 594 } 595 596 if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName); 597 sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY); 598 } 599 600 @Override 601 public boolean processMessage(Message message) { 602 if (super.processMessage(message)) return true; 603 604 logMessage(this, message.what); 605 switch (message.what) { 606 case CMD_TETHER_REQUESTED: 607 mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode."); 608 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 619 // 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 { 625 @Override 626 public void enter() { 627 super.enter(); 628 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 629 transitionTo(mInitialState); 630 } 631 632 if (DBG) Log.d(TAG, "Tethered " + mIfaceName); 633 sendInterfaceState(IControlsTethering.STATE_TETHERED); 634 } 635 636 @Override 637 public void exit() { 638 cleanupUpstream(); 639 super.exit(); 640 } 641 642 private void cleanupUpstream() { 643 if (mUpstreamIfaceSet == null) return; 644 645 for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname); 646 mUpstreamIfaceSet = null; 647 } 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()); 659 } 660 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 } 670 } 671 672 @Override 673 public boolean processMessage(Message message) { 674 if (super.processMessage(message)) return true; 675 676 logMessage(this, message.what); 677 switch (message.what) { 678 case CMD_TETHER_REQUESTED: 679 mLog.e("CMD_TETHER_REQUESTED while already tethering."); 680 break; 681 case CMD_TETHER_CONNECTION_CHANGED: 682 final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj; 683 if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) { 684 if (VDBG) Log.d(TAG, "Connection changed noop - dropping"); 685 break; 686 } 687 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) { 703 try { 704 mNMService.enableNat(mIfaceName, ifname); 705 mNMService.startInterfaceForwarding(mIfaceName, ifname); 706 } catch (Exception e) { 707 mLog.e("Exception enabling NAT: " + e); 708 cleanupUpstream(); 709 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; 710 transitionTo(mInitialState); 711 return true; 712 } 713 } 714 break; 715 default: 716 return false; 717 } 718 return true; 719 } 720 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 } 742 } 743 744 /** 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 */ 751 class UnavailableState extends State { 752 @Override 753 public void enter() { 754 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 755 sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE); 756 } 757 } 758 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(); 773 dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1)); 774 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 782 private static byte getRandomSanitizedByte(byte dflt, byte... excluded) { 783 final byte random = (byte) (new Random()).nextInt(); 784 for (int value : excluded) { 785 if (random == value) return dflt; 786 } 787 return random; 788 } 789 } 790