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