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