• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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