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