OSDN Git Service

Fix Bluetooth tethering
[android-x86/frameworks-base.git] / services / java / com / android / server / connectivity / Tethering.java
1 /*
2  * Copyright (C) 2010 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;
18
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 import android.hardware.usb.UsbManager;
29 import android.net.ConnectivityManager;
30 import android.net.IConnectivityManager;
31 import android.net.INetworkManagementEventObserver;
32 import android.net.INetworkStatsService;
33 import android.net.InterfaceConfiguration;
34 import android.net.LinkAddress;
35 import android.net.LinkProperties;
36 import android.net.NetworkInfo;
37 import android.net.NetworkUtils;
38 import android.net.RouteInfo;
39 import android.os.Binder;
40 import android.os.INetworkManagementService;
41 import android.os.Looper;
42 import android.os.Message;
43 import android.os.RemoteException;
44 import android.os.UserHandle;
45 import android.provider.Settings;
46 import android.util.Log;
47
48 import com.android.internal.telephony.Phone;
49 import com.android.internal.telephony.PhoneConstants;
50 import com.android.internal.util.IState;
51 import com.android.internal.util.State;
52 import com.android.internal.util.StateMachine;
53 import com.android.server.IoThread;
54 import com.google.android.collect.Lists;
55
56 import java.io.FileDescriptor;
57 import java.io.PrintWriter;
58 import java.net.InetAddress;
59 import java.net.Inet4Address;
60 import java.util.ArrayList;
61 import java.util.Collection;
62 import java.util.HashMap;
63 import java.util.Iterator;
64 import java.util.Set;
65
66 /**
67  * @hide
68  *
69  * Timeout
70  *
71  * TODO - look for parent classes and code sharing
72  */
73 public class Tethering extends INetworkManagementEventObserver.Stub {
74
75     private Context mContext;
76     private final static String TAG = "Tethering";
77     private final static boolean DBG = true;
78     private final static boolean VDBG = false;
79
80     // TODO - remove both of these - should be part of interface inspection/selection stuff
81     private String[] mTetherableUsbRegexs;
82     private String[] mTetherableWifiRegexs;
83     private String[] mTetherableBluetoothRegexs;
84     private Collection<Integer> mUpstreamIfaceTypes;
85
86     // used to synchronize public access to members
87     private Object mPublicSync;
88
89     private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
90     private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
91     private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
92
93     // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
94     // upstream type list and the DUN_REQUIRED secure-setting
95     private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
96
97     private final INetworkManagementService mNMService;
98     private final INetworkStatsService mStatsService;
99     private final IConnectivityManager mConnService;
100     private Looper mLooper;
101
102     private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
103
104     private BroadcastReceiver mStateReceiver;
105
106     private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
107     private static final int USB_PREFIX_LENGTH        = 24;
108
109     // USB is  192.168.42.1 and 255.255.255.0
110     // Wifi is 192.168.43.1 and 255.255.255.0
111     // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
112     // with 255.255.255.0
113
114     private String[] mDhcpRange;
115     private static final String[] DHCP_DEFAULT_RANGE = {
116         "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
117         "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
118         "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
119         "192.168.48.2", "192.168.48.254",
120     };
121
122     private String[] mDefaultDnsServers;
123     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
124     private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
125
126     private StateMachine mTetherMasterSM;
127
128     private Notification mTetheredNotification;
129
130     private boolean mRndisEnabled;       // track the RNDIS function enabled state
131     private boolean mUsbTetherRequested; // true if USB tethering should be started
132                                          // when RNDIS is enabled
133
134     public Tethering(Context context, INetworkManagementService nmService,
135             INetworkStatsService statsService, IConnectivityManager connService, Looper looper) {
136         mContext = context;
137         mNMService = nmService;
138         mStatsService = statsService;
139         mConnService = connService;
140         mLooper = looper;
141
142         mPublicSync = new Object();
143
144         mIfaces = new HashMap<String, TetherInterfaceSM>();
145
146         // make our own thread so we don't anr the system
147         mLooper = IoThread.get().getLooper();
148         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
149         mTetherMasterSM.start();
150
151         mStateReceiver = new StateReceiver();
152         IntentFilter filter = new IntentFilter();
153         filter.addAction(UsbManager.ACTION_USB_STATE);
154         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
155         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
156         mContext.registerReceiver(mStateReceiver, filter);
157
158         filter = new IntentFilter();
159         filter.addAction(Intent.ACTION_MEDIA_SHARED);
160         filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
161         filter.addDataScheme("file");
162         mContext.registerReceiver(mStateReceiver, filter);
163
164         mDhcpRange = context.getResources().getStringArray(
165                 com.android.internal.R.array.config_tether_dhcp_range);
166         if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
167             mDhcpRange = DHCP_DEFAULT_RANGE;
168         }
169
170         // load device config info
171         updateConfiguration();
172
173         // TODO - remove and rely on real notifications of the current iface
174         mDefaultDnsServers = new String[2];
175         mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
176         mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
177     }
178
179     void updateConfiguration() {
180         String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
181                 com.android.internal.R.array.config_tether_usb_regexs);
182         String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
183                 com.android.internal.R.array.config_tether_wifi_regexs);
184         String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
185                 com.android.internal.R.array.config_tether_bluetooth_regexs);
186
187         int ifaceTypes[] = mContext.getResources().getIntArray(
188                 com.android.internal.R.array.config_tether_upstream_types);
189         Collection<Integer> upstreamIfaceTypes = new ArrayList();
190         for (int i : ifaceTypes) {
191             upstreamIfaceTypes.add(new Integer(i));
192         }
193
194         synchronized (mPublicSync) {
195             mTetherableUsbRegexs = tetherableUsbRegexs;
196             mTetherableWifiRegexs = tetherableWifiRegexs;
197             mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
198             mUpstreamIfaceTypes = upstreamIfaceTypes;
199         }
200
201         // check if the upstream type list needs to be modified due to secure-settings
202         checkDunRequired();
203     }
204
205     public void interfaceStatusChanged(String iface, boolean up) {
206         if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
207         boolean found = false;
208         boolean usb = false;
209         synchronized (mPublicSync) {
210             if (isWifi(iface)) {
211                 found = true;
212             } else if (isUsb(iface)) {
213                 found = true;
214                 usb = true;
215             } else if (isBluetooth(iface)) {
216                 found = true;
217             }
218             if (found == false) return;
219
220             TetherInterfaceSM sm = mIfaces.get(iface);
221             if (up) {
222                 if (sm == null) {
223                     sm = new TetherInterfaceSM(iface, mLooper, usb);
224                     mIfaces.put(iface, sm);
225                     sm.start();
226                 }
227             } else {
228                 if (isUsb(iface)) {
229                     // ignore usb0 down after enabling RNDIS
230                     // we will handle disconnect in interfaceRemoved instead
231                     if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
232                 } else if (isBluetooth(iface)) {
233                     // ignore interface down for bt liskstate change
234                     // disconnect will only be handled in interfaceRemoved
235                     if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
236                 } else if (sm != null) {
237                     sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
238                     mIfaces.remove(iface);
239                 }
240             }
241         }
242     }
243
244     public void interfaceLinkStateChanged(String iface, boolean up) {
245         if (VDBG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
246         interfaceStatusChanged(iface, up);
247     }
248
249     private boolean isUsb(String iface) {
250         synchronized (mPublicSync) {
251             for (String regex : mTetherableUsbRegexs) {
252                 if (iface.matches(regex)) return true;
253             }
254             return false;
255         }
256     }
257
258     public boolean isWifi(String iface) {
259         synchronized (mPublicSync) {
260             for (String regex : mTetherableWifiRegexs) {
261                 if (iface.matches(regex)) return true;
262             }
263             return false;
264         }
265     }
266
267     public boolean isBluetooth(String iface) {
268         synchronized (mPublicSync) {
269             for (String regex : mTetherableBluetoothRegexs) {
270                 if (iface.matches(regex)) return true;
271             }
272             return false;
273         }
274     }
275
276     public void interfaceAdded(String iface) {
277         if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
278         boolean found = false;
279         boolean usb = false;
280         synchronized (mPublicSync) {
281             if (isWifi(iface)) {
282                 found = true;
283             }
284             if (isUsb(iface)) {
285                 found = true;
286                 usb = true;
287             }
288             if (isBluetooth(iface)) {
289                 found = true;
290             }
291             if (found == false) {
292                 if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
293                 return;
294             }
295
296             TetherInterfaceSM sm = mIfaces.get(iface);
297             if (sm != null) {
298                 if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
299                 return;
300             }
301             sm = new TetherInterfaceSM(iface, mLooper, usb);
302             mIfaces.put(iface, sm);
303             sm.start();
304         }
305     }
306
307     public void interfaceRemoved(String iface) {
308         if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
309         synchronized (mPublicSync) {
310             TetherInterfaceSM sm = mIfaces.get(iface);
311             if (sm == null) {
312                 if (VDBG) {
313                     Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
314                 }
315                 return;
316             }
317             sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
318             mIfaces.remove(iface);
319         }
320     }
321
322     public void addressUpdated(String address, String iface, int flags, int scope) {}
323
324     public void addressRemoved(String address, String iface, int flags, int scope) {}
325
326     public void limitReached(String limitName, String iface) {}
327
328     public void interfaceClassDataActivityChanged(String label, boolean active) {}
329
330     public int tether(String iface) {
331         if (DBG) Log.d(TAG, "Tethering " + iface);
332         TetherInterfaceSM sm = null;
333         synchronized (mPublicSync) {
334             sm = mIfaces.get(iface);
335         }
336         if (sm == null) {
337             Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
338             return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
339         }
340         if (!sm.isAvailable() && !sm.isErrored()) {
341             Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
342             return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
343         }
344         sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
345         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
346     }
347
348     public int untether(String iface) {
349         if (DBG) Log.d(TAG, "Untethering " + iface);
350         TetherInterfaceSM sm = null;
351         synchronized (mPublicSync) {
352             sm = mIfaces.get(iface);
353         }
354         if (sm == null) {
355             Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
356             return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
357         }
358         if (sm.isErrored()) {
359             Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
360             return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
361         }
362         sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
363         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
364     }
365
366     public int getLastTetherError(String iface) {
367         TetherInterfaceSM sm = null;
368         synchronized (mPublicSync) {
369             sm = mIfaces.get(iface);
370             if (sm == null) {
371                 Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
372                         ", ignoring");
373                 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
374             }
375             return sm.getLastError();
376         }
377     }
378
379     // TODO - move all private methods used only by the state machine into the state machine
380     // to clarify what needs synchronized protection.
381     private void sendTetherStateChangedBroadcast() {
382         try {
383             if (!mConnService.isTetheringSupported()) return;
384         } catch (RemoteException e) {
385             return;
386         }
387
388         ArrayList<String> availableList = new ArrayList<String>();
389         ArrayList<String> activeList = new ArrayList<String>();
390         ArrayList<String> erroredList = new ArrayList<String>();
391
392         boolean wifiTethered = false;
393         boolean usbTethered = false;
394         boolean bluetoothTethered = false;
395
396         synchronized (mPublicSync) {
397             Set ifaces = mIfaces.keySet();
398             for (Object iface : ifaces) {
399                 TetherInterfaceSM sm = mIfaces.get(iface);
400                 if (sm != null) {
401                     if (sm.isErrored()) {
402                         erroredList.add((String)iface);
403                     } else if (sm.isAvailable()) {
404                         availableList.add((String)iface);
405                     } else if (sm.isTethered()) {
406                         if (isUsb((String)iface)) {
407                             usbTethered = true;
408                         } else if (isWifi((String)iface)) {
409                             wifiTethered = true;
410                       } else if (isBluetooth((String)iface)) {
411                             bluetoothTethered = true;
412                         }
413                         activeList.add((String)iface);
414                     }
415                 }
416             }
417         }
418         Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
419         broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
420                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
421         broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
422                 availableList);
423         broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
424         broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
425                 erroredList);
426         mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
427         if (DBG) {
428             Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
429                     activeList.size() + ", " + erroredList.size());
430         }
431
432         if (usbTethered) {
433             if (wifiTethered || bluetoothTethered) {
434                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
435             } else {
436                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
437             }
438         } else if (wifiTethered) {
439             if (bluetoothTethered) {
440                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
441             } else {
442                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
443             }
444         } else if (bluetoothTethered) {
445             showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
446         } else {
447             clearTetheredNotification();
448         }
449     }
450
451     private void showTetheredNotification(int icon) {
452         NotificationManager notificationManager =
453                 (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
454         if (notificationManager == null) {
455             return;
456         }
457
458         if (mTetheredNotification != null) {
459             if (mTetheredNotification.icon == icon) {
460                 return;
461             }
462             notificationManager.cancelAsUser(null, mTetheredNotification.icon,
463                     UserHandle.ALL);
464         }
465
466         Intent intent = new Intent();
467         intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
468         intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
469
470         PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
471                 null, UserHandle.CURRENT);
472
473         Resources r = Resources.getSystem();
474         CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
475         CharSequence message = r.getText(com.android.internal.R.string.
476                 tethered_notification_message);
477
478         if (mTetheredNotification == null) {
479             mTetheredNotification = new Notification();
480             mTetheredNotification.when = 0;
481         }
482         mTetheredNotification.icon = icon;
483         mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
484         mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
485         mTetheredNotification.tickerText = title;
486         mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
487
488         notificationManager.notifyAsUser(null, mTetheredNotification.icon,
489                 mTetheredNotification, UserHandle.ALL);
490     }
491
492     private void clearTetheredNotification() {
493         NotificationManager notificationManager =
494             (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
495         if (notificationManager != null && mTetheredNotification != null) {
496             notificationManager.cancelAsUser(null, mTetheredNotification.icon,
497                     UserHandle.ALL);
498             mTetheredNotification = null;
499         }
500     }
501
502     private class StateReceiver extends BroadcastReceiver {
503         public void onReceive(Context content, Intent intent) {
504             String action = intent.getAction();
505             if (action.equals(UsbManager.ACTION_USB_STATE)) {
506                 synchronized (Tethering.this.mPublicSync) {
507                     boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
508                     mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
509                     // start tethering if we have a request pending
510                     if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
511                         tetherUsb(true);
512                     }
513                     mUsbTetherRequested = false;
514                 }
515             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
516                 NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
517                         ConnectivityManager.EXTRA_NETWORK_INFO);
518                 if (networkInfo != null &&
519                         networkInfo.getDetailedState() != NetworkInfo.DetailedState.FAILED) {
520                     if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
521                     mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
522                 }
523             } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
524                 updateConfiguration();
525             }
526         }
527     }
528
529     private void tetherUsb(boolean enable) {
530         if (VDBG) Log.d(TAG, "tetherUsb " + enable);
531
532         String[] ifaces = new String[0];
533         try {
534             ifaces = mNMService.listInterfaces();
535         } catch (Exception e) {
536             Log.e(TAG, "Error listing Interfaces", e);
537             return;
538         }
539         for (String iface : ifaces) {
540             if (isUsb(iface)) {
541                 int result = (enable ? tether(iface) : untether(iface));
542                 if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
543                     return;
544                 }
545             }
546         }
547         Log.e(TAG, "unable start or stop USB tethering");
548     }
549
550     // configured when we start tethering and unconfig'd on error or conclusion
551     private boolean configureUsbIface(boolean enabled) {
552         if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")");
553
554         // toggle the USB interfaces
555         String[] ifaces = new String[0];
556         try {
557             ifaces = mNMService.listInterfaces();
558         } catch (Exception e) {
559             Log.e(TAG, "Error listing Interfaces", e);
560             return false;
561         }
562         for (String iface : ifaces) {
563             if (isUsb(iface)) {
564                 InterfaceConfiguration ifcg = null;
565                 try {
566                     ifcg = mNMService.getInterfaceConfig(iface);
567                     if (ifcg != null) {
568                         InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR);
569                         ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH));
570                         if (enabled) {
571                             ifcg.setInterfaceUp();
572                         } else {
573                             ifcg.setInterfaceDown();
574                         }
575                         ifcg.clearFlag("running");
576                         mNMService.setInterfaceConfig(iface, ifcg);
577                     }
578                 } catch (Exception e) {
579                     Log.e(TAG, "Error configuring interface " + iface, e);
580                     return false;
581                 }
582             }
583          }
584
585         return true;
586     }
587
588     // TODO - return copies so people can't tamper
589     public String[] getTetherableUsbRegexs() {
590         return mTetherableUsbRegexs;
591     }
592
593     public String[] getTetherableWifiRegexs() {
594         return mTetherableWifiRegexs;
595     }
596
597     public String[] getTetherableBluetoothRegexs() {
598         return mTetherableBluetoothRegexs;
599     }
600
601     public int setUsbTethering(boolean enable) {
602         if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
603         UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
604
605         synchronized (mPublicSync) {
606             if (enable) {
607                 if (mRndisEnabled) {
608                     tetherUsb(true);
609                 } else {
610                     mUsbTetherRequested = true;
611                     usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
612                 }
613             } else {
614                 tetherUsb(false);
615                 if (mRndisEnabled) {
616                     usbManager.setCurrentFunction(null, false);
617                 }
618                 mUsbTetherRequested = false;
619             }
620         }
621         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
622     }
623
624     public int[] getUpstreamIfaceTypes() {
625         int values[];
626         synchronized (mPublicSync) {
627             updateConfiguration();  // TODO - remove?
628             values = new int[mUpstreamIfaceTypes.size()];
629             Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
630             for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
631                 values[i] = iterator.next();
632             }
633         }
634         return values;
635     }
636
637     public void checkDunRequired() {
638         int secureSetting = Settings.Global.getInt(mContext.getContentResolver(),
639                 Settings.Global.TETHER_DUN_REQUIRED, 2);
640         synchronized (mPublicSync) {
641             // 2 = not set, 0 = DUN not required, 1 = DUN required
642             if (secureSetting != 2) {
643                 int requiredApn = (secureSetting == 1 ?
644                         ConnectivityManager.TYPE_MOBILE_DUN :
645                         ConnectivityManager.TYPE_MOBILE_HIPRI);
646                 if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
647                     while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
648                         mUpstreamIfaceTypes.remove(MOBILE_TYPE);
649                     }
650                     while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
651                         mUpstreamIfaceTypes.remove(HIPRI_TYPE);
652                     }
653                     if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
654                         mUpstreamIfaceTypes.add(DUN_TYPE);
655                     }
656                 } else {
657                     while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
658                         mUpstreamIfaceTypes.remove(DUN_TYPE);
659                     }
660                     if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
661                         mUpstreamIfaceTypes.add(MOBILE_TYPE);
662                     }
663                     if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
664                         mUpstreamIfaceTypes.add(HIPRI_TYPE);
665                     }
666                 }
667             }
668             if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
669                 mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
670             } else {
671                 mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
672             }
673         }
674     }
675
676     // TODO review API - maybe return ArrayList<String> here and below?
677     public String[] getTetheredIfaces() {
678         ArrayList<String> list = new ArrayList<String>();
679         synchronized (mPublicSync) {
680             Set keys = mIfaces.keySet();
681             for (Object key : keys) {
682                 TetherInterfaceSM sm = mIfaces.get(key);
683                 if (sm.isTethered()) {
684                     list.add((String)key);
685                 }
686             }
687         }
688         String[] retVal = new String[list.size()];
689         for (int i=0; i < list.size(); i++) {
690             retVal[i] = list.get(i);
691         }
692         return retVal;
693     }
694
695     public String[] getTetherableIfaces() {
696         ArrayList<String> list = new ArrayList<String>();
697         synchronized (mPublicSync) {
698             Set keys = mIfaces.keySet();
699             for (Object key : keys) {
700                 TetherInterfaceSM sm = mIfaces.get(key);
701                 if (sm.isAvailable()) {
702                     list.add((String)key);
703                 }
704             }
705         }
706         String[] retVal = new String[list.size()];
707         for (int i=0; i < list.size(); i++) {
708             retVal[i] = list.get(i);
709         }
710         return retVal;
711     }
712
713     public String[] getErroredIfaces() {
714         ArrayList<String> list = new ArrayList<String>();
715         synchronized (mPublicSync) {
716             Set keys = mIfaces.keySet();
717             for (Object key : keys) {
718                 TetherInterfaceSM sm = mIfaces.get(key);
719                 if (sm.isErrored()) {
720                     list.add((String)key);
721                 }
722             }
723         }
724         String[] retVal = new String[list.size()];
725         for (int i= 0; i< list.size(); i++) {
726             retVal[i] = list.get(i);
727         }
728         return retVal;
729     }
730
731     //TODO: Temporary handling upstream change triggered without
732     //      CONNECTIVITY_ACTION. Only to accomodate interface
733     //      switch during HO.
734     //      @see bug/4455071
735     public void handleTetherIfaceChange() {
736         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
737     }
738
739     class TetherInterfaceSM extends StateMachine {
740         // notification from the master SM that it's not in tether mode
741         static final int CMD_TETHER_MODE_DEAD            =  1;
742         // request from the user that it wants to tether
743         static final int CMD_TETHER_REQUESTED            =  2;
744         // request from the user that it wants to untether
745         static final int CMD_TETHER_UNREQUESTED          =  3;
746         // notification that this interface is down
747         static final int CMD_INTERFACE_DOWN              =  4;
748         // notification that this interface is up
749         static final int CMD_INTERFACE_UP                =  5;
750         // notification from the master SM that it had an error turning on cellular dun
751         static final int CMD_CELL_DUN_ERROR              =  6;
752         // notification from the master SM that it had trouble enabling IP Forwarding
753         static final int CMD_IP_FORWARDING_ENABLE_ERROR  =  7;
754         // notification from the master SM that it had trouble disabling IP Forwarding
755         static final int CMD_IP_FORWARDING_DISABLE_ERROR =  8;
756         // notification from the master SM that it had trouble staring tethering
757         static final int CMD_START_TETHERING_ERROR       =  9;
758         // notification from the master SM that it had trouble stopping tethering
759         static final int CMD_STOP_TETHERING_ERROR        = 10;
760         // notification from the master SM that it had trouble setting the DNS forwarders
761         static final int CMD_SET_DNS_FORWARDERS_ERROR    = 11;
762         // the upstream connection has changed
763         static final int CMD_TETHER_CONNECTION_CHANGED   = 12;
764
765         private State mDefaultState;
766
767         private State mInitialState;
768         private State mStartingState;
769         private State mTetheredState;
770
771         private State mUnavailableState;
772
773         private boolean mAvailable;
774         private boolean mTethered;
775         int mLastError;
776
777         String mIfaceName;
778         String mMyUpstreamIfaceName;  // may change over time
779
780         boolean mUsb;
781
782         TetherInterfaceSM(String name, Looper looper, boolean usb) {
783             super(name, looper);
784             mIfaceName = name;
785             mUsb = usb;
786             setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
787
788             mInitialState = new InitialState();
789             addState(mInitialState);
790             mStartingState = new StartingState();
791             addState(mStartingState);
792             mTetheredState = new TetheredState();
793             addState(mTetheredState);
794             mUnavailableState = new UnavailableState();
795             addState(mUnavailableState);
796
797             setInitialState(mInitialState);
798         }
799
800         public String toString() {
801             String res = new String();
802             res += mIfaceName + " - ";
803             IState current = getCurrentState();
804             if (current == mInitialState) res += "InitialState";
805             if (current == mStartingState) res += "StartingState";
806             if (current == mTetheredState) res += "TetheredState";
807             if (current == mUnavailableState) res += "UnavailableState";
808             if (mAvailable) res += " - Available";
809             if (mTethered) res += " - Tethered";
810             res += " - lastError =" + mLastError;
811             return res;
812         }
813
814         public int getLastError() {
815             synchronized (Tethering.this.mPublicSync) {
816                 return mLastError;
817             }
818         }
819
820         private void setLastError(int error) {
821             synchronized (Tethering.this.mPublicSync) {
822                 mLastError = error;
823
824                 if (isErrored()) {
825                     if (mUsb) {
826                         // note everything's been unwound by this point so nothing to do on
827                         // further error..
828                         Tethering.this.configureUsbIface(false);
829                     }
830                 }
831             }
832         }
833
834         public boolean isAvailable() {
835             synchronized (Tethering.this.mPublicSync) {
836                 return mAvailable;
837             }
838         }
839
840         private void setAvailable(boolean available) {
841             synchronized (Tethering.this.mPublicSync) {
842                 mAvailable = available;
843             }
844         }
845
846         public boolean isTethered() {
847             synchronized (Tethering.this.mPublicSync) {
848                 return mTethered;
849             }
850         }
851
852         private void setTethered(boolean tethered) {
853             synchronized (Tethering.this.mPublicSync) {
854                 mTethered = tethered;
855             }
856         }
857
858         public boolean isErrored() {
859             synchronized (Tethering.this.mPublicSync) {
860                 return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
861             }
862         }
863
864         class InitialState extends State {
865             @Override
866             public void enter() {
867                 setAvailable(true);
868                 setTethered(false);
869                 sendTetherStateChangedBroadcast();
870             }
871
872             @Override
873             public boolean processMessage(Message message) {
874                 if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
875                 boolean retValue = true;
876                 switch (message.what) {
877                     case CMD_TETHER_REQUESTED:
878                         setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
879                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
880                                 TetherInterfaceSM.this);
881                         transitionTo(mStartingState);
882                         break;
883                     case CMD_INTERFACE_DOWN:
884                         transitionTo(mUnavailableState);
885                         break;
886                     default:
887                         retValue = false;
888                         break;
889                 }
890                 return retValue;
891             }
892         }
893
894         class StartingState extends State {
895             @Override
896             public void enter() {
897                 setAvailable(false);
898                 if (mUsb) {
899                     if (!Tethering.this.configureUsbIface(true)) {
900                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
901                                 TetherInterfaceSM.this);
902                         setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
903
904                         transitionTo(mInitialState);
905                         return;
906                     }
907                 }
908                 sendTetherStateChangedBroadcast();
909
910                 // Skipping StartingState
911                 transitionTo(mTetheredState);
912             }
913             @Override
914             public boolean processMessage(Message message) {
915                 if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
916                 boolean retValue = true;
917                 switch (message.what) {
918                     // maybe a parent class?
919                     case CMD_TETHER_UNREQUESTED:
920                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
921                                 TetherInterfaceSM.this);
922                         if (mUsb) {
923                             if (!Tethering.this.configureUsbIface(false)) {
924                                 setLastErrorAndTransitionToInitialState(
925                                     ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
926                                 break;
927                             }
928                         }
929                         transitionTo(mInitialState);
930                         break;
931                     case CMD_CELL_DUN_ERROR:
932                     case CMD_IP_FORWARDING_ENABLE_ERROR:
933                     case CMD_IP_FORWARDING_DISABLE_ERROR:
934                     case CMD_START_TETHERING_ERROR:
935                     case CMD_STOP_TETHERING_ERROR:
936                     case CMD_SET_DNS_FORWARDERS_ERROR:
937                         setLastErrorAndTransitionToInitialState(
938                                 ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
939                         break;
940                     case CMD_INTERFACE_DOWN:
941                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
942                                 TetherInterfaceSM.this);
943                         transitionTo(mUnavailableState);
944                         break;
945                     default:
946                         retValue = false;
947                 }
948                 return retValue;
949             }
950         }
951
952         class TetheredState extends State {
953             @Override
954             public void enter() {
955                 try {
956                     mNMService.tetherInterface(mIfaceName);
957                 } catch (Exception e) {
958                     Log.e(TAG, "Error Tethering: " + e.toString());
959                     setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
960
961                     transitionTo(mInitialState);
962                     return;
963                 }
964                 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
965                 setAvailable(false);
966                 setTethered(true);
967                 sendTetherStateChangedBroadcast();
968             }
969
970             private void cleanupUpstream() {
971                 if (mMyUpstreamIfaceName != null) {
972                     // note that we don't care about errors here.
973                     // sometimes interfaces are gone before we get
974                     // to remove their rules, which generates errors.
975                     // just do the best we can.
976                     try {
977                         // about to tear down NAT; gather remaining statistics
978                         mStatsService.forceUpdate();
979                     } catch (Exception e) {
980                         if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
981                     }
982                     try {
983                         mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
984                     } catch (Exception e) {
985                         if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
986                     }
987                     mMyUpstreamIfaceName = null;
988                 }
989                 return;
990             }
991
992             @Override
993             public boolean processMessage(Message message) {
994                 if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
995                 boolean retValue = true;
996                 boolean error = false;
997                 switch (message.what) {
998                     case CMD_TETHER_UNREQUESTED:
999                     case CMD_INTERFACE_DOWN:
1000                         cleanupUpstream();
1001                         try {
1002                             mNMService.untetherInterface(mIfaceName);
1003                         } catch (Exception e) {
1004                             setLastErrorAndTransitionToInitialState(
1005                                     ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1006                             break;
1007                         }
1008                         mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1009                                 TetherInterfaceSM.this);
1010                         if (message.what == CMD_TETHER_UNREQUESTED) {
1011                             if (mUsb) {
1012                                 if (!Tethering.this.configureUsbIface(false)) {
1013                                     setLastError(
1014                                             ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1015                                 }
1016                             }
1017                             transitionTo(mInitialState);
1018                         } else if (message.what == CMD_INTERFACE_DOWN) {
1019                             transitionTo(mUnavailableState);
1020                         }
1021                         if (DBG) Log.d(TAG, "Untethered " + mIfaceName);
1022                         break;
1023                     case CMD_TETHER_CONNECTION_CHANGED:
1024                         String newUpstreamIfaceName = (String)(message.obj);
1025                         if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
1026                                 (mMyUpstreamIfaceName != null &&
1027                                 mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
1028                             if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
1029                             break;
1030                         }
1031                         cleanupUpstream();
1032                         if (newUpstreamIfaceName != null) {
1033                             try {
1034                                 mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
1035                             } catch (Exception e) {
1036                                 Log.e(TAG, "Exception enabling Nat: " + e.toString());
1037                                 try {
1038                                     mNMService.untetherInterface(mIfaceName);
1039                                 } catch (Exception ee) {}
1040
1041                                 setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
1042                                 transitionTo(mInitialState);
1043                                 return true;
1044                             }
1045                         }
1046                         mMyUpstreamIfaceName = newUpstreamIfaceName;
1047                         break;
1048                     case CMD_CELL_DUN_ERROR:
1049                     case CMD_IP_FORWARDING_ENABLE_ERROR:
1050                     case CMD_IP_FORWARDING_DISABLE_ERROR:
1051                     case CMD_START_TETHERING_ERROR:
1052                     case CMD_STOP_TETHERING_ERROR:
1053                     case CMD_SET_DNS_FORWARDERS_ERROR:
1054                         error = true;
1055                         // fall through
1056                     case CMD_TETHER_MODE_DEAD:
1057                         cleanupUpstream();
1058                         try {
1059                             mNMService.untetherInterface(mIfaceName);
1060                         } catch (Exception e) {
1061                             setLastErrorAndTransitionToInitialState(
1062                                     ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1063                             break;
1064                         }
1065                         if (error) {
1066                             setLastErrorAndTransitionToInitialState(
1067                                     ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
1068                             break;
1069                         }
1070                         if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
1071                         sendTetherStateChangedBroadcast();
1072                         if (mUsb) {
1073                             if (!Tethering.this.configureUsbIface(false)) {
1074                                 setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1075                             }
1076                         }
1077                         transitionTo(mInitialState);
1078                         break;
1079                     default:
1080                         retValue = false;
1081                         break;
1082                 }
1083                 return retValue;
1084             }
1085         }
1086
1087         class UnavailableState extends State {
1088             @Override
1089             public void enter() {
1090                 setAvailable(false);
1091                 setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1092                 setTethered(false);
1093                 sendTetherStateChangedBroadcast();
1094             }
1095             @Override
1096             public boolean processMessage(Message message) {
1097                 boolean retValue = true;
1098                 switch (message.what) {
1099                     case CMD_INTERFACE_UP:
1100                         transitionTo(mInitialState);
1101                         break;
1102                     default:
1103                         retValue = false;
1104                         break;
1105                 }
1106                 return retValue;
1107             }
1108         }
1109
1110         void setLastErrorAndTransitionToInitialState(int error) {
1111             setLastError(error);
1112             transitionTo(mInitialState);
1113         }
1114
1115     }
1116
1117     class TetherMasterSM extends StateMachine {
1118         // an interface SM has requested Tethering
1119         static final int CMD_TETHER_MODE_REQUESTED   = 1;
1120         // an interface SM has unrequested Tethering
1121         static final int CMD_TETHER_MODE_UNREQUESTED = 2;
1122         // upstream connection change - do the right thing
1123         static final int CMD_UPSTREAM_CHANGED        = 3;
1124         // we received notice that the cellular DUN connection is up
1125         static final int CMD_CELL_CONNECTION_RENEW   = 4;
1126         // we don't have a valid upstream conn, check again after a delay
1127         static final int CMD_RETRY_UPSTREAM          = 5;
1128
1129         // This indicates what a timeout event relates to.  A state that
1130         // sends itself a delayed timeout event and handles incoming timeout events
1131         // should inc this when it is entered and whenever it sends a new timeout event.
1132         // We do not flush the old ones.
1133         private int mSequenceNumber;
1134
1135         private State mInitialState;
1136         private State mTetherModeAliveState;
1137
1138         private State mSetIpForwardingEnabledErrorState;
1139         private State mSetIpForwardingDisabledErrorState;
1140         private State mStartTetheringErrorState;
1141         private State mStopTetheringErrorState;
1142         private State mSetDnsForwardersErrorState;
1143
1144         private ArrayList<TetherInterfaceSM> mNotifyList;
1145
1146         private int mCurrentConnectionSequence;
1147         private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1148
1149         private String mUpstreamIfaceName = null;
1150
1151         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
1152         private static final int CELL_CONNECTION_RENEW_MS    = 40000;
1153
1154         TetherMasterSM(String name, Looper looper) {
1155             super(name, looper);
1156
1157             //Add states
1158             mInitialState = new InitialState();
1159             addState(mInitialState);
1160             mTetherModeAliveState = new TetherModeAliveState();
1161             addState(mTetherModeAliveState);
1162
1163             mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1164             addState(mSetIpForwardingEnabledErrorState);
1165             mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1166             addState(mSetIpForwardingDisabledErrorState);
1167             mStartTetheringErrorState = new StartTetheringErrorState();
1168             addState(mStartTetheringErrorState);
1169             mStopTetheringErrorState = new StopTetheringErrorState();
1170             addState(mStopTetheringErrorState);
1171             mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1172             addState(mSetDnsForwardersErrorState);
1173
1174             mNotifyList = new ArrayList<TetherInterfaceSM>();
1175             setInitialState(mInitialState);
1176         }
1177
1178         class TetherMasterUtilState extends State {
1179             protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
1180             protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE     = false;
1181
1182             @Override
1183             public boolean processMessage(Message m) {
1184                 return false;
1185             }
1186             protected String enableString(int apnType) {
1187                 switch (apnType) {
1188                 case ConnectivityManager.TYPE_MOBILE_DUN:
1189                     return Phone.FEATURE_ENABLE_DUN_ALWAYS;
1190                 case ConnectivityManager.TYPE_MOBILE:
1191                 case ConnectivityManager.TYPE_MOBILE_HIPRI:
1192                     return Phone.FEATURE_ENABLE_HIPRI;
1193                 }
1194                 return null;
1195             }
1196             protected boolean turnOnUpstreamMobileConnection(int apnType) {
1197                 boolean retValue = true;
1198                 if (apnType == ConnectivityManager.TYPE_NONE) return false;
1199                 if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
1200                 int result = PhoneConstants.APN_REQUEST_FAILED;
1201                 String enableString = enableString(apnType);
1202                 if (enableString == null) return false;
1203                 try {
1204                     result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1205                             enableString, new Binder());
1206                 } catch (Exception e) {
1207                 }
1208                 switch (result) {
1209                 case PhoneConstants.APN_ALREADY_ACTIVE:
1210                 case PhoneConstants.APN_REQUEST_STARTED:
1211                     mMobileApnReserved = apnType;
1212                     Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
1213                     m.arg1 = ++mCurrentConnectionSequence;
1214                     sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
1215                     break;
1216                 case PhoneConstants.APN_REQUEST_FAILED:
1217                 default:
1218                     retValue = false;
1219                     break;
1220                 }
1221
1222                 return retValue;
1223             }
1224             protected boolean turnOffUpstreamMobileConnection() {
1225                 // ignore pending renewal requests
1226                 ++mCurrentConnectionSequence;
1227                 if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
1228                     try {
1229                         mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1230                                 enableString(mMobileApnReserved));
1231                     } catch (Exception e) {
1232                         return false;
1233                     }
1234                     mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1235                 }
1236                 return true;
1237             }
1238             protected boolean turnOnMasterTetherSettings() {
1239                 try {
1240                     mNMService.setIpForwardingEnabled(true);
1241                 } catch (Exception e) {
1242                     transitionTo(mSetIpForwardingEnabledErrorState);
1243                     return false;
1244                 }
1245                 try {
1246                     mNMService.startTethering(mDhcpRange);
1247                 } catch (Exception e) {
1248                     try {
1249                         mNMService.stopTethering();
1250                         mNMService.startTethering(mDhcpRange);
1251                     } catch (Exception ee) {
1252                         transitionTo(mStartTetheringErrorState);
1253                         return false;
1254                     }
1255                 }
1256                 try {
1257                     mNMService.setDnsForwarders(mDefaultDnsServers);
1258                 } catch (Exception e) {
1259                     transitionTo(mSetDnsForwardersErrorState);
1260                     return false;
1261                 }
1262                 return true;
1263             }
1264             protected boolean turnOffMasterTetherSettings() {
1265                 try {
1266                     mNMService.stopTethering();
1267                 } catch (Exception e) {
1268                     transitionTo(mStopTetheringErrorState);
1269                     return false;
1270                 }
1271                 try {
1272                     mNMService.setIpForwardingEnabled(false);
1273                 } catch (Exception e) {
1274                     transitionTo(mSetIpForwardingDisabledErrorState);
1275                     return false;
1276                 }
1277                 transitionTo(mInitialState);
1278                 return true;
1279             }
1280
1281             protected void chooseUpstreamType(boolean tryCell) {
1282                 int upType = ConnectivityManager.TYPE_NONE;
1283                 String iface = null;
1284
1285                 updateConfiguration(); // TODO - remove?
1286
1287                 synchronized (mPublicSync) {
1288                     if (VDBG) {
1289                         Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1290                         for (Integer netType : mUpstreamIfaceTypes) {
1291                             Log.d(TAG, " " + netType);
1292                         }
1293                     }
1294
1295                     for (Integer netType : mUpstreamIfaceTypes) {
1296                         NetworkInfo info = null;
1297                         try {
1298                             info = mConnService.getNetworkInfo(netType.intValue());
1299                         } catch (RemoteException e) { }
1300                         if ((info != null) && info.isConnected()) {
1301                             upType = netType.intValue();
1302                             break;
1303                         }
1304                     }
1305                 }
1306
1307                 if (DBG) {
1308                     Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
1309                             + mPreferredUpstreamMobileApn + ", got type=" + upType);
1310                 }
1311
1312                 // if we're on DUN, put our own grab on it
1313                 if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
1314                         upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
1315                     turnOnUpstreamMobileConnection(upType);
1316                 } else if (upType != ConnectivityManager.TYPE_NONE) {
1317                     /* If we've found an active upstream connection that's not DUN/HIPRI
1318                      * we should stop any outstanding DUN/HIPRI start requests.
1319                      *
1320                      * If we found NONE we don't want to do this as we want any previous
1321                      * requests to keep trying to bring up something we can use.
1322                      */
1323                     turnOffUpstreamMobileConnection();
1324                 }
1325
1326                 if (upType == ConnectivityManager.TYPE_NONE) {
1327                     boolean tryAgainLater = true;
1328                     if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) &&
1329                             (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) {
1330                         // we think mobile should be coming up - don't set a retry
1331                         tryAgainLater = false;
1332                     }
1333                     if (tryAgainLater) {
1334                         sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1335                     }
1336                 } else {
1337                     LinkProperties linkProperties = null;
1338                     try {
1339                         linkProperties = mConnService.getLinkProperties(upType);
1340                     } catch (RemoteException e) { }
1341                     if (linkProperties != null) {
1342                         // Find the interface with the default IPv4 route. It may be the
1343                         // interface described by linkProperties, or one of the interfaces
1344                         // stacked on top of it.
1345                         Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
1346                         RouteInfo ipv4Default = RouteInfo.selectBestRoute(
1347                             linkProperties.getAllRoutes(), Inet4Address.ANY);
1348                         if (ipv4Default != null) {
1349                             iface = ipv4Default.getInterface();
1350                             Log.i(TAG, "Found interface " + ipv4Default.getInterface());
1351                         } else {
1352                             Log.i(TAG, "No IPv4 upstream interface, giving up.");
1353                         }
1354                     }
1355
1356                     if (iface != null) {
1357                         String[] dnsServers = mDefaultDnsServers;
1358                         Collection<InetAddress> dnses = linkProperties.getDnses();
1359                         if (dnses != null) {
1360                             // we currently only handle IPv4
1361                             ArrayList<InetAddress> v4Dnses =
1362                                     new ArrayList<InetAddress>(dnses.size());
1363                             for (InetAddress dnsAddress : dnses) {
1364                                 if (dnsAddress instanceof Inet4Address) {
1365                                     v4Dnses.add(dnsAddress);
1366                                 }
1367                             }
1368                             if (v4Dnses.size() > 0) {
1369                                 dnsServers = NetworkUtils.makeStrings(v4Dnses);
1370                             }
1371                         }
1372                         try {
1373                             mNMService.setDnsForwarders(dnsServers);
1374                         } catch (Exception e) {
1375                             transitionTo(mSetDnsForwardersErrorState);
1376                         }
1377                     }
1378                 }
1379                 notifyTetheredOfNewUpstreamIface(iface);
1380             }
1381
1382             protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1383                 if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
1384                 mUpstreamIfaceName = ifaceName;
1385                 for (TetherInterfaceSM sm : mNotifyList) {
1386                     sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1387                             ifaceName);
1388                 }
1389             }
1390         }
1391
1392         class InitialState extends TetherMasterUtilState {
1393             @Override
1394             public void enter() {
1395             }
1396             @Override
1397             public boolean processMessage(Message message) {
1398                 if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
1399                 boolean retValue = true;
1400                 switch (message.what) {
1401                     case CMD_TETHER_MODE_REQUESTED:
1402                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1403                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1404                         mNotifyList.add(who);
1405                         transitionTo(mTetherModeAliveState);
1406                         break;
1407                     case CMD_TETHER_MODE_UNREQUESTED:
1408                         who = (TetherInterfaceSM)message.obj;
1409                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1410                         int index = mNotifyList.indexOf(who);
1411                         if (index != -1) {
1412                             mNotifyList.remove(who);
1413                         }
1414                         break;
1415                     default:
1416                         retValue = false;
1417                         break;
1418                 }
1419                 return retValue;
1420             }
1421         }
1422
1423         class TetherModeAliveState extends TetherMasterUtilState {
1424             boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1425             @Override
1426             public void enter() {
1427                 turnOnMasterTetherSettings(); // may transition us out
1428
1429                 mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
1430                                                         // or crazy tests cases will fail
1431                 chooseUpstreamType(mTryCell);
1432                 mTryCell = !mTryCell;
1433             }
1434             @Override
1435             public void exit() {
1436                 turnOffUpstreamMobileConnection();
1437                 notifyTetheredOfNewUpstreamIface(null);
1438             }
1439             @Override
1440             public boolean processMessage(Message message) {
1441                 if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
1442                 boolean retValue = true;
1443                 switch (message.what) {
1444                     case CMD_TETHER_MODE_REQUESTED:
1445                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1446                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1447                         mNotifyList.add(who);
1448                         who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1449                                 mUpstreamIfaceName);
1450                         break;
1451                     case CMD_TETHER_MODE_UNREQUESTED:
1452                         who = (TetherInterfaceSM)message.obj;
1453                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1454                         int index = mNotifyList.indexOf(who);
1455                         if (index != -1) {
1456                             if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1457                             mNotifyList.remove(index);
1458                             if (mNotifyList.isEmpty()) {
1459                                 turnOffMasterTetherSettings(); // transitions appropriately
1460                             } else {
1461                                 if (DBG) {
1462                                     Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1463                                             " live requests:");
1464                                     for (Object o : mNotifyList) Log.d(TAG, "  " + o);
1465                                 }
1466                             }
1467                         } else {
1468                            Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1469                         }
1470                         break;
1471                     case CMD_UPSTREAM_CHANGED:
1472                         // need to try DUN immediately if Wifi goes down
1473                         mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1474                         chooseUpstreamType(mTryCell);
1475                         mTryCell = !mTryCell;
1476                         break;
1477                     case CMD_CELL_CONNECTION_RENEW:
1478                         // make sure we're still using a requested connection - may have found
1479                         // wifi or something since then.
1480                         if (mCurrentConnectionSequence == message.arg1) {
1481                             if (VDBG) {
1482                                 Log.d(TAG, "renewing mobile connection - requeuing for another " +
1483                                         CELL_CONNECTION_RENEW_MS + "ms");
1484                             }
1485                             turnOnUpstreamMobileConnection(mMobileApnReserved);
1486                         }
1487                         break;
1488                     case CMD_RETRY_UPSTREAM:
1489                         chooseUpstreamType(mTryCell);
1490                         mTryCell = !mTryCell;
1491                         break;
1492                     default:
1493                         retValue = false;
1494                         break;
1495                 }
1496                 return retValue;
1497             }
1498         }
1499
1500         class ErrorState extends State {
1501             int mErrorNotification;
1502             @Override
1503             public boolean processMessage(Message message) {
1504                 boolean retValue = true;
1505                 switch (message.what) {
1506                     case CMD_TETHER_MODE_REQUESTED:
1507                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1508                         who.sendMessage(mErrorNotification);
1509                         break;
1510                     default:
1511                        retValue = false;
1512                 }
1513                 return retValue;
1514             }
1515             void notify(int msgType) {
1516                 mErrorNotification = msgType;
1517                 for (Object o : mNotifyList) {
1518                     TetherInterfaceSM sm = (TetherInterfaceSM)o;
1519                     sm.sendMessage(msgType);
1520                 }
1521             }
1522
1523         }
1524         class SetIpForwardingEnabledErrorState extends ErrorState {
1525             @Override
1526             public void enter() {
1527                 Log.e(TAG, "Error in setIpForwardingEnabled");
1528                 notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
1529             }
1530         }
1531
1532         class SetIpForwardingDisabledErrorState extends ErrorState {
1533             @Override
1534             public void enter() {
1535                 Log.e(TAG, "Error in setIpForwardingDisabled");
1536                 notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
1537             }
1538         }
1539
1540         class StartTetheringErrorState extends ErrorState {
1541             @Override
1542             public void enter() {
1543                 Log.e(TAG, "Error in startTethering");
1544                 notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
1545                 try {
1546                     mNMService.setIpForwardingEnabled(false);
1547                 } catch (Exception e) {}
1548             }
1549         }
1550
1551         class StopTetheringErrorState extends ErrorState {
1552             @Override
1553             public void enter() {
1554                 Log.e(TAG, "Error in stopTethering");
1555                 notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
1556                 try {
1557                     mNMService.setIpForwardingEnabled(false);
1558                 } catch (Exception e) {}
1559             }
1560         }
1561
1562         class SetDnsForwardersErrorState extends ErrorState {
1563             @Override
1564             public void enter() {
1565                 Log.e(TAG, "Error in setDnsForwarders");
1566                 notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
1567                 try {
1568                     mNMService.stopTethering();
1569                 } catch (Exception e) {}
1570                 try {
1571                     mNMService.setIpForwardingEnabled(false);
1572                 } catch (Exception e) {}
1573             }
1574         }
1575     }
1576
1577     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1578         if (mContext.checkCallingOrSelfPermission(
1579                 android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1580             pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1581                     "from from pid=" + Binder.getCallingPid() + ", uid=" +
1582                     Binder.getCallingUid());
1583                     return;
1584         }
1585
1586         synchronized (mPublicSync) {
1587             pw.println("mUpstreamIfaceTypes: ");
1588             for (Integer netType : mUpstreamIfaceTypes) {
1589                 pw.println(" " + netType);
1590             }
1591
1592             pw.println();
1593             pw.println("Tether state:");
1594             for (Object o : mIfaces.values()) {
1595                 pw.println(" " + o);
1596             }
1597         }
1598         pw.println();
1599         return;
1600     }
1601 }