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