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