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