Tethering.java revision c9d5fb7c95f158d9a31d534895373afcfad77806
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.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.PackageManager;
28import android.content.res.Resources;
29import android.net.ConnectivityManager;
30import android.net.InterfaceConfiguration;
31import android.net.IConnectivityManager;
32import android.net.INetworkManagementEventObserver;
33import android.net.NetworkInfo;
34import android.os.BatteryManager;
35import android.os.Binder;
36import android.os.IBinder;
37import android.os.INetworkManagementService;
38import android.os.Message;
39import android.os.RemoteException;
40import android.os.ServiceManager;
41import android.provider.Settings;
42import android.util.Log;
43
44import com.android.internal.telephony.Phone;
45import com.android.internal.util.HierarchicalState;
46import com.android.internal.util.HierarchicalStateMachine;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.ArrayList;
51import java.util.HashMap;
52import java.util.Set;
53/**
54 * @hide
55 *
56 * Timeout
57 * TODO - review error states - they currently are dead-ends with no recovery possible
58 *
59 * TODO - look for parent classes and code sharing
60 */
61
62public class Tethering extends INetworkManagementEventObserver.Stub {
63
64    private Notification mTetheringNotification;
65    private Context mContext;
66    private final String TAG = "Tethering";
67
68    private boolean mPlaySounds = false;
69    private boolean mBooted = false;
70    //used to remember if we got connected before boot finished
71    private boolean mDeferedUsbConnection = false;
72
73    // TODO - remove both of these - should be part of interface inspection/selection stuff
74    private String[] mTetherableUsbRegexs;
75    private String[] mTetherableWifiRegexs;
76    private String[] mUpstreamIfaceRegexs;
77
78    private HashMap<String, TetherInterfaceSM> mIfaces;
79
80    private ArrayList<String> mActiveTtys;
81
82    private BroadcastReceiver mStateReceiver;
83
84    private static final String USB_NEAR_IFACE_ADDR      = "169.254.2.1";
85
86    private String[] mDhcpRange;
87    private static final String DHCP_DEFAULT_RANGE_START = "169.254.2.10";
88    private static final String DHCP_DEFAULT_RANGE_STOP  = "169.254.2.64";
89
90    private String[] mDnsServers;
91    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
92    private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
93
94    private boolean mDunRequired;
95    private boolean mUseHiPri;
96    private String mUpstreamIfaceName;
97
98    HierarchicalStateMachine mTetherMasterSM;
99
100    public Tethering(Context context) {
101        Log.d(TAG, "Tethering starting");
102        mContext = context;
103
104        // register for notifications from NetworkManagement Service
105        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
106        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
107        try {
108            service.registerObserver(this);
109        } catch (RemoteException e) {
110            Log.e(TAG, "Error registering observer :" + e);
111        }
112
113        mIfaces = new HashMap<String, TetherInterfaceSM>();
114        mActiveTtys = new ArrayList<String>();
115
116        mTetherMasterSM = new TetherMasterSM("TetherMaster");
117        mTetherMasterSM.start();
118
119        // TODO - remove this hack after real USB connections are detected.
120        IntentFilter filter = new IntentFilter();
121        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
122        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
123        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
124        mStateReceiver = new StateReceiver();
125        mContext.registerReceiver(mStateReceiver, filter);
126
127        mDhcpRange = context.getResources().getStringArray(
128                com.android.internal.R.array.config_tether_dhcp_range);
129        if (mDhcpRange.length == 0) {
130            mDhcpRange = new String[2];
131            mDhcpRange[0] = DHCP_DEFAULT_RANGE_START;
132            mDhcpRange[1] = DHCP_DEFAULT_RANGE_STOP;
133        } else if(mDhcpRange.length == 1) {
134            String[] tmp = new String[2];
135            tmp[0] = mDhcpRange[0];
136            tmp[1] = new String("");
137            mDhcpRange = tmp;
138        }
139        mDunRequired = context.getResources().getBoolean(
140                com.android.internal.R.bool.config_tether_dun_required);
141
142        mTetherableUsbRegexs = context.getResources().getStringArray(
143                com.android.internal.R.array.config_tether_usb_regexs);
144        mTetherableWifiRegexs = context.getResources().getStringArray(
145                com.android.internal.R.array.config_tether_wifi_regexs);
146        mUpstreamIfaceRegexs = context.getResources().getStringArray(
147                com.android.internal.R.array.config_tether_upstream_regexs);
148
149        // TODO - remove and rely on real notifications of the current iface
150        mDnsServers = new String[2];
151        mDnsServers[0] = DNS_DEFAULT_SERVER1;
152        mDnsServers[1] = DNS_DEFAULT_SERVER2;
153    }
154
155    public void interfaceLinkStatusChanged(String iface, boolean link) {
156        Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
157        boolean found = false;
158        boolean usb = false;
159        for (String regex : mTetherableWifiRegexs) {
160            if (iface.matches(regex)) {
161                found = true;
162                break;
163            }
164        }
165        for (String regex: mTetherableUsbRegexs) {
166            if (iface.matches(regex)) {
167                found = true;
168                usb = true;
169                break;
170            }
171        }
172        if (found == false) return;
173
174        synchronized (mIfaces) {
175            TetherInterfaceSM sm = mIfaces.get(iface);
176            if (link) {
177                if (sm == null) {
178                    sm = new TetherInterfaceSM(iface, usb);
179                    mIfaces.put(iface, sm);
180                    sm.start();
181                }
182            } else {
183                if (sm != null) {
184                    sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN));
185                    mIfaces.remove(iface);
186                }
187            }
188        }
189    }
190
191    public void interfaceAdded(String iface) {
192        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
193        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
194        boolean found = false;
195        boolean usb = false;
196        for (String regex : mTetherableWifiRegexs) {
197            if (iface.matches(regex)) {
198                found = true;
199                break;
200            }
201        }
202        for (String regex : mTetherableUsbRegexs) {
203            if (iface.matches(regex)) {
204                found = true;
205                usb = true;
206                break;
207            }
208        }
209        if (found == false) {
210            Log.d(TAG, iface + " is not a tetherable iface, ignoring");
211            return;
212        }
213
214        synchronized (mIfaces) {
215            TetherInterfaceSM sm = mIfaces.get(iface);
216            if (sm != null) {
217                Log.e(TAG, "active iface (" + iface + ") reported as added, ignoring");
218                return;
219            }
220            sm = new TetherInterfaceSM(iface, usb);
221            mIfaces.put(iface, sm);
222            sm.start();
223        }
224        Log.d(TAG, "interfaceAdded :" + iface);
225    }
226
227    public void interfaceRemoved(String iface) {
228        synchronized (mIfaces) {
229            TetherInterfaceSM sm = mIfaces.get(iface);
230            if (sm == null) {
231                Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
232                return;
233            }
234            sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN));
235            mIfaces.remove(iface);
236        }
237    }
238
239    public boolean tether(String iface) {
240        Log.d(TAG, "Tethering " + iface);
241        TetherInterfaceSM sm = null;
242        synchronized (mIfaces) {
243            sm = mIfaces.get(iface);
244        }
245        if (sm == null) {
246            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
247            return false;
248        }
249        if (sm.isErrored()) {
250            Log.e(TAG, "Tried to Tether to an errored iface :" + iface + ", ignoring");
251            return false;
252        }
253        if (!sm.isAvailable()) {
254            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
255            return false;
256        }
257        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED));
258        return true;
259    }
260
261    public boolean untether(String iface) {
262        Log.d(TAG, "Untethering " + iface);
263        TetherInterfaceSM sm = null;
264        synchronized (mIfaces) {
265            sm = mIfaces.get(iface);
266        }
267        if (sm == null) {
268            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
269            return false;
270        }
271        if (sm.isErrored()) {
272            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
273            return false;
274        }
275        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED));
276        return true;
277    }
278
279    private void sendTetherStateChangedBroadcast() {
280        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
281        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
282        try {
283            if (!service.isTetheringSupported()) return;
284        } catch (RemoteException e) {
285            return;
286        }
287
288        ArrayList<String> availableList = new ArrayList<String>();
289        ArrayList<String> activeList = new ArrayList<String>();
290        ArrayList<String> erroredList = new ArrayList<String>();
291
292        synchronized (mIfaces) {
293            Set ifaces = mIfaces.keySet();
294            for (Object iface : ifaces) {
295                TetherInterfaceSM sm = mIfaces.get(iface);
296                if (sm != null) {
297                    if(sm.isErrored()) {
298                        erroredList.add((String)iface);
299                    } else if (sm.isAvailable()) {
300                        availableList.add((String)iface);
301                    } else if (sm.isTethered()) {
302                        activeList.add((String)iface);
303                    }
304                }
305            }
306        }
307        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
308        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
309        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
310                availableList);
311        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
312        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
313                erroredList);
314        mContext.sendStickyBroadcast(broadcast);
315        Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
316                activeList.size() + ", " + erroredList.size());
317        // check if we need to send a USB notification
318        // Check if the user wants to be bothered
319        boolean tellUser = (Settings.Secure.getInt(mContext.getContentResolver(),
320                Settings.Secure.TETHER_NOTIFY, 0) == 1);
321        for (Object o : activeList) {
322            String s = (String)o;
323            for (Object regexObject : mTetherableUsbRegexs) {
324                if (s.matches((String)regexObject)) {
325                    showTetheredNotification();
326                    return;
327                }
328            }
329        }
330        if (tellUser) {
331            for (Object o : availableList) {
332                String s = (String)o;
333                for (String match : mTetherableUsbRegexs) {
334                    if (s.matches(match)) {
335                        showTetherAvailableNotification();
336                        return;
337                    }
338                }
339            }
340        }
341        clearNotification();
342    }
343
344    private void showTetherAvailableNotification() {
345        NotificationManager notificationManager = (NotificationManager)mContext.
346                getSystemService(Context.NOTIFICATION_SERVICE);
347        if (notificationManager == null) {
348            return;
349        }
350        Intent intent = new Intent();
351        intent.setClass(mContext, com.android.internal.app.TetherActivity.class);
352
353        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
354        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
355
356        Resources r = Resources.getSystem();
357        CharSequence title = r.getText(com.android.internal.R.string.
358                tether_available_notification_title);
359        CharSequence message = r.getText(com.android.internal.R.string.
360                tether_available_notification_message);
361
362        if(mTetheringNotification == null) {
363            mTetheringNotification = new Notification();
364            mTetheringNotification.when = 0;
365        }
366        mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb;
367
368        boolean playSounds = false;
369        //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
370        if (playSounds) {
371            mTetheringNotification.defaults |= Notification.DEFAULT_SOUND;
372        } else {
373            mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND;
374        }
375
376        mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT;
377        mTetheringNotification.tickerText = title;
378        mTetheringNotification.setLatestEventInfo(mContext, title, message, pi);
379
380        notificationManager.notify(mTetheringNotification.icon, mTetheringNotification);
381
382    }
383
384    private void showTetheredNotification() {
385        NotificationManager notificationManager = (NotificationManager)mContext.
386                getSystemService(Context.NOTIFICATION_SERVICE);
387        if (notificationManager == null) {
388            return;
389        }
390
391        Intent intent = new Intent();
392        intent.setClass(mContext, com.android.internal.app.TetherActivity.class);
393
394        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
395        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
396
397        Resources r = Resources.getSystem();
398        CharSequence title = r.getText(com.android.internal.R.string.
399                tether_stop_notification_title);
400        CharSequence message = r.getText(com.android.internal.R.string.
401                tether_stop_notification_message);
402
403        if(mTetheringNotification == null) {
404            mTetheringNotification = new Notification();
405            mTetheringNotification.when = 0;
406        }
407        mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb;
408
409        boolean playSounds = false;
410        //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
411        if (playSounds) {
412            mTetheringNotification.defaults |= Notification.DEFAULT_SOUND;
413        } else {
414            mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND;
415        }
416
417        mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT;
418        mTetheringNotification.tickerText = title;
419        mTetheringNotification.setLatestEventInfo(mContext, title, message, pi);
420
421        notificationManager.notify(mTetheringNotification.icon, mTetheringNotification);
422    }
423
424    private void clearNotification() {
425        NotificationManager notificationManager = (NotificationManager)mContext.
426                getSystemService(Context.NOTIFICATION_SERVICE);
427        if (notificationManager != null && mTetheringNotification != null) {
428            notificationManager.cancel(mTetheringNotification.icon);
429            mTetheringNotification = null;
430        }
431    }
432
433    private class StateReceiver extends BroadcastReceiver {
434        public void onReceive(Context content, Intent intent) {
435            String action = intent.getAction();
436            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
437                boolean usbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
438                        == BatteryManager.BATTERY_PLUGGED_USB);
439                if (mBooted) {
440                    Tethering.this.enableUsbIfaces(usbConnected); // add or remove them
441                } else {
442                    mDeferedUsbConnection = usbConnected;
443                }
444            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
445                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
446                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
447                try {
448                    int netType = (mUseHiPri ? ConnectivityManager.TYPE_MOBILE_HIPRI:
449                                               ConnectivityManager.TYPE_MOBILE_DUN);
450                    NetworkInfo info = service.getNetworkInfo(netType);
451                    int msg;
452                    if (info != null && info.isConnected() == true) {
453                        msg = TetherMasterSM.CMD_CELL_DUN_ENABLED;
454                    } else {
455                        msg = TetherMasterSM.CMD_CELL_DUN_DISABLED;
456                    }
457                    mTetherMasterSM.sendMessage(mTetherMasterSM.obtainMessage(msg));
458                } catch (RemoteException e) {}
459            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
460                mBooted = true;
461                if (mDeferedUsbConnection) {
462                    Tethering.this.enableUsbIfaces(true);
463                }
464            }
465        }
466    }
467
468    // used on cable insert/remove
469    private void enableUsbIfaces(boolean enable) {
470        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
471        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
472        String[] ifaces = new String[0];
473        try {
474            ifaces = service.listInterfaces();
475        } catch (Exception e) {
476            Log.e(TAG, "Error listing Interfaces :" + e);
477            return;
478        }
479        for (String iface : ifaces) {
480            for (String regex : mTetherableUsbRegexs) {
481                if (iface.matches(regex)) {
482                    if (enable) {
483                        interfaceAdded(iface);
484                    } else {
485                        interfaceRemoved(iface);
486                    }
487                }
488            }
489        }
490    }
491
492    // toggled when we enter/leave the fully teathered state
493    private boolean enableUsbRndis(boolean enabled) {
494        Log.d(TAG, "enableUsbRndis(" + enabled + ")");
495        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
496                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
497
498        try {
499            if (enabled) {
500                synchronized (this) {
501                    if (!service.isUsbRNDISStarted()) {
502                        service.startUsbRNDIS();
503                    }
504                }
505            } else {
506                if (service.isUsbRNDISStarted()) {
507                    service.stopUsbRNDIS();
508                }
509            }
510        } catch (Exception e) {
511            Log.e(TAG, "Error toggling usb RNDIS :" + e);
512            return false;
513        }
514        return true;
515    }
516
517    // configured when we start tethering and unconfig'd on error or conclusion
518    private boolean configureUsbIface(boolean enabled) {
519        Log.d(TAG, "configureUsbIface(" + enabled + ")");
520
521        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
522        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
523
524        // bring toggle the interfaces
525        String[] ifaces = new String[0];
526        try {
527            ifaces = service.listInterfaces();
528        } catch (Exception e) {
529            Log.e(TAG, "Error listing Interfaces :" + e);
530            return false;
531        }
532        for (String iface : ifaces) {
533            for (String regex : mTetherableUsbRegexs) {
534                if (iface.matches(regex)) {
535                    InterfaceConfiguration ifcg = null;
536                    try {
537                        ifcg = service.getInterfaceConfig(iface);
538                        if (ifcg != null) {
539                            ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1;
540                            ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
541                            if (enabled) {
542                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
543                            } else {
544                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
545                                // TODO - clean this up - maybe a better regex?
546                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
547                                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("  "," ");
548                            }
549                            service.setInterfaceConfig(iface, ifcg);
550                        }
551                    } catch (Exception e) {
552                        Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
553                        return false;
554                    }
555                }
556            }
557        }
558
559        return true;
560    }
561
562    public String[] getTetherableUsbRegexs() {
563        return mTetherableUsbRegexs;
564    }
565
566    public String[] getTetherableWifiRegexs() {
567        return mTetherableWifiRegexs;
568    }
569
570    public String[] getUpstreamIfaceRegexs() {
571        return mUpstreamIfaceRegexs;
572    }
573
574    public boolean isDunRequired() {
575        return mDunRequired;
576    }
577
578    public String[] getTetheredIfaces() {
579        ArrayList<String> list = new ArrayList<String>();
580        synchronized (mIfaces) {
581            Set keys = mIfaces.keySet();
582            for (Object key : keys) {
583                TetherInterfaceSM sm = mIfaces.get(key);
584                if (sm.isTethered()) {
585                    list.add((String)key);
586                }
587            }
588        }
589        String[] retVal = new String[list.size()];
590        for (int i=0; i < list.size(); i++) {
591            retVal[i] = list.get(i);
592        }
593        return retVal;
594    }
595
596    public String[] getTetherableIfaces() {
597        ArrayList<String> list = new ArrayList<String>();
598        synchronized (mIfaces) {
599            Set keys = mIfaces.keySet();
600            for (Object key : keys) {
601                TetherInterfaceSM sm = mIfaces.get(key);
602                if (sm.isAvailable()) {
603                    list.add((String)key);
604                }
605            }
606        }
607        String[] retVal = new String[list.size()];
608        for (int i=0; i < list.size(); i++) {
609            retVal[i] = list.get(i);
610        }
611        return retVal;
612    }
613
614
615    class TetherInterfaceSM extends HierarchicalStateMachine {
616        // notification from the master SM that it's in tether mode
617        static final int CMD_TETHER_MODE_ALIVE           =  1;
618        // notification from the master SM that it's not in tether mode
619        static final int CMD_TETHER_MODE_DEAD            =  2;
620        // request from the user that it wants to tether
621        static final int CMD_TETHER_REQUESTED            =  3;
622        // request from the user that it wants to untether
623        static final int CMD_TETHER_UNREQUESTED          =  4;
624        // notification that this interface is down
625        static final int CMD_INTERFACE_DOWN              =  5;
626        // notification that this interface is up
627        static final int CMD_INTERFACE_UP                =  6;
628        // notification from the master SM that it had an error turning on cellular dun
629        static final int CMD_CELL_DUN_ERROR              = 10;
630        // notification from the master SM that it had trouble enabling IP Forwarding
631        static final int CMD_IP_FORWARDING_ENABLE_ERROR  = 11;
632        // notification from the master SM that it had trouble disabling IP Forwarding
633        static final int CMD_IP_FORWARDING_DISABLE_ERROR = 12;
634        // notification from the master SM that it had trouble staring tethering
635        static final int CMD_START_TETHERING_ERROR       = 13;
636        // notification from the master SM that it had trouble stopping tethering
637        static final int CMD_STOP_TETHERING_ERROR        = 14;
638        // notification from the master SM that it had trouble setting the DNS forwarders
639        static final int CMD_SET_DNS_FORWARDERS_ERROR    = 15;
640        // a mechanism to transition self to error state from an enter function
641        static final int CMD_TRANSITION_TO_ERROR         = 16;
642
643        private HierarchicalState mDefaultState;
644
645        private HierarchicalState mInitialState;
646        private HierarchicalState mStartingState;
647        private HierarchicalState mTetheredState;
648
649        private HierarchicalState mMasterTetherErrorState;
650        private HierarchicalState mTetherInterfaceErrorState;
651        private HierarchicalState mUntetherInterfaceErrorState;
652        private HierarchicalState mEnableNatErrorState;
653        private HierarchicalState mDisableNatErrorState;
654        private HierarchicalState mUsbConfigurationErrorState;
655
656        private HierarchicalState mUnavailableState;
657
658        private boolean mAvailable;
659        private boolean mErrored;
660        private boolean mTethered;
661
662        String mIfaceName;
663        boolean mUsb;
664
665        TetherInterfaceSM(String name, boolean usb) {
666            super(name);
667            mIfaceName = name;
668            mUsb = usb;
669
670            mInitialState = new InitialState();
671            addState(mInitialState);
672            mStartingState = new StartingState();
673            addState(mStartingState);
674            mTetheredState = new TetheredState();
675            addState(mTetheredState);
676            mMasterTetherErrorState = new MasterTetherErrorState();
677            addState(mMasterTetherErrorState);
678            mTetherInterfaceErrorState = new TetherInterfaceErrorState();
679            addState(mTetherInterfaceErrorState);
680            mUntetherInterfaceErrorState = new UntetherInterfaceErrorState();
681            addState(mUntetherInterfaceErrorState);
682            mEnableNatErrorState = new EnableNatErrorState();
683            addState(mEnableNatErrorState);
684            mDisableNatErrorState = new DisableNatErrorState();
685            addState(mDisableNatErrorState);
686            mUsbConfigurationErrorState = new UsbConfigurationErrorState();
687            addState(mUsbConfigurationErrorState);
688            mUnavailableState = new UnavailableState();
689            addState(mUnavailableState);
690
691            setInitialState(mInitialState);
692        }
693
694        public String toString() {
695            String res = new String();
696            res += mIfaceName + " - ";
697            HierarchicalState current = getCurrentState();
698            if (current == mInitialState) res += "InitialState";
699            if (current == mStartingState) res += "StartingState";
700            if (current == mTetheredState) res += "TetheredState";
701            if (current == mMasterTetherErrorState) res += "MasterTetherErrorState";
702            if (current == mTetherInterfaceErrorState) res += "TetherInterfaceErrorState";
703            if (current == mUntetherInterfaceErrorState) res += "UntetherInterfaceErrorState";
704            if (current == mEnableNatErrorState) res += "EnableNatErrorState";
705            if (current == mDisableNatErrorState) res += "DisableNatErrorState";
706            if (current == mUsbConfigurationErrorState) res += "UsbConfigurationErrorState";
707            if (current == mUnavailableState) res += "UnavailableState";
708            if (mAvailable) res += " - Available";
709            if (mTethered) res += " - Tethered";
710            if (mErrored) res += " - ERRORED";
711            return res;
712        }
713
714        // synchronized between this getter and the following setter
715        public synchronized boolean isAvailable() {
716            return mAvailable;
717        }
718
719        private synchronized void setAvailable(boolean available) {
720            mAvailable = available;
721        }
722
723        // synchronized between this getter and the following setter
724        public synchronized boolean isTethered() {
725            return mTethered;
726        }
727
728        private synchronized void setTethered(boolean tethered) {
729            mTethered = tethered;
730        }
731
732        // synchronized between this getter and the following setter
733        public synchronized boolean isErrored() {
734            return mErrored;
735        }
736
737        private void setErrored(boolean errored) {
738            synchronized (this) {
739                mErrored = errored;
740            }
741            if (errored && mUsb) {
742                // note everything's been unwound by this point so nothing to do on
743                // further error..
744                Tethering.this.configureUsbIface(false);
745            }
746        }
747
748        class InitialState extends HierarchicalState {
749            @Override
750            public void enter() {
751                setAvailable(true);
752                setTethered(false);
753                setErrored(false);
754                sendTetherStateChangedBroadcast();
755            }
756
757            @Override
758            public boolean processMessage(Message message) {
759                Log.d(TAG, "InitialState.processMessage what=" + message.what);
760                boolean retValue = true;
761                switch (message.what) {
762                    case CMD_TETHER_REQUESTED:
763                        Message m = mTetherMasterSM.obtainMessage(
764                                TetherMasterSM.CMD_TETHER_MODE_REQUESTED);
765                        m.obj = TetherInterfaceSM.this;
766                        mTetherMasterSM.sendMessage(m);
767                        transitionTo(mStartingState);
768                        break;
769                    case CMD_INTERFACE_DOWN:
770                        transitionTo(mUnavailableState);
771                        break;
772                    default:
773                        retValue = false;
774                        break;
775                }
776                return retValue;
777            }
778        }
779
780        class StartingState extends HierarchicalState {
781            @Override
782            public void enter() {
783                setAvailable(false);
784                if (mUsb) {
785                    if (!Tethering.this.configureUsbIface(true)) {
786                        Message m = mTetherMasterSM.obtainMessage(
787                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
788                        m.obj = TetherInterfaceSM.this;
789                        mTetherMasterSM.sendMessage(m);
790
791                        m = obtainMessage(CMD_TRANSITION_TO_ERROR);
792                        m.obj = mUsbConfigurationErrorState;
793                        sendMessageAtFrontOfQueue(m);
794                        return;
795                    }
796                }
797                sendTetherStateChangedBroadcast();
798            }
799            @Override
800            public boolean processMessage(Message message) {
801                Log.d(TAG, "StartingState.processMessage what=" + message.what);
802                boolean retValue = true;
803                switch (message.what) {
804                    // maybe a parent class?
805                    case CMD_TETHER_UNREQUESTED:
806                        Message m = mTetherMasterSM.obtainMessage(
807                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
808                        m.obj = TetherInterfaceSM.this;
809                        mTetherMasterSM.sendMessage(m);
810                        if (mUsb) {
811                            if (!Tethering.this.configureUsbIface(false)) {
812                                transitionTo(mUsbConfigurationErrorState);
813                                break;
814                            }
815                        }
816                        transitionTo(mInitialState);
817                        break;
818                    case CMD_TETHER_MODE_ALIVE:
819                        transitionTo(mTetheredState);
820                        break;
821                    case CMD_CELL_DUN_ERROR:
822                    case CMD_IP_FORWARDING_ENABLE_ERROR:
823                    case CMD_IP_FORWARDING_DISABLE_ERROR:
824                    case CMD_START_TETHERING_ERROR:
825                    case CMD_STOP_TETHERING_ERROR:
826                    case CMD_SET_DNS_FORWARDERS_ERROR:
827                        transitionTo(mMasterTetherErrorState);
828                        break;
829                    case CMD_INTERFACE_DOWN:
830                        m = mTetherMasterSM.obtainMessage(
831                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
832                        m.obj = TetherInterfaceSM.this;
833                        mTetherMasterSM.sendMessage(m);
834                        transitionTo(mUnavailableState);
835                        break;
836                   case CMD_TRANSITION_TO_ERROR:
837                       HierarchicalState s = (HierarchicalState)(message.obj);
838                       transitionTo(s);
839                       break;
840                    default:
841                        retValue = false;
842                }
843                return retValue;
844            }
845        }
846
847        class TetheredState extends HierarchicalState {
848            @Override
849            public void enter() {
850                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
851                INetworkManagementService service =
852                        INetworkManagementService.Stub.asInterface(b);
853                try {
854                    service.tetherInterface(mIfaceName);
855                } catch (Exception e) {
856                    Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
857                    m.obj = mTetherInterfaceErrorState;
858                    sendMessageAtFrontOfQueue(m);
859                    return;
860                }
861                try {
862                    service.enableNat(mIfaceName, mUpstreamIfaceName);
863                } catch (Exception e) {
864                    Message m = obtainMessage(CMD_TRANSITION_TO_ERROR);
865                    m.obj = mEnableNatErrorState;
866                    sendMessageAtFrontOfQueue(m);
867                    return;
868                }
869                if (mUsb) Tethering.this.enableUsbRndis(true);
870                Log.d(TAG, "Tethered " + mIfaceName);
871                setAvailable(false);
872                setTethered(true);
873                sendTetherStateChangedBroadcast();
874            }
875            @Override
876            public void exit() {
877                if (mUsb) Tethering.this.enableUsbRndis(false);
878            }
879            @Override
880            public boolean processMessage(Message message) {
881                Log.d(TAG, "TetheredState.processMessage what=" + message.what);
882                boolean retValue = true;
883                boolean error = false;
884                switch (message.what) {
885                    case CMD_TETHER_UNREQUESTED:
886                    case CMD_INTERFACE_DOWN:
887                        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
888                        INetworkManagementService service =
889                                INetworkManagementService.Stub.asInterface(b);
890                        try {
891                            service.disableNat(mIfaceName, mUpstreamIfaceName);
892                        } catch (Exception e) {
893                            transitionTo(mDisableNatErrorState);
894                            break;
895                        }
896                        try {
897                            service.untetherInterface(mIfaceName);
898                        } catch (Exception e) {
899                            transitionTo(mUntetherInterfaceErrorState);
900                            break;
901                        }
902                        Message m = mTetherMasterSM.obtainMessage(
903                                TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
904                        m.obj = TetherInterfaceSM.this;
905                        mTetherMasterSM.sendMessage(m);
906                        if (message.what == CMD_TETHER_UNREQUESTED) {
907                            if (mUsb) {
908                                if (!Tethering.this.configureUsbIface(false)) {
909                                    transitionTo(mUsbConfigurationErrorState);
910                                } else {
911                                    transitionTo(mInitialState);
912                                }
913                            } else {
914                                transitionTo(mInitialState);
915                            }
916                        } else if (message.what == CMD_INTERFACE_DOWN) {
917                            transitionTo(mUnavailableState);
918                        }
919                        Log.d(TAG, "Untethered " + mIfaceName);
920                        break;
921                    case CMD_CELL_DUN_ERROR:
922                    case CMD_IP_FORWARDING_ENABLE_ERROR:
923                    case CMD_IP_FORWARDING_DISABLE_ERROR:
924                    case CMD_START_TETHERING_ERROR:
925                    case CMD_STOP_TETHERING_ERROR:
926                    case CMD_SET_DNS_FORWARDERS_ERROR:
927                        error = true;
928                        // fall through
929                    case CMD_TETHER_MODE_DEAD:
930                        b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
931                        service = INetworkManagementService.Stub.asInterface(b);
932                        try {
933                            service.disableNat(mIfaceName, mUpstreamIfaceName);
934                        } catch (Exception e) {
935                            transitionTo(mDisableNatErrorState);
936                            break;
937                        }
938                        try {
939                            service.untetherInterface(mIfaceName);
940                        } catch (Exception e) {
941                            transitionTo(mUntetherInterfaceErrorState);
942                            break;
943                        }
944                        if (error) {
945                            transitionTo(mMasterTetherErrorState);
946                            break;
947                        }
948                        Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
949                        sendTetherStateChangedBroadcast();
950                        if (mUsb) {
951                            if (!Tethering.this.configureUsbIface(false)) {
952                                transitionTo(mUsbConfigurationErrorState);
953                                break;
954                            }
955                        }
956                        transitionTo(mInitialState);
957                        break;
958                    case CMD_TRANSITION_TO_ERROR:
959                        HierarchicalState s = (HierarchicalState)(message.obj);
960                        transitionTo(s);
961                        break;
962                    default:
963                        retValue = false;
964                        break;
965                }
966                return retValue;
967            }
968        }
969
970        class UnavailableState extends HierarchicalState {
971            @Override
972            public void enter() {
973                setAvailable(false);
974                setErrored(false);
975                setTethered(false);
976                sendTetherStateChangedBroadcast();
977            }
978            @Override
979            public boolean processMessage(Message message) {
980                boolean retValue = true;
981                switch (message.what) {
982                    case CMD_INTERFACE_UP:
983                        transitionTo(mInitialState);
984                        break;
985                    default:
986                        retValue = false;
987                        break;
988                }
989                return retValue;
990            }
991        }
992
993
994        class ErrorState extends HierarchicalState {
995            int mErrorNotification;
996            @Override
997            public boolean processMessage(Message message) {
998                boolean retValue = true;
999                switch (message.what) {
1000                    case CMD_TETHER_REQUESTED:
1001                        sendTetherStateChangedBroadcast();
1002                        break;
1003                    default:
1004                        retValue = false;
1005                        break;
1006                }
1007                return retValue;
1008            }
1009        }
1010
1011        class MasterTetherErrorState extends ErrorState {
1012            @Override
1013            public void enter() {
1014                Log.e(TAG, "Error in Master Tether state " + mIfaceName);
1015                setAvailable(false);
1016                setErrored(true);
1017                sendTetherStateChangedBroadcast();
1018            }
1019        }
1020
1021        class TetherInterfaceErrorState extends ErrorState {
1022            @Override
1023            public void enter() {
1024                Log.e(TAG, "Error trying to tether " + mIfaceName);
1025                setAvailable(false);
1026                setErrored(true);
1027                sendTetherStateChangedBroadcast();
1028            }
1029        }
1030
1031        class UntetherInterfaceErrorState extends ErrorState {
1032            @Override
1033            public void enter() {
1034                Log.e(TAG, "Error trying to untether " + mIfaceName);
1035                setAvailable(false);
1036                setErrored(true);
1037                sendTetherStateChangedBroadcast();
1038            }
1039        }
1040
1041        class EnableNatErrorState extends ErrorState {
1042            @Override
1043            public void enter() {
1044                Log.e(TAG, "Error trying to enable NAT " + mIfaceName);
1045                setAvailable(false);
1046                setErrored(true);
1047
1048                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1049                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1050                try {
1051                    service.untetherInterface(mIfaceName);
1052                } catch (Exception e) {}
1053                sendTetherStateChangedBroadcast();
1054            }
1055        }
1056
1057
1058        class DisableNatErrorState extends ErrorState {
1059            @Override
1060            public void enter() {
1061                Log.e(TAG, "Error trying to disable NAT " + mIfaceName);
1062                setAvailable(false);
1063                setErrored(true);
1064
1065                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1066                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1067                try {
1068                    service.untetherInterface(mIfaceName);
1069                } catch (Exception e) {}
1070                sendTetherStateChangedBroadcast();
1071            }
1072        }
1073
1074        class UsbConfigurationErrorState extends ErrorState {
1075            @Override
1076            public void enter() {
1077                Log.e(TAG, "Error trying to configure USB " + mIfaceName);
1078                setAvailable(false);
1079                setErrored(true);
1080            }
1081        }
1082    }
1083
1084    class TetherMasterSM extends HierarchicalStateMachine {
1085        // an interface SM has requested Tethering
1086        static final int CMD_TETHER_MODE_REQUESTED   = 1;
1087        // an interface SM has unrequested Tethering
1088        static final int CMD_TETHER_MODE_UNREQUESTED = 2;
1089        // we received notice that the cellular DUN connection is up
1090        static final int CMD_CELL_DUN_ENABLED        = 3;
1091        // we received notice that the cellular DUN connection is down
1092        static final int CMD_CELL_DUN_DISABLED       = 4;
1093        // we timed out on a cellular DUN toggle
1094        static final int CMD_CELL_DUN_TIMEOUT        = 5;
1095        // it's time to renew our cellular DUN reservation
1096        static final int CMD_CELL_DUN_RENEW          = 6;
1097
1098        // This indicates what a timeout event relates to.  A state that
1099        // sends itself a delayed timeout event and handles incoming timeout events
1100        // should inc this when it is entered and whenever it sends a new timeout event.
1101        // We do not flush the old ones.
1102        private int mSequenceNumber;
1103
1104        private HierarchicalState mInitialState;
1105        private HierarchicalState mCellDunRequestedState;
1106        private HierarchicalState mCellDunAliveState;
1107        private HierarchicalState mTetherModeAliveState;
1108
1109        private HierarchicalState mCellDunErrorState;
1110        private HierarchicalState mSetIpForwardingEnabledErrorState;
1111        private HierarchicalState mSetIpForwardingDisabledErrorState;
1112        private HierarchicalState mStartTetheringErrorState;
1113        private HierarchicalState mStopTetheringErrorState;
1114        private HierarchicalState mSetDnsForwardersErrorState;
1115
1116        private ArrayList mNotifyList;
1117
1118
1119        private static final int CELL_DUN_TIMEOUT_MS         = 45000;
1120        private static final int CELL_DISABLE_DUN_TIMEOUT_MS = 3000;
1121        private static final int CELL_DUN_RENEW_MS           = 40000;
1122
1123        TetherMasterSM(String name) {
1124            super(name);
1125
1126            //Add states
1127            mInitialState = new InitialState();
1128            addState(mInitialState);
1129            mCellDunRequestedState = new CellDunRequestedState();
1130            addState(mCellDunRequestedState);
1131            mCellDunAliveState = new CellDunAliveState();
1132            addState(mCellDunAliveState);
1133            mTetherModeAliveState = new TetherModeAliveState();
1134            addState(mTetherModeAliveState);
1135
1136            mCellDunErrorState = new CellDunErrorState();
1137            addState(mCellDunErrorState);
1138            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1139            addState(mSetIpForwardingEnabledErrorState);
1140            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1141            addState(mSetIpForwardingDisabledErrorState);
1142            mStartTetheringErrorState = new StartTetheringErrorState();
1143            addState(mStartTetheringErrorState);
1144            mStopTetheringErrorState = new StopTetheringErrorState();
1145            addState(mStopTetheringErrorState);
1146            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1147            addState(mSetDnsForwardersErrorState);
1148
1149            mNotifyList = new ArrayList();
1150
1151            setInitialState(mInitialState);
1152        }
1153
1154        class TetherMasterUtilState extends HierarchicalState {
1155            @Override
1156            public boolean processMessage(Message m) {
1157                return false;
1158            }
1159            public int turnOnMobileDun() {
1160                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1161                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1162                int retValue = Phone.APN_REQUEST_FAILED;
1163                try {
1164                    retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1165                            (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN),
1166                            new Binder());
1167                } catch (Exception e) {
1168                }
1169                return retValue;
1170            }
1171            public boolean turnOffMobileDun() {
1172                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1173                IConnectivityManager service =
1174                        IConnectivityManager.Stub.asInterface(b);
1175                try {
1176                    service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1177                            (mUseHiPri ? Phone.FEATURE_ENABLE_HIPRI : Phone.FEATURE_ENABLE_DUN));
1178                } catch (Exception e) {
1179                    return false;
1180                }
1181                return true;
1182            }
1183            public boolean turnOnMasterTetherSettings() {
1184                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1185                INetworkManagementService service =
1186                        INetworkManagementService.Stub.asInterface(b);
1187                try {
1188                    service.setIpForwardingEnabled(true);
1189                } catch (Exception e) {
1190                    transitionTo(mSetIpForwardingEnabledErrorState);
1191                    return false;
1192                }
1193                try {
1194                    service.startTethering(mDhcpRange[0], mDhcpRange[1]);
1195                } catch (Exception e) {
1196                    transitionTo(mStartTetheringErrorState);
1197                    return false;
1198                }
1199                try {
1200                    service.setDnsForwarders(mDnsServers);
1201                } catch (Exception e) {
1202                    transitionTo(mSetDnsForwardersErrorState);
1203                    return false;
1204                }
1205                transitionTo(mTetherModeAliveState);
1206                return true;
1207            }
1208            public boolean turnOffMasterTetherSettings() {
1209                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1210                INetworkManagementService service =
1211                        INetworkManagementService.Stub.asInterface(b);
1212                try {
1213                    service.stopTethering();
1214                } catch (Exception e) {
1215                    transitionTo(mStopTetheringErrorState);
1216                    return false;
1217                }
1218                try {
1219                    service.setIpForwardingEnabled(false);
1220                } catch (Exception e) {
1221                    transitionTo(mSetIpForwardingDisabledErrorState);
1222                    return false;
1223                }
1224                transitionTo(mInitialState);
1225                return true;
1226            }
1227            public String findActiveUpstreamIface() {
1228                // check for what iface we can use - if none found switch to error.
1229                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1230                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1231
1232                String[] ifaces = new String[0];
1233                try {
1234                    ifaces = service.listInterfaces();
1235                } catch (Exception e) {
1236                    Log.e(TAG, "Error listing Interfaces :" + e);
1237                    return null;
1238                }
1239                for (String iface : ifaces) {
1240                    for (String regex : mUpstreamIfaceRegexs) {
1241                        if (iface.matches(regex)) {
1242                            // verify it is up!
1243                            InterfaceConfiguration ifcg = null;
1244                            try {
1245                                ifcg = service.getInterfaceConfig(iface);
1246                            } catch (Exception e) {
1247                                Log.e(TAG, "Error getting iface config :" + e);
1248                                // ignore - try next
1249                                continue;
1250                            }
1251                            if (ifcg.interfaceFlags.contains("up")) {
1252                                return iface;
1253                            }
1254                        }
1255                    }
1256                }
1257                return null;
1258            }
1259        }
1260
1261        class InitialState extends TetherMasterUtilState {
1262            @Override
1263            public void enter() {
1264                mUseHiPri = false;
1265            }
1266            @Override
1267            public boolean processMessage(Message message) {
1268                Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
1269                boolean retValue = true;
1270                switch (message.what) {
1271                    case CMD_TETHER_MODE_REQUESTED:
1272                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1273                        Log.d(TAG, "Tether Mode requested by " + who.toString());
1274                        mNotifyList.add(who);
1275                        transitionTo(mCellDunRequestedState);
1276                        break;
1277                    case CMD_TETHER_MODE_UNREQUESTED:
1278                        who = (TetherInterfaceSM)message.obj;
1279                        Log.d(TAG, "Tether Mode unrequested by " + who.toString());
1280                        int index = mNotifyList.indexOf(who);
1281                        if (index != -1) {
1282                            mNotifyList.remove(who);
1283                        }
1284                        break;
1285                    case CMD_CELL_DUN_ENABLED:
1286                        transitionTo(mCellDunAliveState);
1287                        break;
1288                    default:
1289                        retValue = false;
1290                        break;
1291                }
1292                return retValue;
1293            }
1294        }
1295        class CellDunRequestedState extends TetherMasterUtilState {
1296            @Override
1297            public void enter() {
1298                mUseHiPri = (findActiveUpstreamIface() == null && !mDunRequired);
1299                if (mDunRequired || mUseHiPri) {
1300                    ++mSequenceNumber;
1301                    int result = turnOnMobileDun();
1302                    switch (result) {
1303                        case Phone.APN_ALREADY_ACTIVE:
1304                            Log.d(TAG, "Dun already active");
1305                            sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED));
1306                            break;
1307                        case Phone.APN_REQUEST_FAILED:
1308                        case Phone.APN_TYPE_NOT_AVAILABLE:
1309                            Log.d(TAG, "Error bringing up Dun connection");
1310                            Message m = obtainMessage(CMD_CELL_DUN_TIMEOUT);
1311                            m.arg1 = mSequenceNumber;
1312                            sendMessage(m);
1313                            break;
1314                        case Phone.APN_REQUEST_STARTED:
1315                            Log.d(TAG, "Started bringing up Dun connection");
1316                            m = obtainMessage(CMD_CELL_DUN_TIMEOUT);
1317                            m.arg1 = mSequenceNumber;
1318                            sendMessageDelayed(m, CELL_DUN_TIMEOUT_MS);
1319                            break;
1320                        default:
1321                            Log.e(TAG, "Unknown return value from startUsingNetworkFeature " +
1322                                    result);
1323                    }
1324                } else {
1325                    Log.d(TAG, "no Dun Required.  Skipping to Active");
1326                    sendMessage(obtainMessage(CMD_CELL_DUN_ENABLED));
1327                }
1328            }
1329
1330            @Override
1331            public boolean processMessage(Message message) {
1332                Log.d(TAG, "CellDunRequestedState.processMessage what=" + message.what);
1333                boolean retValue = true;
1334                switch (message.what) {
1335                    case CMD_TETHER_MODE_REQUESTED:
1336                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1337                        mNotifyList.add(who);
1338                        break;
1339                    case CMD_TETHER_MODE_UNREQUESTED:
1340                        who = (TetherInterfaceSM)message.obj;
1341                        int index = mNotifyList.indexOf(who);
1342                        if (index != -1) {
1343                            mNotifyList.remove(index);
1344                            if (mNotifyList.isEmpty()) {
1345                                if (mDunRequired || mUseHiPri) {
1346                                    turnOffMobileDun();
1347                                }
1348                                transitionTo(mInitialState);
1349                            }
1350                        }
1351                        break;
1352                    case CMD_CELL_DUN_ENABLED:
1353                        turnOnMasterTetherSettings();
1354                        break;
1355                    case CMD_CELL_DUN_DISABLED:
1356                        break;
1357                    case CMD_CELL_DUN_TIMEOUT:
1358                        if (message.arg1 == mSequenceNumber) {
1359                            transitionTo(mCellDunErrorState);
1360                        }
1361                        break;
1362                    default:
1363                        retValue = false;
1364                        break;
1365                }
1366                return retValue;
1367            }
1368        }
1369
1370        class CellDunAliveState extends TetherMasterUtilState {
1371            @Override
1372            public void enter() {
1373                Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
1374                sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
1375            }
1376
1377            @Override
1378            public boolean processMessage(Message message) {
1379                Log.d(TAG, "CellDunAliveState.processMessage what=" + message.what);
1380                boolean retValue = true;
1381                switch (message.what) {
1382                    case CMD_TETHER_MODE_REQUESTED:
1383                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1384                        mNotifyList.add(who);
1385                        turnOnMasterTetherSettings();
1386                        break;
1387                    case CMD_TETHER_MODE_UNREQUESTED:
1388                        who = (TetherInterfaceSM)message.obj;
1389                        int index = mNotifyList.indexOf(who);
1390                        if (index != -1) {
1391                            mNotifyList.remove(index);
1392                            if (mNotifyList.isEmpty()) {
1393                                if (mDunRequired || mUseHiPri) {
1394                                    turnOffMobileDun();
1395                                }
1396                                transitionTo(mInitialState);
1397                            }
1398                        }
1399                        break;
1400                    case CMD_CELL_DUN_DISABLED:
1401                        transitionTo(mInitialState);
1402                        break;
1403                    case CMD_CELL_DUN_RENEW:
1404                        Log.d(TAG, "renewing dun connection - requeuing for another " +
1405                                CELL_DUN_RENEW_MS + "ms");
1406                        turnOnMobileDun();
1407                        sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
1408                        break;
1409                    default:
1410                        retValue = false;
1411                        break;
1412                }
1413                return retValue;
1414            }
1415        }
1416
1417        class TetherModeAliveState extends TetherMasterUtilState {
1418            @Override
1419            public void enter() {
1420                if (mDunRequired || mUseHiPri) {
1421                    Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
1422                    sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
1423                }
1424                mUpstreamIfaceName = findActiveUpstreamIface();
1425                if (mUpstreamIfaceName == null) {
1426                    Log.d(TAG, "Erroring our of tether - no upstream ifaces available");
1427                    sendMessage(obtainMessage(CMD_CELL_DUN_DISABLED));
1428                } else {
1429                    for (Object o : mNotifyList) {
1430                        TetherInterfaceSM sm = (TetherInterfaceSM)o;
1431                        sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE));
1432                    }
1433                }
1434            }
1435            @Override
1436            public boolean processMessage(Message message) {
1437                Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
1438                boolean retValue = true;
1439                switch (message.what) {
1440                    case CMD_TETHER_MODE_REQUESTED:
1441                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1442                        mNotifyList.add(who);
1443                        who.sendMessage(who.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE));
1444                        break;
1445                    case CMD_TETHER_MODE_UNREQUESTED:
1446                        who = (TetherInterfaceSM)message.obj;
1447                        int index = mNotifyList.indexOf(who);
1448                        if (index != -1) {
1449                            mNotifyList.remove(index);
1450                            if (mNotifyList.isEmpty()) {
1451                                if (mDunRequired || mUseHiPri) {
1452                                    turnOffMobileDun();
1453                                }
1454                                turnOffMasterTetherSettings(); // transitions appropriately
1455                                mUpstreamIfaceName = null;
1456                            }
1457                        }
1458                        break;
1459                    case CMD_CELL_DUN_DISABLED:
1460                        int size = mNotifyList.size();
1461                        for (int i = 0; i < size; i++) {
1462                            TetherInterfaceSM sm = (TetherInterfaceSM)mNotifyList.get(i);
1463                            mNotifyList.remove(i);
1464                            sm.sendMessage(sm.obtainMessage(
1465                                    TetherInterfaceSM.CMD_TETHER_MODE_DEAD));
1466                        }
1467                        turnOffMasterTetherSettings(); // transitions appropriately
1468                        mUpstreamIfaceName = null;
1469                        break;
1470                    case CMD_CELL_DUN_RENEW:
1471                        Log.d(TAG, "renewing dun connection - requeuing for another " +
1472                                CELL_DUN_RENEW_MS + "ms");
1473                        turnOnMobileDun();
1474                        sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
1475                        break;
1476                    default:
1477                       retValue = false;
1478                       break;
1479                }
1480                return retValue;
1481            }
1482        }
1483
1484        class ErrorState extends HierarchicalState {
1485            int mErrorNotification;
1486            @Override
1487            public boolean processMessage(Message message) {
1488                boolean retValue = true;
1489                switch (message.what) {
1490                    case CMD_TETHER_MODE_REQUESTED:
1491                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1492                        who.sendMessage(who.obtainMessage(mErrorNotification));
1493                        break;
1494                    default:
1495                       retValue = false;
1496                }
1497                return retValue;
1498            }
1499            void notify(int msgType) {
1500                mErrorNotification = msgType;
1501                for (Object o : mNotifyList) {
1502                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
1503                    sm.sendMessage(sm.obtainMessage(msgType));
1504                }
1505            }
1506
1507        }
1508        class CellDunErrorState extends ErrorState {
1509            @Override
1510            public void enter() {
1511                Log.e(TAG, "Error trying to enable Cell DUN");
1512                notify(TetherInterfaceSM.CMD_CELL_DUN_ERROR);
1513            }
1514        }
1515
1516        class SetIpForwardingEnabledErrorState extends ErrorState {
1517            @Override
1518            public void enter() {
1519                Log.e(TAG, "Error in setIpForwardingEnabled");
1520                notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
1521            }
1522        }
1523
1524        class SetIpForwardingDisabledErrorState extends ErrorState {
1525            @Override
1526            public void enter() {
1527                Log.e(TAG, "Error in setIpForwardingDisabled");
1528                notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
1529            }
1530        }
1531
1532        class StartTetheringErrorState extends ErrorState {
1533            @Override
1534            public void enter() {
1535                Log.e(TAG, "Error in startTethering");
1536                notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
1537                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1538                INetworkManagementService service =
1539                        INetworkManagementService.Stub.asInterface(b);
1540                try {
1541                    service.setIpForwardingEnabled(false);
1542                } catch (Exception e) {}
1543            }
1544        }
1545
1546        class StopTetheringErrorState extends ErrorState {
1547            @Override
1548            public void enter() {
1549                Log.e(TAG, "Error in stopTethering");
1550                notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
1551                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1552                INetworkManagementService service =
1553                         INetworkManagementService.Stub.asInterface(b);
1554                try {
1555                    service.setIpForwardingEnabled(false);
1556                } catch (Exception e) {}
1557            }
1558        }
1559
1560        class SetDnsForwardersErrorState extends ErrorState {
1561            @Override
1562            public void enter() {
1563                Log.e(TAG, "Error in setDnsForwarders");
1564                notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
1565                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1566                INetworkManagementService service =
1567                        INetworkManagementService.Stub.asInterface(b);
1568                try {
1569                    service.stopTethering();
1570                } catch (Exception e) {}
1571                try {
1572                    service.setIpForwardingEnabled(false);
1573                } catch (Exception e) {}
1574            }
1575        }
1576    }
1577
1578    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1579        if (mContext.checkCallingOrSelfPermission(
1580                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1581            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1582                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1583                    Binder.getCallingUid());
1584                    return;
1585        }
1586
1587        pw.println();
1588        pw.println("Tether state:");
1589        synchronized (mIfaces) {
1590            for (Object o : mIfaces.values()) {
1591                pw.println(" "+o.toString());
1592            }
1593        }
1594        pw.println();
1595        return;
1596    }
1597}
1598