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