Home | History | Annotate | Download | only in tethering
      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.RFC7421_PREFIX_LENGTH;
     20 
     21 import android.net.ConnectivityManager;
     22 import android.net.INetd;
     23 import android.net.INetworkStatsService;
     24 import android.net.InterfaceConfiguration;
     25 import android.net.IpPrefix;
     26 import android.net.LinkAddress;
     27 import android.net.LinkProperties;
     28 import android.net.NetworkUtils;
     29 import android.net.RouteInfo;
     30 import android.net.ip.RouterAdvertisementDaemon;
     31 import android.net.ip.RouterAdvertisementDaemon.RaParams;
     32 import android.net.util.NetdService;
     33 import android.net.util.SharedLog;
     34 import android.os.INetworkManagementService;
     35 import android.os.Looper;
     36 import android.os.Message;
     37 import android.os.RemoteException;
     38 import android.os.ServiceSpecificException;
     39 import android.util.Log;
     40 import android.util.Slog;
     41 import android.util.SparseArray;
     42 
     43 import com.android.internal.util.MessageUtils;
     44 import com.android.internal.util.Protocol;
     45 import com.android.internal.util.State;
     46 import com.android.internal.util.StateMachine;
     47 
     48 import java.net.Inet6Address;
     49 import java.net.InetAddress;
     50 import java.net.NetworkInterface;
     51 import java.net.SocketException;
     52 import java.net.UnknownHostException;
     53 import java.util.ArrayList;
     54 import java.util.HashSet;
     55 import java.util.Objects;
     56 import java.util.Random;
     57 
     58 /**
     59  * Provides the interface to IP-layer serving functionality for a given network
     60  * interface, e.g. for tethering or "local-only hotspot" mode.
     61  *
     62  * @hide
     63  */
     64 public class TetherInterfaceStateMachine extends StateMachine {
     65     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
     66 
     67     private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
     68     private static final int USB_PREFIX_LENGTH = 24;
     69     private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
     70     private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
     71 
     72     private final static String TAG = "TetherInterfaceSM";
     73     private final static boolean DBG = false;
     74     private final static boolean VDBG = false;
     75     private static final Class[] messageClasses = {
     76             TetherInterfaceStateMachine.class
     77     };
     78     private static final SparseArray<String> sMagicDecoderRing =
     79             MessageUtils.findMessageNames(messageClasses);
     80 
     81     private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
     82     // request from the user that it wants to tether
     83     public static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
     84     // request from the user that it wants to untether
     85     public static final int CMD_TETHER_UNREQUESTED          = BASE_IFACE + 3;
     86     // notification that this interface is down
     87     public static final int CMD_INTERFACE_DOWN              = BASE_IFACE + 4;
     88     // notification from the master SM that it had trouble enabling IP Forwarding
     89     public static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IFACE + 7;
     90     // notification from the master SM that it had trouble disabling IP Forwarding
     91     public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
     92     // notification from the master SM that it had trouble starting tethering
     93     public static final int CMD_START_TETHERING_ERROR       = BASE_IFACE + 9;
     94     // notification from the master SM that it had trouble stopping tethering
     95     public static final int CMD_STOP_TETHERING_ERROR        = BASE_IFACE + 10;
     96     // notification from the master SM that it had trouble setting the DNS forwarders
     97     public static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IFACE + 11;
     98     // the upstream connection has changed
     99     public static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IFACE + 12;
    100     // new IPv6 tethering parameters need to be processed
    101     public static final int CMD_IPV6_TETHER_UPDATE          = BASE_IFACE + 13;
    102 
    103     private final State mInitialState;
    104     private final State mLocalHotspotState;
    105     private final State mTetheredState;
    106     private final State mUnavailableState;
    107 
    108     private final SharedLog mLog;
    109     private final INetworkManagementService mNMService;
    110     private final INetworkStatsService mStatsService;
    111     private final IControlsTethering mTetherController;
    112 
    113     private final String mIfaceName;
    114     private final int mInterfaceType;
    115     private final LinkProperties mLinkProperties;
    116 
    117     private int mLastError;
    118     private int mServingMode;
    119     private String mMyUpstreamIfaceName;  // may change over time
    120     private NetworkInterface mNetworkInterface;
    121     private byte[] mHwAddr;
    122     // TODO: De-duplicate this with mLinkProperties above. Currently, these link
    123     // properties are those selected by the IPv6TetheringCoordinator and relayed
    124     // to us. By comparison, mLinkProperties contains the addresses and directly
    125     // connected routes that have been formed from these properties iff. we have
    126     // succeeded in configuring them and are able to announce them within Router
    127     // Advertisements (otherwise, we do not add them to mLinkProperties at all).
    128     private LinkProperties mLastIPv6LinkProperties;
    129     private RouterAdvertisementDaemon mRaDaemon;
    130     private RaParams mLastRaParams;
    131 
    132     public TetherInterfaceStateMachine(
    133             String ifaceName, Looper looper, int interfaceType, SharedLog log,
    134             INetworkManagementService nMService, INetworkStatsService statsService,
    135             IControlsTethering tetherController) {
    136         super(ifaceName, looper);
    137         mLog = log.forSubComponent(ifaceName);
    138         mNMService = nMService;
    139         mStatsService = statsService;
    140         mTetherController = tetherController;
    141         mIfaceName = ifaceName;
    142         mInterfaceType = interfaceType;
    143         mLinkProperties = new LinkProperties();
    144         resetLinkProperties();
    145         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
    146         mServingMode = IControlsTethering.STATE_AVAILABLE;
    147 
    148         mInitialState = new InitialState();
    149         mLocalHotspotState = new LocalHotspotState();
    150         mTetheredState = new TetheredState();
    151         mUnavailableState = new UnavailableState();
    152         addState(mInitialState);
    153         addState(mLocalHotspotState);
    154         addState(mTetheredState);
    155         addState(mUnavailableState);
    156 
    157         setInitialState(mInitialState);
    158     }
    159 
    160     public String interfaceName() { return mIfaceName; }
    161 
    162     public int interfaceType() { return mInterfaceType; }
    163 
    164     public int lastError() { return mLastError; }
    165 
    166     public int servingMode() { return mServingMode; }
    167 
    168     public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
    169 
    170     public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
    171 
    172     public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
    173 
    174     /**
    175      * Internals.
    176      */
    177 
    178     private boolean startIPv4() { return configureIPv4(true); }
    179 
    180     private void stopIPv4() { configureIPv4(false); }
    181 
    182     private boolean configureIPv4(boolean enabled) {
    183         if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
    184 
    185         // TODO: Replace this hard-coded information with dynamically selected
    186         // config passed down to us by a higher layer IP-coordinating element.
    187         String ipAsString = null;
    188         int prefixLen = 0;
    189         if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
    190             ipAsString = USB_NEAR_IFACE_ADDR;
    191             prefixLen = USB_PREFIX_LENGTH;
    192         } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
    193             ipAsString = WIFI_HOST_IFACE_ADDR;
    194             prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
    195         } else {
    196             // Nothing to do, BT does this elsewhere.
    197             return true;
    198         }
    199 
    200         final LinkAddress linkAddr;
    201         try {
    202             final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
    203             if (ifcg == null) {
    204                 mLog.e("Received null interface config");
    205                 return false;
    206             }
    207 
    208             InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
    209             linkAddr = new LinkAddress(addr, prefixLen);
    210             ifcg.setLinkAddress(linkAddr);
    211             if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
    212                 // The WiFi stack has ownership of the interface up/down state.
    213                 // It is unclear whether the Bluetooth or USB stacks will manage their own
    214                 // state.
    215                 ifcg.ignoreInterfaceUpDownStatus();
    216             } else {
    217                 if (enabled) {
    218                     ifcg.setInterfaceUp();
    219                 } else {
    220                     ifcg.setInterfaceDown();
    221                 }
    222             }
    223             ifcg.clearFlag("running");
    224             mNMService.setInterfaceConfig(mIfaceName, ifcg);
    225         } catch (Exception e) {
    226             mLog.e("Error configuring interface " + e);
    227             return false;
    228         }
    229 
    230         // Directly-connected route.
    231         final RouteInfo route = new RouteInfo(linkAddr);
    232         if (enabled) {
    233             mLinkProperties.addLinkAddress(linkAddr);
    234             mLinkProperties.addRoute(route);
    235         } else {
    236             mLinkProperties.removeLinkAddress(linkAddr);
    237             mLinkProperties.removeRoute(route);
    238         }
    239         return true;
    240     }
    241 
    242     private boolean startIPv6() {
    243         // TODO: Refactor for testability (perhaps passing an android.system.Os
    244         // instance and calling getifaddrs() directly).
    245         try {
    246             mNetworkInterface = NetworkInterface.getByName(mIfaceName);
    247         } catch (SocketException e) {
    248             mLog.e("Error looking up NetworkInterfaces: " + e);
    249             stopIPv6();
    250             return false;
    251         }
    252         if (mNetworkInterface == null) {
    253             mLog.e("Failed to find NetworkInterface");
    254             stopIPv6();
    255             return false;
    256         }
    257 
    258         try {
    259             mHwAddr = mNetworkInterface.getHardwareAddress();
    260         } catch (SocketException e) {
    261             mLog.e("Failed to find hardware address: " + e);
    262             stopIPv6();
    263             return false;
    264         }
    265 
    266         final int ifindex = mNetworkInterface.getIndex();
    267         mRaDaemon = new RouterAdvertisementDaemon(mIfaceName, ifindex, mHwAddr);
    268         if (!mRaDaemon.start()) {
    269             stopIPv6();
    270             return false;
    271         }
    272 
    273         return true;
    274     }
    275 
    276     private void stopIPv6() {
    277         mNetworkInterface = null;
    278         mHwAddr = null;
    279         setRaParams(null);
    280 
    281         if (mRaDaemon != null) {
    282             mRaDaemon.stop();
    283             mRaDaemon = null;
    284         }
    285     }
    286 
    287     // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
    288     // LinkProperties. These have extraneous data filtered out and only the
    289     // necessary prefixes included (per its prefix distribution policy).
    290     //
    291     // TODO: Evaluate using a data structure than is more directly suited to
    292     // communicating only the relevant information.
    293     private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) {
    294         if (mRaDaemon == null) return;
    295 
    296         // Avoid unnecessary work on spurious updates.
    297         if (Objects.equals(mLastIPv6LinkProperties, v6only)) {
    298             return;
    299         }
    300 
    301         RaParams params = null;
    302 
    303         if (v6only != null) {
    304             params = new RaParams();
    305             params.mtu = v6only.getMtu();
    306             params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
    307 
    308             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
    309                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
    310 
    311                 final IpPrefix prefix = new IpPrefix(
    312                         linkAddr.getAddress(), linkAddr.getPrefixLength());
    313                 params.prefixes.add(prefix);
    314 
    315                 final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
    316                 if (dnsServer != null) {
    317                     params.dnses.add(dnsServer);
    318                 }
    319             }
    320         }
    321         // If v6only is null, we pass in null to setRaParams(), which handles
    322         // deprecation of any existing RA data.
    323 
    324         setRaParams(params);
    325         mLastIPv6LinkProperties = v6only;
    326     }
    327 
    328     private void configureLocalIPv6Routes(
    329             HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
    330         // [1] Remove the routes that are deprecated.
    331         if (!deprecatedPrefixes.isEmpty()) {
    332             final ArrayList<RouteInfo> toBeRemoved =
    333                     getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
    334             try {
    335                 final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
    336                 if (removalFailures > 0) {
    337                     mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
    338                             removalFailures));
    339                 }
    340             } catch (RemoteException e) {
    341                 mLog.e("Failed to remove IPv6 routes from local table: " + e);
    342             }
    343 
    344             for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
    345         }
    346 
    347         // [2] Add only the routes that have not previously been added.
    348         if (newPrefixes != null && !newPrefixes.isEmpty()) {
    349             HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone();
    350             if (mLastRaParams != null) {
    351                 addedPrefixes.removeAll(mLastRaParams.prefixes);
    352             }
    353 
    354             if (mLastRaParams == null || mLastRaParams.prefixes.isEmpty()) {
    355                 // We need to be able to send unicast RAs, and clients might
    356                 // like to ping the default router's link-local address.  Note
    357                 // that we never remove the link-local route from the network
    358                 // until Tethering disables tethering on the interface. We
    359                 // only need to add the link-local prefix once, but in the
    360                 // event we add it more than once netd silently ignores EEXIST.
    361                 addedPrefixes.add(LINK_LOCAL_PREFIX);
    362             }
    363 
    364             if (!addedPrefixes.isEmpty()) {
    365                 final ArrayList<RouteInfo> toBeAdded =
    366                         getLocalRoutesFor(mIfaceName, addedPrefixes);
    367                 try {
    368                     // It's safe to call addInterfaceToLocalNetwork() even if
    369                     // the interface is already in the local_network. Note also
    370                     // that adding routes that already exist does not cause an
    371                     // error (EEXIST is silently ignored).
    372                     mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
    373                 } catch (RemoteException e) {
    374                     mLog.e("Failed to add IPv6 routes to local table: " + e);
    375                 }
    376 
    377                 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
    378             }
    379         }
    380     }
    381 
    382     private void configureLocalIPv6Dns(
    383             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
    384         final INetd netd = NetdService.getInstance();
    385         if (netd == null) {
    386             if (newDnses != null) newDnses.clear();
    387             mLog.e("No netd service instance available; not setting local IPv6 addresses");
    388             return;
    389         }
    390 
    391         // [1] Remove deprecated local DNS IP addresses.
    392         if (!deprecatedDnses.isEmpty()) {
    393             for (Inet6Address dns : deprecatedDnses) {
    394                 final String dnsString = dns.getHostAddress();
    395                 try {
    396                     netd.interfaceDelAddress(mIfaceName, dnsString, RFC7421_PREFIX_LENGTH);
    397                 } catch (ServiceSpecificException | RemoteException e) {
    398                     mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
    399                 }
    400 
    401                 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
    402             }
    403         }
    404 
    405         // [2] Add only the local DNS IP addresses that have not previously been added.
    406         if (newDnses != null && !newDnses.isEmpty()) {
    407             final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone();
    408             if (mLastRaParams != null) {
    409                 addedDnses.removeAll(mLastRaParams.dnses);
    410             }
    411 
    412             for (Inet6Address dns : addedDnses) {
    413                 final String dnsString = dns.getHostAddress();
    414                 try {
    415                     netd.interfaceAddAddress(mIfaceName, dnsString, RFC7421_PREFIX_LENGTH);
    416                 } catch (ServiceSpecificException | RemoteException e) {
    417                     mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
    418                     newDnses.remove(dns);
    419                 }
    420 
    421                 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
    422             }
    423         }
    424 
    425         try {
    426             netd.tetherApplyDnsInterfaces();
    427         } catch (ServiceSpecificException | RemoteException e) {
    428             mLog.e("Failed to update local DNS caching server");
    429             if (newDnses != null) newDnses.clear();
    430         }
    431     }
    432 
    433     private void setRaParams(RaParams newParams) {
    434         if (mRaDaemon != null) {
    435             final RaParams deprecatedParams =
    436                     RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
    437 
    438             configureLocalIPv6Routes(deprecatedParams.prefixes,
    439                     (newParams != null) ? newParams.prefixes : null);
    440 
    441             configureLocalIPv6Dns(deprecatedParams.dnses,
    442                     (newParams != null) ? newParams.dnses : null);
    443 
    444             mRaDaemon.buildNewRa(deprecatedParams, newParams);
    445         }
    446 
    447         mLastRaParams = newParams;
    448     }
    449 
    450     private void logMessage(State state, int what) {
    451         mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
    452     }
    453 
    454     private void sendInterfaceState(int newInterfaceState) {
    455         mServingMode = newInterfaceState;
    456         mTetherController.updateInterfaceState(
    457                 TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
    458         sendLinkProperties();
    459     }
    460 
    461     private void sendLinkProperties() {
    462         mTetherController.updateLinkProperties(
    463                 TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
    464     }
    465 
    466     private void resetLinkProperties() {
    467         mLinkProperties.clear();
    468         mLinkProperties.setInterfaceName(mIfaceName);
    469     }
    470 
    471     class InitialState extends State {
    472         @Override
    473         public void enter() {
    474             sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
    475         }
    476 
    477         @Override
    478         public boolean processMessage(Message message) {
    479             logMessage(this, message.what);
    480             switch (message.what) {
    481                 case CMD_TETHER_REQUESTED:
    482                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
    483                     switch (message.arg1) {
    484                         case IControlsTethering.STATE_LOCAL_ONLY:
    485                             transitionTo(mLocalHotspotState);
    486                             break;
    487                         case IControlsTethering.STATE_TETHERED:
    488                             transitionTo(mTetheredState);
    489                             break;
    490                         default:
    491                             mLog.e("Invalid tethering interface serving state specified.");
    492                     }
    493                     break;
    494                 case CMD_INTERFACE_DOWN:
    495                     transitionTo(mUnavailableState);
    496                     break;
    497                 case CMD_IPV6_TETHER_UPDATE:
    498                     updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
    499                     break;
    500                 default:
    501                     return NOT_HANDLED;
    502             }
    503             return HANDLED;
    504         }
    505     }
    506 
    507     class BaseServingState extends State {
    508         @Override
    509         public void enter() {
    510             if (!startIPv4()) {
    511                 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
    512                 return;
    513             }
    514 
    515             try {
    516                 mNMService.tetherInterface(mIfaceName);
    517             } catch (Exception e) {
    518                 mLog.e("Error Tethering: " + e);
    519                 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
    520                 return;
    521             }
    522 
    523             if (!startIPv6()) {
    524                 mLog.e("Failed to startIPv6");
    525                 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
    526                 return;
    527             }
    528         }
    529 
    530         @Override
    531         public void exit() {
    532             // Note that at this point, we're leaving the tethered state.  We can fail any
    533             // of these operations, but it doesn't really change that we have to try them
    534             // all in sequence.
    535             stopIPv6();
    536 
    537             try {
    538                 mNMService.untetherInterface(mIfaceName);
    539             } catch (Exception e) {
    540                 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
    541                 mLog.e("Failed to untether interface: " + e);
    542             }
    543 
    544             stopIPv4();
    545 
    546             resetLinkProperties();
    547         }
    548 
    549         @Override
    550         public boolean processMessage(Message message) {
    551             logMessage(this, message.what);
    552             switch (message.what) {
    553                 case CMD_TETHER_UNREQUESTED:
    554                     transitionTo(mInitialState);
    555                     if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
    556                     break;
    557                 case CMD_INTERFACE_DOWN:
    558                     transitionTo(mUnavailableState);
    559                     if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
    560                     break;
    561                 case CMD_IPV6_TETHER_UPDATE:
    562                     updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
    563                     sendLinkProperties();
    564                     break;
    565                 case CMD_IP_FORWARDING_ENABLE_ERROR:
    566                 case CMD_IP_FORWARDING_DISABLE_ERROR:
    567                 case CMD_START_TETHERING_ERROR:
    568                 case CMD_STOP_TETHERING_ERROR:
    569                 case CMD_SET_DNS_FORWARDERS_ERROR:
    570                     mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
    571                     transitionTo(mInitialState);
    572                     break;
    573                 default:
    574                     return false;
    575             }
    576             return true;
    577         }
    578     }
    579 
    580     // Handling errors in BaseServingState.enter() by transitioning is
    581     // problematic because transitioning during a multi-state jump yields
    582     // a Log.wtf(). Ultimately, there should be only one ServingState,
    583     // and forwarding and NAT rules should be handled by a coordinating
    584     // functional element outside of TetherInterfaceStateMachine.
    585     class LocalHotspotState extends BaseServingState {
    586         @Override
    587         public void enter() {
    588             super.enter();
    589             if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
    590                 transitionTo(mInitialState);
    591             }
    592 
    593             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
    594             sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
    595         }
    596 
    597         @Override
    598         public boolean processMessage(Message message) {
    599             if (super.processMessage(message)) return true;
    600 
    601             logMessage(this, message.what);
    602             switch (message.what) {
    603                 case CMD_TETHER_REQUESTED:
    604                     mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
    605                     break;
    606                 case CMD_TETHER_CONNECTION_CHANGED:
    607                     // Ignored in local hotspot state.
    608                     break;
    609                 default:
    610                     return false;
    611             }
    612             return true;
    613         }
    614     }
    615 
    616     // Handling errors in BaseServingState.enter() by transitioning is
    617     // problematic because transitioning during a multi-state jump yields
    618     // a Log.wtf(). Ultimately, there should be only one ServingState,
    619     // and forwarding and NAT rules should be handled by a coordinating
    620     // functional element outside of TetherInterfaceStateMachine.
    621     class TetheredState extends BaseServingState {
    622         @Override
    623         public void enter() {
    624             super.enter();
    625             if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
    626                 transitionTo(mInitialState);
    627             }
    628 
    629             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
    630             sendInterfaceState(IControlsTethering.STATE_TETHERED);
    631         }
    632 
    633         @Override
    634         public void exit() {
    635             cleanupUpstream();
    636             super.exit();
    637         }
    638 
    639         private void cleanupUpstream() {
    640             if (mMyUpstreamIfaceName == null) return;
    641 
    642             cleanupUpstreamInterface(mMyUpstreamIfaceName);
    643             mMyUpstreamIfaceName = null;
    644         }
    645 
    646         private void cleanupUpstreamInterface(String upstreamIface) {
    647             // Note that we don't care about errors here.
    648             // Sometimes interfaces are gone before we get
    649             // to remove their rules, which generates errors.
    650             // Just do the best we can.
    651             try {
    652                 // About to tear down NAT; gather remaining statistics.
    653                 mStatsService.forceUpdate();
    654             } catch (Exception e) {
    655                 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
    656             }
    657             try {
    658                 mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
    659             } catch (Exception e) {
    660                 if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
    661             }
    662             try {
    663                 mNMService.disableNat(mIfaceName, upstreamIface);
    664             } catch (Exception e) {
    665                 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
    666             }
    667         }
    668 
    669         @Override
    670         public boolean processMessage(Message message) {
    671             if (super.processMessage(message)) return true;
    672 
    673             logMessage(this, message.what);
    674             switch (message.what) {
    675                 case CMD_TETHER_REQUESTED:
    676                     mLog.e("CMD_TETHER_REQUESTED while already tethering.");
    677                     break;
    678                 case CMD_TETHER_CONNECTION_CHANGED:
    679                     String newUpstreamIfaceName = (String)(message.obj);
    680                     if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
    681                             (mMyUpstreamIfaceName != null &&
    682                             mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
    683                         if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
    684                         break;
    685                     }
    686                     cleanupUpstream();
    687                     if (newUpstreamIfaceName != null) {
    688                         try {
    689                             mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
    690                             mNMService.startInterfaceForwarding(mIfaceName,
    691                                     newUpstreamIfaceName);
    692                         } catch (Exception e) {
    693                             mLog.e("Exception enabling NAT: " + e);
    694                             cleanupUpstreamInterface(newUpstreamIfaceName);
    695                             mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
    696                             transitionTo(mInitialState);
    697                             return true;
    698                         }
    699                     }
    700                     mMyUpstreamIfaceName = newUpstreamIfaceName;
    701                     break;
    702                 default:
    703                     return false;
    704             }
    705             return true;
    706         }
    707     }
    708 
    709     /**
    710      * This state is terminal for the per interface state machine.  At this
    711      * point, the master state machine should have removed this interface
    712      * specific state machine from its list of possible recipients of
    713      * tethering requests.  The state machine itself will hang around until
    714      * the garbage collector finds it.
    715      */
    716     class UnavailableState extends State {
    717         @Override
    718         public void enter() {
    719             mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
    720             sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
    721         }
    722     }
    723 
    724     // Accumulate routes representing "prefixes to be assigned to the local
    725     // interface", for subsequent modification of local_network routing.
    726     private static ArrayList<RouteInfo> getLocalRoutesFor(
    727             String ifname, HashSet<IpPrefix> prefixes) {
    728         final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>();
    729         for (IpPrefix ipp : prefixes) {
    730             localRoutes.add(new RouteInfo(ipp, null, ifname));
    731         }
    732         return localRoutes;
    733     }
    734 
    735     // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
    736     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
    737         final byte[] dnsBytes = localPrefix.getRawAddress();
    738         dnsBytes[dnsBytes.length - 1] = getRandomNonZeroByte();
    739         try {
    740             return Inet6Address.getByAddress(null, dnsBytes, 0);
    741         } catch (UnknownHostException e) {
    742             Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix);
    743             return null;
    744         }
    745     }
    746 
    747     private static byte getRandomNonZeroByte() {
    748         final byte random = (byte) (new Random()).nextInt();
    749         // Don't pick the subnet-router anycast address, since that might be
    750         // in use on the upstream already.
    751         return (random != 0) ? random : 0x1;
    752     }
    753 }
    754