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