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