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