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 android.net.ConnectivityManager; 20 import android.net.INetworkStatsService; 21 import android.net.InterfaceConfiguration; 22 import android.net.LinkAddress; 23 import android.net.LinkProperties; 24 import android.net.NetworkUtils; 25 import android.os.INetworkManagementService; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.util.Log; 29 import android.util.SparseArray; 30 31 import com.android.internal.util.MessageUtils; 32 import com.android.internal.util.Protocol; 33 import com.android.internal.util.State; 34 import com.android.internal.util.StateMachine; 35 36 import java.net.InetAddress; 37 38 /** 39 * @hide 40 * 41 * Tracks the eligibility of a given network interface for tethering. 42 */ 43 public class TetherInterfaceStateMachine extends StateMachine { 44 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; 45 private static final int USB_PREFIX_LENGTH = 24; 46 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; 47 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; 48 49 private final static String TAG = "TetherInterfaceSM"; 50 private final static boolean DBG = false; 51 private final static boolean VDBG = false; 52 private static final Class[] messageClasses = { 53 TetherInterfaceStateMachine.class 54 }; 55 private static final SparseArray<String> sMagicDecoderRing = 56 MessageUtils.findMessageNames(messageClasses); 57 58 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; 59 // request from the user that it wants to tether 60 public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2; 61 // request from the user that it wants to untether 62 public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3; 63 // notification that this interface is down 64 public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4; 65 // notification from the master SM that it had trouble enabling IP Forwarding 66 public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7; 67 // notification from the master SM that it had trouble disabling IP Forwarding 68 public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8; 69 // notification from the master SM that it had trouble starting tethering 70 public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9; 71 // notification from the master SM that it had trouble stopping tethering 72 public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10; 73 // notification from the master SM that it had trouble setting the DNS forwarders 74 public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11; 75 // the upstream connection has changed 76 public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12; 77 // new IPv6 tethering parameters need to be processed 78 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; 79 80 private final State mInitialState; 81 private final State mTetheredState; 82 private final State mUnavailableState; 83 84 private final INetworkManagementService mNMService; 85 private final INetworkStatsService mStatsService; 86 private final IControlsTethering mTetherController; 87 88 private final String mIfaceName; 89 private final int mInterfaceType; 90 private final IPv6TetheringInterfaceServices mIPv6TetherSvc; 91 92 private int mLastError; 93 private String mMyUpstreamIfaceName; // may change over time 94 TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, INetworkManagementService nMService, INetworkStatsService statsService, IControlsTethering tetherController)95 public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType, 96 INetworkManagementService nMService, INetworkStatsService statsService, 97 IControlsTethering tetherController) { 98 super(ifaceName, looper); 99 mNMService = nMService; 100 mStatsService = statsService; 101 mTetherController = tetherController; 102 mIfaceName = ifaceName; 103 mInterfaceType = interfaceType; 104 mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService); 105 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 106 107 mInitialState = new InitialState(); 108 addState(mInitialState); 109 mTetheredState = new TetheredState(); 110 addState(mTetheredState); 111 mUnavailableState = new UnavailableState(); 112 addState(mUnavailableState); 113 114 setInitialState(mInitialState); 115 } 116 interfaceType()117 public int interfaceType() { 118 return mInterfaceType; 119 } 120 121 // configured when we start tethering and unconfig'd on error or conclusion configureIfaceIp(boolean enabled)122 private boolean configureIfaceIp(boolean enabled) { 123 if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")"); 124 125 String ipAsString = null; 126 int prefixLen = 0; 127 if (mInterfaceType == ConnectivityManager.TETHERING_USB) { 128 ipAsString = USB_NEAR_IFACE_ADDR; 129 prefixLen = USB_PREFIX_LENGTH; 130 } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { 131 ipAsString = WIFI_HOST_IFACE_ADDR; 132 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; 133 } else { 134 // Nothing to do, BT does this elsewhere. 135 return true; 136 } 137 138 InterfaceConfiguration ifcg = null; 139 try { 140 ifcg = mNMService.getInterfaceConfig(mIfaceName); 141 if (ifcg != null) { 142 InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString); 143 ifcg.setLinkAddress(new LinkAddress(addr, prefixLen)); 144 if (enabled) { 145 ifcg.setInterfaceUp(); 146 } else { 147 ifcg.setInterfaceDown(); 148 } 149 ifcg.clearFlag("running"); 150 mNMService.setInterfaceConfig(mIfaceName, ifcg); 151 } 152 } catch (Exception e) { 153 Log.e(TAG, "Error configuring interface " + mIfaceName, e); 154 return false; 155 } 156 157 return true; 158 } 159 maybeLogMessage(State state, int what)160 private void maybeLogMessage(State state, int what) { 161 if (DBG) { 162 Log.d(TAG, state.getName() + " got " + 163 sMagicDecoderRing.get(what, Integer.toString(what))); 164 } 165 } 166 167 class InitialState extends State { 168 @Override enter()169 public void enter() { 170 mTetherController.notifyInterfaceStateChange( 171 mIfaceName, TetherInterfaceStateMachine.this, 172 IControlsTethering.STATE_AVAILABLE, mLastError); 173 } 174 175 @Override processMessage(Message message)176 public boolean processMessage(Message message) { 177 maybeLogMessage(this, message.what); 178 boolean retValue = true; 179 switch (message.what) { 180 case CMD_TETHER_REQUESTED: 181 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 182 transitionTo(mTetheredState); 183 break; 184 case CMD_INTERFACE_DOWN: 185 transitionTo(mUnavailableState); 186 break; 187 case CMD_IPV6_TETHER_UPDATE: 188 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties( 189 (LinkProperties) message.obj); 190 break; 191 default: 192 retValue = false; 193 break; 194 } 195 return retValue; 196 } 197 } 198 199 class TetheredState extends State { 200 @Override enter()201 public void enter() { 202 if (!configureIfaceIp(true)) { 203 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; 204 transitionTo(mInitialState); 205 return; 206 } 207 208 try { 209 mNMService.tetherInterface(mIfaceName); 210 } catch (Exception e) { 211 Log.e(TAG, "Error Tethering: " + e.toString()); 212 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; 213 transitionTo(mInitialState); 214 return; 215 } 216 217 if (!mIPv6TetherSvc.start()) { 218 Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices"); 219 } 220 221 if (DBG) Log.d(TAG, "Tethered " + mIfaceName); 222 mTetherController.notifyInterfaceStateChange( 223 mIfaceName, TetherInterfaceStateMachine.this, 224 IControlsTethering.STATE_TETHERED, mLastError); 225 } 226 227 @Override exit()228 public void exit() { 229 // Note that at this point, we're leaving the tethered state. We can fail any 230 // of these operations, but it doesn't really change that we have to try them 231 // all in sequence. 232 mIPv6TetherSvc.stop(); 233 cleanupUpstream(); 234 235 try { 236 mNMService.untetherInterface(mIfaceName); 237 } catch (Exception ee) { 238 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; 239 Log.e(TAG, "Failed to untether interface: " + ee.toString()); 240 } 241 242 configureIfaceIp(false); 243 } 244 cleanupUpstream()245 private void cleanupUpstream() { 246 if (mMyUpstreamIfaceName != null) { 247 // note that we don't care about errors here. 248 // sometimes interfaces are gone before we get 249 // to remove their rules, which generates errors. 250 // just do the best we can. 251 try { 252 // about to tear down NAT; gather remaining statistics 253 mStatsService.forceUpdate(); 254 } catch (Exception e) { 255 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString()); 256 } 257 try { 258 mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName); 259 } catch (Exception e) { 260 if (VDBG) Log.e( 261 TAG, "Exception in removeInterfaceForward: " + e.toString()); 262 } 263 try { 264 mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName); 265 } catch (Exception e) { 266 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString()); 267 } 268 mMyUpstreamIfaceName = null; 269 } 270 return; 271 } 272 273 @Override processMessage(Message message)274 public boolean processMessage(Message message) { 275 maybeLogMessage(this, message.what); 276 boolean retValue = true; 277 switch (message.what) { 278 case CMD_TETHER_UNREQUESTED: 279 transitionTo(mInitialState); 280 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName); 281 break; 282 case CMD_INTERFACE_DOWN: 283 transitionTo(mUnavailableState); 284 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName); 285 break; 286 case CMD_TETHER_CONNECTION_CHANGED: 287 String newUpstreamIfaceName = (String)(message.obj); 288 if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) || 289 (mMyUpstreamIfaceName != null && 290 mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) { 291 if (VDBG) Log.d(TAG, "Connection changed noop - dropping"); 292 break; 293 } 294 cleanupUpstream(); 295 if (newUpstreamIfaceName != null) { 296 try { 297 mNMService.enableNat(mIfaceName, newUpstreamIfaceName); 298 mNMService.startInterfaceForwarding(mIfaceName, 299 newUpstreamIfaceName); 300 } catch (Exception e) { 301 Log.e(TAG, "Exception enabling Nat: " + e.toString()); 302 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; 303 transitionTo(mInitialState); 304 return true; 305 } 306 } 307 mMyUpstreamIfaceName = newUpstreamIfaceName; 308 break; 309 case CMD_IPV6_TETHER_UPDATE: 310 mIPv6TetherSvc.updateUpstreamIPv6LinkProperties( 311 (LinkProperties) message.obj); 312 break; 313 case CMD_IP_FORWARDING_ENABLE_ERROR: 314 case CMD_IP_FORWARDING_DISABLE_ERROR: 315 case CMD_START_TETHERING_ERROR: 316 case CMD_STOP_TETHERING_ERROR: 317 case CMD_SET_DNS_FORWARDERS_ERROR: 318 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR; 319 transitionTo(mInitialState); 320 break; 321 default: 322 retValue = false; 323 break; 324 } 325 return retValue; 326 } 327 } 328 329 /** 330 * This state is terminal for the per interface state machine. At this 331 * point, the master state machine should have removed this interface 332 * specific state machine from its list of possible recipients of 333 * tethering requests. The state machine itself will hang around until 334 * the garbage collector finds it. 335 */ 336 class UnavailableState extends State { 337 @Override enter()338 public void enter() { 339 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 340 mTetherController.notifyInterfaceStateChange( 341 mIfaceName, TetherInterfaceStateMachine.this, 342 IControlsTethering.STATE_UNAVAILABLE, mLastError); 343 } 344 } 345 } 346