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