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