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