WifiStateMachine.java revision e8daf2a7000e12dc0d62cb98b06ca849cf40564a
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 android.net.wifi;
18
19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
24
25/**
26 * TODO: Add soft AP states as part of WIFI_STATE_XXX
27 * Retain WIFI_STATE_ENABLING that indicates driver is loading
28 * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
29 * and WIFI_STATE_FAILED for failure
30 * Deprecate WIFI_STATE_UNKNOWN
31 *
32 * Doing this will simplify the logic for sending broadcasts
33 */
34import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
35import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
36import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
37import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
38import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
39
40import android.app.AlarmManager;
41import android.app.PendingIntent;
42import android.app.backup.IBackupManager;
43import android.bluetooth.BluetoothAdapter;
44import android.content.BroadcastReceiver;
45import android.content.Context;
46import android.content.Intent;
47import android.content.IntentFilter;
48import android.net.ConnectivityManager;
49import android.net.DhcpInfo;
50import android.net.DhcpInfoInternal;
51import android.net.DhcpStateMachine;
52import android.net.InterfaceConfiguration;
53import android.net.LinkAddress;
54import android.net.LinkProperties;
55import android.net.NetworkInfo;
56import android.net.NetworkInfo.DetailedState;
57import android.net.NetworkUtils;
58import android.net.wifi.WpsResult.Status;
59import android.os.Binder;
60import android.os.IBinder;
61import android.os.INetworkManagementService;
62import android.os.Message;
63import android.os.Messenger;
64import android.os.PowerManager;
65import android.os.Process;
66import android.os.RemoteException;
67import android.os.ServiceManager;
68import android.os.SystemProperties;
69import android.os.WorkSource;
70import android.provider.Settings;
71import android.util.EventLog;
72import android.util.Log;
73import android.util.LruCache;
74
75import com.android.internal.app.IBatteryStats;
76import com.android.internal.util.AsyncChannel;
77import com.android.internal.util.Protocol;
78import com.android.internal.util.State;
79import com.android.internal.util.StateMachine;
80
81import java.net.InetAddress;
82import java.util.ArrayList;
83import java.util.List;
84import java.util.concurrent.atomic.AtomicInteger;
85import java.util.concurrent.atomic.AtomicBoolean;
86import java.util.regex.Pattern;
87
88/**
89 * Track the state of Wifi connectivity. All event handling is done here,
90 * and all changes in connectivity state are initiated here.
91 *
92 * @hide
93 */
94public class WifiStateMachine extends StateMachine {
95
96    private static final String TAG = "WifiStateMachine";
97    private static final String NETWORKTYPE = "WIFI";
98    private static final boolean DBG = false;
99
100    /* TODO: This is no more used with the hostapd code. Clean up */
101    private static final String SOFTAP_IFACE = "wl0.1";
102
103    private WifiMonitor mWifiMonitor;
104    private INetworkManagementService nwService;
105    private ConnectivityManager mCm;
106
107    /* Scan results handling */
108    private List<ScanResult> mScanResults;
109    private static final Pattern scanResultPattern = Pattern.compile("\t+");
110    private static final int SCAN_RESULT_CACHE_SIZE = 80;
111    private final LruCache<String, ScanResult> mScanResultCache;
112
113    private String mInterfaceName;
114
115    private int mLastSignalLevel = -1;
116    private String mLastBssid;
117    private int mLastNetworkId;
118    private boolean mEnableRssiPolling = false;
119    private boolean mEnableBackgroundScan = false;
120    private int mRssiPollToken = 0;
121    private int mReconnectCount = 0;
122    private boolean mIsScanMode = false;
123    private boolean mScanResultIsPending = false;
124
125    private boolean mBluetoothConnectionActive = false;
126
127    /**
128     * Interval in milliseconds between polling for RSSI
129     * and linkspeed information
130     */
131    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
132
133    /**
134     * Delay between supplicant restarts upon failure to establish connection
135     */
136    private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
137
138    /**
139     * Number of times we attempt to restart supplicant
140     */
141    private static final int SUPPLICANT_RESTART_TRIES = 5;
142
143    private int mSupplicantRestartCount = 0;
144
145    private LinkProperties mLinkProperties;
146
147    // Wakelock held during wifi start/stop and driver load/unload
148    private PowerManager.WakeLock mWakeLock;
149
150    private Context mContext;
151
152    private DhcpInfoInternal mDhcpInfoInternal;
153    private WifiInfo mWifiInfo;
154    private NetworkInfo mNetworkInfo;
155    private SupplicantStateTracker mSupplicantStateTracker;
156    private WpsStateMachine mWpsStateMachine;
157    private DhcpStateMachine mDhcpStateMachine;
158
159    private AlarmManager mAlarmManager;
160    private PendingIntent mScanIntent;
161    /* Tracks current frequency mode */
162    private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
163
164    /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
165    private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
166
167    // Channel for sending replies.
168    private AsyncChannel mReplyChannel = new AsyncChannel();
169
170    // Event log tags (must be in sync with event-log-tags)
171    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
172    private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
173    private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
174
175    /* The base for wifi message types */
176    static final int BASE = Protocol.BASE_WIFI;
177    /* Load the driver */
178    static final int CMD_LOAD_DRIVER                      = BASE + 1;
179    /* Unload the driver */
180    static final int CMD_UNLOAD_DRIVER                    = BASE + 2;
181    /* Indicates driver load succeeded */
182    static final int CMD_LOAD_DRIVER_SUCCESS              = BASE + 3;
183    /* Indicates driver load failed */
184    static final int CMD_LOAD_DRIVER_FAILURE              = BASE + 4;
185    /* Indicates driver unload succeeded */
186    static final int CMD_UNLOAD_DRIVER_SUCCESS            = BASE + 5;
187    /* Indicates driver unload failed */
188    static final int CMD_UNLOAD_DRIVER_FAILURE            = BASE + 6;
189
190    /* Start the supplicant */
191    static final int CMD_START_SUPPLICANT                 = BASE + 11;
192    /* Stop the supplicant */
193    static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
194    /* Start the driver */
195    static final int CMD_START_DRIVER                     = BASE + 13;
196    /* Start the driver */
197    static final int CMD_STOP_DRIVER                      = BASE + 14;
198    /* Indicates Static IP succeded */
199    static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
200    /* Indicates Static IP failed */
201    static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
202
203    /* Start the soft access point */
204    static final int CMD_START_AP                         = BASE + 21;
205    /* Stop the soft access point */
206    static final int CMD_STOP_AP                          = BASE + 22;
207    /* Set the soft access point configuration */
208    static final int CMD_SET_AP_CONFIG                    = BASE + 23;
209    /* Get the soft access point configuration */
210    static final int CMD_GET_AP_CONFIG                    = BASE + 24;
211    /* Set configuration on tether interface */
212    static final int CMD_TETHER_INTERFACE                 = BASE + 25;
213
214    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 26;
215
216    /* Supplicant events */
217    /* Connection to supplicant established */
218    static final int SUP_CONNECTION_EVENT                 = BASE + 31;
219    /* Connection to supplicant lost */
220    static final int SUP_DISCONNECTION_EVENT              = BASE + 32;
221   /* Network connection completed */
222    static final int NETWORK_CONNECTION_EVENT             = BASE + 33;
223    /* Network disconnection completed */
224    static final int NETWORK_DISCONNECTION_EVENT          = BASE + 34;
225    /* Scan results are available */
226    static final int SCAN_RESULTS_EVENT                   = BASE + 35;
227    /* Supplicate state changed */
228    static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 36;
229    /* Password failure and EAP authentication failure */
230    static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 37;
231    /* WPS overlap detected */
232    static final int WPS_OVERLAP_EVENT                    = BASE + 38;
233
234
235    /* Supplicant commands */
236    /* Is supplicant alive ? */
237    static final int CMD_PING_SUPPLICANT                  = BASE + 51;
238    /* Add/update a network configuration */
239    static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
240    /* Delete a network */
241    static final int CMD_REMOVE_NETWORK                   = BASE + 53;
242    /* Enable a network. The device will attempt a connection to the given network. */
243    static final int CMD_ENABLE_NETWORK                   = BASE + 54;
244    /* Enable all networks */
245    static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
246    /* Disable a network. The device does not attempt a connection to the given network. */
247    static final int CMD_DISABLE_NETWORK                  = BASE + 56;
248    /* Blacklist network. De-prioritizes the given BSSID for connection. */
249    static final int CMD_BLACKLIST_NETWORK                = BASE + 57;
250    /* Clear the blacklist network list */
251    static final int CMD_CLEAR_BLACKLIST                  = BASE + 58;
252    /* Save configuration */
253    static final int CMD_SAVE_CONFIG                      = BASE + 59;
254
255    /* Supplicant commands after driver start*/
256    /* Initiate a scan */
257    static final int CMD_START_SCAN                       = BASE + 71;
258    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
259    static final int CMD_SET_SCAN_MODE                    = BASE + 72;
260    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
261    static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
262    /* Disconnect from a network */
263    static final int CMD_DISCONNECT                       = BASE + 74;
264    /* Reconnect to a network */
265    static final int CMD_RECONNECT                        = BASE + 75;
266    /* Reassociate to a network */
267    static final int CMD_REASSOCIATE                      = BASE + 76;
268    /* Controls power mode and suspend mode optimizations
269     *
270     * When high perf mode is enabled, power mode is set to
271     * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
272     *
273     * When high perf mode is disabled, power mode is set to
274     * POWER_MODE_AUTO and suspend mode optimizations are enabled
275     *
276     * Suspend mode optimizations include:
277     * - packet filtering
278     * - turn off roaming
279     * - DTIM wake up settings
280     */
281    static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
282    /* Set the country code */
283    static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
284    /* Request connectivity manager wake lock before driver stop */
285    static final int CMD_REQUEST_CM_WAKELOCK              = BASE + 81;
286    /* Enables RSSI poll */
287    static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
288    /* RSSI poll */
289    static final int CMD_RSSI_POLL                        = BASE + 83;
290    /* Set up packet filtering */
291    static final int CMD_START_PACKET_FILTERING           = BASE + 84;
292    /* Clear packet filter */
293    static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
294
295    /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
296    static final int MULTICAST_V6  = 1;
297    static final int MULTICAST_V4  = 0;
298
299    /* Connect to a specified network (network id
300     * or WifiConfiguration) This involves increasing
301     * the priority of the network, enabling the network
302     * (while disabling others) and issuing a reconnect.
303     * Note that CMD_RECONNECT just does a reconnect to
304     * an existing network. All the networks get enabled
305     * upon a successful connection or a failure.
306     */
307    static final int CMD_CONNECT_NETWORK                  = BASE + 86;
308    /* Save the specified network. This involves adding
309     * an enabled network (if new) and updating the
310     * config and issuing a save on supplicant config.
311     */
312    static final int CMD_SAVE_NETWORK                     = BASE + 87;
313    /* Delete the specified network. This involves
314     * removing the network and issuing a save on
315     * supplicant config.
316     */
317    static final int CMD_FORGET_NETWORK                   = BASE + 88;
318    /* Start Wi-Fi protected setup */
319    static final int CMD_START_WPS                        = BASE + 89;
320    /* Set the frequency band */
321    static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
322    /* Enable background scan for configured networks */
323    static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
324
325    /* Commands from/to the SupplicantStateTracker */
326    /* Reset the supplicant state tracker */
327    static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
328
329    /* Commands/events reported by WpsStateMachine */
330    /* Indicates the completion of WPS activity */
331    static final int WPS_COMPLETED_EVENT                  = BASE + 121;
332    /* Reset the WPS state machine */
333    static final int CMD_RESET_WPS_STATE                  = BASE + 122;
334
335    private static final int CONNECT_MODE   = 1;
336    private static final int SCAN_ONLY_MODE = 2;
337
338    private static final int SCAN_ACTIVE = 1;
339    private static final int SCAN_PASSIVE = 2;
340
341    private static final int SUCCESS = 1;
342    private static final int FAILURE = -1;
343
344    /**
345     * The maximum number of times we will retry a connection to an access point
346     * for which we have failed in acquiring an IP address from DHCP. A value of
347     * N means that we will make N+1 connection attempts in all.
348     * <p>
349     * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
350     * value if a Settings value is not present.
351     */
352    private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
353
354    static final int POWER_MODE_ACTIVE = 1;
355    static final int POWER_MODE_AUTO = 0;
356
357    /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
358    private int mPowerMode = POWER_MODE_AUTO;
359
360    /**
361     * Default framework scan interval in milliseconds. This is used in the scenario in which
362     * wifi chipset does not support background scanning to set up a
363     * periodic wake up scan so that the device can connect to a new access
364     * point on the move. {@link Settings.Secure#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
365     * override this.
366     */
367    private final int mDefaultFrameworkScanIntervalMs;
368
369    /**
370     * Default supplicant scan interval in milliseconds.
371     * {@link Settings.Secure#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} can override this.
372     */
373    private final int mDefaultSupplicantScanIntervalMs;
374
375
376    private static final int MIN_RSSI = -200;
377    private static final int MAX_RSSI = 256;
378
379    /* Constants to indicate if soft ap is running or stopped */
380    private static final int SOFT_AP_STOPPED = 0;
381    private static final int SOFT_AP_RUNNING = 1;
382
383    /* Default parent state */
384    private State mDefaultState = new DefaultState();
385    /* Temporary initial state */
386    private State mInitialState = new InitialState();
387    /* Unloading the driver */
388    private State mDriverUnloadingState = new DriverUnloadingState();
389    /* Loading the driver */
390    private State mDriverUnloadedState = new DriverUnloadedState();
391    /* Driver load/unload failed */
392    private State mDriverFailedState = new DriverFailedState();
393    /* Driver loading */
394    private State mDriverLoadingState = new DriverLoadingState();
395    /* Driver loaded */
396    private State mDriverLoadedState = new DriverLoadedState();
397    /* Driver loaded, waiting for supplicant to start */
398    private State mSupplicantStartingState = new SupplicantStartingState();
399    /* Driver loaded and supplicant ready */
400    private State mSupplicantStartedState = new SupplicantStartedState();
401    /* Waiting for supplicant to stop and monitor to exit */
402    private State mSupplicantStoppingState = new SupplicantStoppingState();
403    /* Driver start issued, waiting for completed event */
404    private State mDriverStartingState = new DriverStartingState();
405    /* Driver started */
406    private State mDriverStartedState = new DriverStartedState();
407    /* Driver stopping */
408    private State mDriverStoppingState = new DriverStoppingState();
409    /* Driver stopped */
410    private State mDriverStoppedState = new DriverStoppedState();
411    /* Scan for networks, no connection will be established */
412    private State mScanModeState = new ScanModeState();
413    /* Connecting to an access point */
414    private State mConnectModeState = new ConnectModeState();
415    /* Fetching IP after network connection (assoc+auth complete) */
416    private State mConnectingState = new ConnectingState();
417    /* Connected with IP addr */
418    private State mConnectedState = new ConnectedState();
419    /* disconnect issued, waiting for network disconnect confirmation */
420    private State mDisconnectingState = new DisconnectingState();
421    /* Network is not connected, supplicant assoc+auth is not complete */
422    private State mDisconnectedState = new DisconnectedState();
423    /* Waiting for WPS to be completed*/
424    private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
425
426    /* Soft ap is running */
427    private State mSoftApStartedState = new SoftApStartedState();
428    /* Soft ap is running and we are tethered through connectivity service */
429    private State mTetheredState = new TetheredState();
430
431
432    /**
433     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
434     *         {@link WifiManager#WIFI_STATE_DISABLING},
435     *         {@link WifiManager#WIFI_STATE_ENABLED},
436     *         {@link WifiManager#WIFI_STATE_ENABLING},
437     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
438     *
439     */
440    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
441
442    /**
443     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
444     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
445     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
446     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
447     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
448     *
449     */
450    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
451
452    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
453    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
454
455    private static final int SCAN_REQUEST = 0;
456    private static final String ACTION_START_SCAN =
457        "com.android.server.WifiManager.action.START_SCAN";
458
459    /**
460     * Keep track of whether WIFI is running.
461     */
462    private boolean mIsRunning = false;
463
464    /**
465     * Keep track of whether we last told the battery stats we had started.
466     */
467    private boolean mReportedRunning = false;
468
469    /**
470     * Most recently set source of starting WIFI.
471     */
472    private final WorkSource mRunningWifiUids = new WorkSource();
473
474    /**
475     * The last reported UIDs that were responsible for starting WIFI.
476     */
477    private final WorkSource mLastRunningWifiUids = new WorkSource();
478
479    private final IBatteryStats mBatteryStats;
480
481    public WifiStateMachine(Context context, String wlanInterface) {
482        super(TAG);
483
484        mContext = context;
485        mInterfaceName = wlanInterface;
486
487        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
488        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
489
490        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
491        nwService = INetworkManagementService.Stub.asInterface(b);
492
493        mWifiMonitor = new WifiMonitor(this);
494        mDhcpInfoInternal = new DhcpInfoInternal();
495        mWifiInfo = new WifiInfo();
496        mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
497        mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
498        mLinkProperties = new LinkProperties();
499
500        mNetworkInfo.setIsAvailable(false);
501        mLinkProperties.clear();
502        mLastBssid = null;
503        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
504        mLastSignalLevel = -1;
505
506        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
507        Intent scanIntent = new Intent(ACTION_START_SCAN, null);
508        mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
509
510        mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
511                com.android.internal.R.integer.config_wifi_framework_scan_interval);
512
513        mDefaultSupplicantScanIntervalMs = mContext.getResources().getInteger(
514                com.android.internal.R.integer.config_wifi_supplicant_scan_interval);
515
516        mContext.registerReceiver(
517            new BroadcastReceiver() {
518                @Override
519                public void onReceive(Context context, Intent intent) {
520                    ArrayList<String> available = intent.getStringArrayListExtra(
521                            ConnectivityManager.EXTRA_AVAILABLE_TETHER);
522                    sendMessage(CMD_TETHER_INTERFACE, available);
523                }
524            },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
525
526        mContext.registerReceiver(
527                new BroadcastReceiver() {
528                    @Override
529                    public void onReceive(Context context, Intent intent) {
530                        startScan(false);
531                    }
532                },
533                new IntentFilter(ACTION_START_SCAN));
534
535        mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
536
537        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
538        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
539
540        addState(mDefaultState);
541            addState(mInitialState, mDefaultState);
542            addState(mDriverUnloadingState, mDefaultState);
543            addState(mDriverUnloadedState, mDefaultState);
544                addState(mDriverFailedState, mDriverUnloadedState);
545            addState(mDriverLoadingState, mDefaultState);
546            addState(mDriverLoadedState, mDefaultState);
547            addState(mSupplicantStartingState, mDefaultState);
548            addState(mSupplicantStartedState, mDefaultState);
549                addState(mDriverStartingState, mSupplicantStartedState);
550                addState(mDriverStartedState, mSupplicantStartedState);
551                    addState(mScanModeState, mDriverStartedState);
552                    addState(mConnectModeState, mDriverStartedState);
553                        addState(mConnectingState, mConnectModeState);
554                        addState(mConnectedState, mConnectModeState);
555                        addState(mDisconnectingState, mConnectModeState);
556                        addState(mDisconnectedState, mConnectModeState);
557                        addState(mWaitForWpsCompletionState, mConnectModeState);
558                addState(mDriverStoppingState, mSupplicantStartedState);
559                addState(mDriverStoppedState, mSupplicantStartedState);
560            addState(mSupplicantStoppingState, mDefaultState);
561            addState(mSoftApStartedState, mDefaultState);
562                addState(mTetheredState, mSoftApStartedState);
563
564        setInitialState(mInitialState);
565
566        if (DBG) setDbg(true);
567
568        //start the state machine
569        start();
570    }
571
572    /*********************************************************
573     * Methods exposed for public use
574     ********************************************************/
575
576    /**
577     * TODO: doc
578     */
579    public boolean syncPingSupplicant(AsyncChannel channel) {
580        Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
581        boolean result = (resultMsg.arg1 != FAILURE);
582        resultMsg.recycle();
583        return result;
584    }
585
586    /**
587     * TODO: doc
588     */
589    public void startScan(boolean forceActive) {
590        sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
591                SCAN_ACTIVE : SCAN_PASSIVE, 0));
592    }
593
594    /**
595     * TODO: doc
596     */
597    public void setWifiEnabled(boolean enable) {
598        mLastEnableUid.set(Binder.getCallingUid());
599        if (enable) {
600            /* Argument is the state that is entered prior to load */
601            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
602            sendMessage(CMD_START_SUPPLICANT);
603        } else {
604            sendMessage(CMD_STOP_SUPPLICANT);
605            /* Argument is the state that is entered upon success */
606            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
607        }
608    }
609
610    /**
611     * TODO: doc
612     */
613    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
614        mLastApEnableUid.set(Binder.getCallingUid());
615        if (enable) {
616            /* Argument is the state that is entered prior to load */
617            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
618            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
619        } else {
620            sendMessage(CMD_STOP_AP);
621            /* Argument is the state that is entered upon success */
622            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
623        }
624    }
625
626    public void setWifiApConfiguration(WifiConfiguration config) {
627        sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
628    }
629
630    public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
631        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
632        WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
633        resultMsg.recycle();
634        return ret;
635    }
636
637    /**
638     * TODO: doc
639     */
640    public int syncGetWifiState() {
641        return mWifiState.get();
642    }
643
644    /**
645     * TODO: doc
646     */
647    public String syncGetWifiStateByName() {
648        switch (mWifiState.get()) {
649            case WIFI_STATE_DISABLING:
650                return "disabling";
651            case WIFI_STATE_DISABLED:
652                return "disabled";
653            case WIFI_STATE_ENABLING:
654                return "enabling";
655            case WIFI_STATE_ENABLED:
656                return "enabled";
657            case WIFI_STATE_UNKNOWN:
658                return "unknown state";
659            default:
660                return "[invalid state]";
661        }
662    }
663
664    /**
665     * TODO: doc
666     */
667    public int syncGetWifiApState() {
668        return mWifiApState.get();
669    }
670
671    /**
672     * TODO: doc
673     */
674    public String syncGetWifiApStateByName() {
675        switch (mWifiApState.get()) {
676            case WIFI_AP_STATE_DISABLING:
677                return "disabling";
678            case WIFI_AP_STATE_DISABLED:
679                return "disabled";
680            case WIFI_AP_STATE_ENABLING:
681                return "enabling";
682            case WIFI_AP_STATE_ENABLED:
683                return "enabled";
684            case WIFI_AP_STATE_FAILED:
685                return "failed";
686            default:
687                return "[invalid state]";
688        }
689    }
690
691    /**
692     * Get status information for the current connection, if any.
693     * @return a {@link WifiInfo} object containing information about the current connection
694     *
695     */
696    public WifiInfo syncRequestConnectionInfo() {
697        return mWifiInfo;
698    }
699
700    public DhcpInfo syncGetDhcpInfo() {
701        synchronized (mDhcpInfoInternal) {
702            return mDhcpInfoInternal.makeDhcpInfo();
703        }
704    }
705
706    /**
707     * TODO: doc
708     */
709    public void setDriverStart(boolean enable) {
710        if (enable) {
711            sendMessage(CMD_START_DRIVER);
712        } else {
713            sendMessage(CMD_STOP_DRIVER);
714        }
715    }
716
717    /**
718     * TODO: doc
719     */
720    public void setScanOnlyMode(boolean enable) {
721      if (enable) {
722          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
723      } else {
724          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
725      }
726    }
727
728    /**
729     * TODO: doc
730     */
731    public void setScanType(boolean active) {
732      if (active) {
733          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
734      } else {
735          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
736      }
737    }
738
739    /**
740     * TODO: doc
741     */
742    public List<ScanResult> syncGetScanResultsList() {
743        return mScanResults;
744    }
745
746    /**
747     * Disconnect from Access Point
748     */
749    public void disconnectCommand() {
750        sendMessage(CMD_DISCONNECT);
751    }
752
753    /**
754     * Initiate a reconnection to AP
755     */
756    public void reconnectCommand() {
757        sendMessage(CMD_RECONNECT);
758    }
759
760    /**
761     * Initiate a re-association to AP
762     */
763    public void reassociateCommand() {
764        sendMessage(CMD_REASSOCIATE);
765    }
766
767    /**
768     * Add a network synchronously
769     *
770     * @return network id of the new network
771     */
772    public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
773        Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
774        int result = resultMsg.arg1;
775        resultMsg.recycle();
776        return result;
777    }
778
779    public List<WifiConfiguration> syncGetConfiguredNetworks() {
780        return WifiConfigStore.getConfiguredNetworks();
781    }
782
783    /**
784     * Delete a network
785     *
786     * @param networkId id of the network to be removed
787     */
788    public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
789        Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
790        boolean result = (resultMsg.arg1 != FAILURE);
791        resultMsg.recycle();
792        return result;
793    }
794
795    /**
796     * Enable a network
797     *
798     * @param netId network id of the network
799     * @param disableOthers true, if all other networks have to be disabled
800     * @return {@code true} if the operation succeeds, {@code false} otherwise
801     */
802    public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
803        Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
804                disableOthers ? 1 : 0);
805        boolean result = (resultMsg.arg1 != FAILURE);
806        resultMsg.recycle();
807        return result;
808    }
809
810    /**
811     * Disable a network
812     *
813     * @param netId network id of the network
814     * @return {@code true} if the operation succeeds, {@code false} otherwise
815     */
816    public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
817        Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId);
818        boolean result = (resultMsg.arg1 != FAILURE);
819        resultMsg.recycle();
820        return result;
821    }
822
823    /**
824     * Blacklist a BSSID. This will avoid the AP if there are
825     * alternate APs to connect
826     *
827     * @param bssid BSSID of the network
828     */
829    public void addToBlacklist(String bssid) {
830        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
831    }
832
833    /**
834     * Clear the blacklist list
835     *
836     */
837    public void clearBlacklist() {
838        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
839    }
840
841    public void connectNetwork(int netId) {
842        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
843    }
844
845    public void connectNetwork(WifiConfiguration wifiConfig) {
846        /* arg1 is used to indicate netId, force a netId value of
847         * WifiConfiguration.INVALID_NETWORK_ID when we are passing
848         * a configuration since the default value of 0 is a valid netId
849         */
850        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
851                0, wifiConfig));
852    }
853
854    public void saveNetwork(WifiConfiguration wifiConfig) {
855        sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig));
856    }
857
858    public void forgetNetwork(int netId) {
859        sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
860    }
861
862    public void startWps(Messenger replyTo, WpsConfiguration config) {
863        Message msg = obtainMessage(CMD_START_WPS, config);
864        msg.replyTo = replyTo;
865        sendMessage(msg);
866    }
867
868    public void enableRssiPolling(boolean enabled) {
869       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
870    }
871
872    public void enableBackgroundScanCommand(boolean enabled) {
873       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
874    }
875
876    public void enableAllNetworks() {
877        sendMessage(CMD_ENABLE_ALL_NETWORKS);
878    }
879
880    /**
881     * Start filtering Multicast v4 packets
882     */
883    public void startFilteringMulticastV4Packets() {
884        mFilteringMulticastV4Packets.set(true);
885        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0));
886    }
887
888    /**
889     * Stop filtering Multicast v4 packets
890     */
891    public void stopFilteringMulticastV4Packets() {
892        mFilteringMulticastV4Packets.set(false);
893        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0));
894    }
895
896    /**
897     * Start filtering Multicast v4 packets
898     */
899    public void startFilteringMulticastV6Packets() {
900        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0));
901    }
902
903    /**
904     * Stop filtering Multicast v4 packets
905     */
906    public void stopFilteringMulticastV6Packets() {
907        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0));
908    }
909
910    /**
911     * Set high performance mode of operation.
912     * Enabling would set active power mode and disable suspend optimizations;
913     * disabling would set auto power mode and enable suspend optimizations
914     * @param enable true if enable, false otherwise
915     */
916    public void setHighPerfModeEnabled(boolean enable) {
917        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
918    }
919
920    /**
921     * Set the country code
922     * @param countryCode following ISO 3166 format
923     * @param persist {@code true} if the setting should be remembered.
924     */
925    public void setCountryCode(String countryCode, boolean persist) {
926        if (persist) {
927            Settings.Secure.putString(mContext.getContentResolver(),
928                    Settings.Secure.WIFI_COUNTRY_CODE,
929                    countryCode);
930        }
931        sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
932    }
933
934    /**
935     * Set the operational frequency band
936     * @param band
937     * @param persist {@code true} if the setting should be remembered.
938     */
939    public void setFrequencyBand(int band, boolean persist) {
940        if (persist) {
941            Settings.Secure.putInt(mContext.getContentResolver(),
942                    Settings.Secure.WIFI_FREQUENCY_BAND,
943                    band);
944        }
945        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
946    }
947
948    /**
949     * Returns the operational frequency band
950     */
951    public int getFrequencyBand() {
952        return mFrequencyBand.get();
953    }
954
955    /**
956     * Returns the wifi configuration file
957     */
958    public String getConfigFile() {
959        return WifiConfigStore.getConfigFile();
960    }
961
962    /**
963     * Send a message indicating bluetooth adapter connection state changed
964     */
965    public void sendBluetoothAdapterStateChange(int state) {
966        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
967    }
968
969    /**
970     * Save configuration on supplicant
971     *
972     * @return {@code true} if the operation succeeds, {@code false} otherwise
973     *
974     * TODO: deprecate this
975     */
976    public boolean syncSaveConfig(AsyncChannel channel) {
977        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
978        boolean result = (resultMsg.arg1 != FAILURE);
979        resultMsg.recycle();
980        return result;
981    }
982
983    /**
984     * Request a wakelock with connectivity service to
985     * keep the device awake until we hand-off from wifi
986     * to an alternate network
987     */
988    public void requestCmWakeLock() {
989        sendMessage(CMD_REQUEST_CM_WAKELOCK);
990    }
991
992    public void updateBatteryWorkSource(WorkSource newSource) {
993        synchronized (mRunningWifiUids) {
994            try {
995                if (newSource != null) {
996                    mRunningWifiUids.set(newSource);
997                }
998                if (mIsRunning) {
999                    if (mReportedRunning) {
1000                        // If the work source has changed since last time, need
1001                        // to remove old work from battery stats.
1002                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
1003                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
1004                                    mRunningWifiUids);
1005                            mLastRunningWifiUids.set(mRunningWifiUids);
1006                        }
1007                    } else {
1008                        // Now being started, report it.
1009                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
1010                        mLastRunningWifiUids.set(mRunningWifiUids);
1011                        mReportedRunning = true;
1012                    }
1013                } else {
1014                    if (mReportedRunning) {
1015                        // Last reported we were running, time to stop.
1016                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
1017                        mLastRunningWifiUids.clear();
1018                        mReportedRunning = false;
1019                    }
1020                }
1021                mWakeLock.setWorkSource(newSource);
1022            } catch (RemoteException ignore) {
1023            }
1024        }
1025    }
1026
1027    @Override
1028    public String toString() {
1029        StringBuffer sb = new StringBuffer();
1030        String LS = System.getProperty("line.separator");
1031        sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
1032        sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
1033        sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
1034        sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
1035        sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
1036        sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
1037        sb.append("mLastBssid ").append(mLastBssid).append(LS);
1038        sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
1039        sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
1040        sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
1041        sb.append("Supplicant status").append(LS)
1042                .append(WifiNative.statusCommand()).append(LS).append(LS);
1043
1044        sb.append(WifiConfigStore.dump());
1045        return sb.toString();
1046    }
1047
1048    /*********************************************************
1049     * Internal private functions
1050     ********************************************************/
1051
1052    private void checkAndSetConnectivityInstance() {
1053        if (mCm == null) {
1054            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
1055        }
1056    }
1057
1058    private boolean startTethering(ArrayList<String> available) {
1059
1060        boolean wifiAvailable = false;
1061
1062        checkAndSetConnectivityInstance();
1063
1064        String[] wifiRegexs = mCm.getTetherableWifiRegexs();
1065
1066        for (String intf : available) {
1067            for (String regex : wifiRegexs) {
1068                if (intf.matches(regex)) {
1069
1070                    InterfaceConfiguration ifcg = null;
1071                    try {
1072                        ifcg = nwService.getInterfaceConfig(intf);
1073                        if (ifcg != null) {
1074                            /* IP/netmask: 192.168.43.1/255.255.255.0 */
1075                            ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
1076                                    "192.168.43.1"), 24);
1077                            ifcg.interfaceFlags = "[up]";
1078
1079                            nwService.setInterfaceConfig(intf, ifcg);
1080                        }
1081                    } catch (Exception e) {
1082                        Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
1083                        setWifiApEnabled(null, false);
1084                        return false;
1085                    }
1086
1087                    if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1088                        Log.e(TAG, "Error tethering on " + intf);
1089                        setWifiApEnabled(null, false);
1090                        return false;
1091                    }
1092                    return true;
1093                }
1094            }
1095        }
1096        // We found no interfaces to tether
1097        return false;
1098    }
1099
1100    private void stopTethering() {
1101
1102        checkAndSetConnectivityInstance();
1103
1104        /* Clear the interface config to allow dhcp correctly configure new
1105           ip settings */
1106        InterfaceConfiguration ifcg = null;
1107        try {
1108            ifcg = nwService.getInterfaceConfig(mInterfaceName);
1109            if (ifcg != null) {
1110                ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
1111                            "0.0.0.0"), 0);
1112                nwService.setInterfaceConfig(mInterfaceName, ifcg);
1113            }
1114        } catch (Exception e) {
1115            Log.e(TAG, "Error resetting interface " + mInterfaceName + ", :" + e);
1116        }
1117
1118        if (mCm.untether(mInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1119            Log.e(TAG, "Untether initiate failed!");
1120        }
1121    }
1122
1123    /**
1124     * Set the country code from the system setting value, if any.
1125     */
1126    private void setCountryCode() {
1127        String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
1128                Settings.Secure.WIFI_COUNTRY_CODE);
1129        if (countryCode != null && !countryCode.isEmpty()) {
1130            setCountryCode(countryCode, false);
1131        } else {
1132            //use driver default
1133        }
1134    }
1135
1136    /**
1137     * Set the frequency band from the system setting value, if any.
1138     */
1139    private void setFrequencyBand() {
1140        int band = Settings.Secure.getInt(mContext.getContentResolver(),
1141                Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
1142        setFrequencyBand(band, false);
1143    }
1144
1145    private void setWifiState(int wifiState) {
1146        final int previousWifiState = mWifiState.get();
1147
1148        try {
1149            if (wifiState == WIFI_STATE_ENABLED) {
1150                mBatteryStats.noteWifiOn();
1151            } else if (wifiState == WIFI_STATE_DISABLED) {
1152                mBatteryStats.noteWifiOff();
1153            }
1154        } catch (RemoteException e) {
1155            Log.e(TAG, "Failed to note battery stats in wifi");
1156        }
1157
1158        mWifiState.set(wifiState);
1159
1160        if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName());
1161
1162        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
1163        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1164        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
1165        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
1166        mContext.sendStickyBroadcast(intent);
1167    }
1168
1169    private void setWifiApState(int wifiApState) {
1170        final int previousWifiApState = mWifiApState.get();
1171
1172        try {
1173            if (wifiApState == WIFI_AP_STATE_ENABLED) {
1174                mBatteryStats.noteWifiOn();
1175            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
1176                mBatteryStats.noteWifiOff();
1177            }
1178        } catch (RemoteException e) {
1179            Log.d(TAG, "Failed to note battery stats in wifi");
1180        }
1181
1182        // Update state
1183        mWifiApState.set(wifiApState);
1184
1185        if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName());
1186
1187        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
1188        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1189        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
1190        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
1191        mContext.sendStickyBroadcast(intent);
1192    }
1193
1194    /**
1195     * Parse the scan result line passed to us by wpa_supplicant (helper).
1196     * @param line the line to parse
1197     * @return the {@link ScanResult} object
1198     */
1199    private ScanResult parseScanResult(String line) {
1200        ScanResult scanResult = null;
1201        if (line != null) {
1202            /*
1203             * Cache implementation (LinkedHashMap) is not synchronized, thus,
1204             * must synchronized here!
1205             */
1206            synchronized (mScanResultCache) {
1207                String[] result = scanResultPattern.split(line);
1208                if (3 <= result.length && result.length <= 5) {
1209                    String bssid = result[0];
1210                    // bssid | frequency | level | flags | ssid
1211                    int frequency;
1212                    int level;
1213                    try {
1214                        frequency = Integer.parseInt(result[1]);
1215                        level = Integer.parseInt(result[2]);
1216                        /* some implementations avoid negative values by adding 256
1217                         * so we need to adjust for that here.
1218                         */
1219                        if (level > 0) level -= 256;
1220                    } catch (NumberFormatException e) {
1221                        frequency = 0;
1222                        level = 0;
1223                    }
1224
1225                    /*
1226                     * The formatting of the results returned by
1227                     * wpa_supplicant is intended to make the fields
1228                     * line up nicely when printed,
1229                     * not to make them easy to parse. So we have to
1230                     * apply some heuristics to figure out which field
1231                     * is the SSID and which field is the flags.
1232                     */
1233                    String ssid;
1234                    String flags;
1235                    if (result.length == 4) {
1236                        if (result[3].charAt(0) == '[') {
1237                            flags = result[3];
1238                            ssid = "";
1239                        } else {
1240                            flags = "";
1241                            ssid = result[3];
1242                        }
1243                    } else if (result.length == 5) {
1244                        flags = result[3];
1245                        ssid = result[4];
1246                    } else {
1247                        // Here, we must have 3 fields: no flags and ssid
1248                        // set
1249                        flags = "";
1250                        ssid = "";
1251                    }
1252
1253                    // bssid + ssid is the hash key
1254                    String key = bssid + ssid;
1255                    scanResult = mScanResultCache.get(key);
1256                    if (scanResult != null) {
1257                        scanResult.level = level;
1258                        scanResult.SSID = ssid;
1259                        scanResult.capabilities = flags;
1260                        scanResult.frequency = frequency;
1261                    } else {
1262                        // Do not add scan results that have no SSID set
1263                        if (0 < ssid.trim().length()) {
1264                            scanResult =
1265                                new ScanResult(
1266                                    ssid, bssid, flags, level, frequency);
1267                            mScanResultCache.put(key, scanResult);
1268                        }
1269                    }
1270                } else {
1271                    Log.w(TAG, "Misformatted scan result text with " +
1272                          result.length + " fields: " + line);
1273                }
1274            }
1275        }
1276
1277        return scanResult;
1278    }
1279
1280    /**
1281     * scanResults input format
1282     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
1283     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
1284     */
1285    private void setScanResults(String scanResults) {
1286        if (scanResults == null) {
1287            return;
1288        }
1289
1290        List<ScanResult> scanList = new ArrayList<ScanResult>();
1291
1292        int lineCount = 0;
1293
1294        int scanResultsLen = scanResults.length();
1295        // Parse the result string, keeping in mind that the last line does
1296        // not end with a newline.
1297        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
1298            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
1299                ++lineCount;
1300
1301                if (lineCount == 1) {
1302                    lineBeg = lineEnd + 1;
1303                    continue;
1304                }
1305                if (lineEnd > lineBeg) {
1306                    String line = scanResults.substring(lineBeg, lineEnd);
1307                    ScanResult scanResult = parseScanResult(line);
1308                    if (scanResult != null) {
1309                        scanList.add(scanResult);
1310                    } else {
1311                        //TODO: hidden network handling
1312                    }
1313                }
1314                lineBeg = lineEnd + 1;
1315            }
1316        }
1317
1318        mScanResults = scanList;
1319    }
1320
1321    private String fetchSSID() {
1322        String status = WifiNative.statusCommand();
1323        if (status == null) {
1324            return null;
1325        }
1326        // extract ssid from a series of "name=value"
1327        String[] lines = status.split("\n");
1328        for (String line : lines) {
1329            String[] prop = line.split(" *= *");
1330            if (prop.length < 2) continue;
1331            String name = prop[0];
1332            String value = prop[1];
1333            if (name.equalsIgnoreCase("ssid")) return value;
1334        }
1335        return null;
1336    }
1337
1338    /*
1339     * Fetch RSSI and linkspeed on current connection
1340     */
1341    private void fetchRssiAndLinkSpeedNative() {
1342        int newRssi = WifiNative.getRssiCommand();
1343        if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
1344            /* some implementations avoid negative values by adding 256
1345             * so we need to adjust for that here.
1346             */
1347            if (newRssi > 0) newRssi -= 256;
1348            mWifiInfo.setRssi(newRssi);
1349            /*
1350             * Rather then sending the raw RSSI out every time it
1351             * changes, we precalculate the signal level that would
1352             * be displayed in the status bar, and only send the
1353             * broadcast if that much more coarse-grained number
1354             * changes. This cuts down greatly on the number of
1355             * broadcasts, at the cost of not mWifiInforming others
1356             * interested in RSSI of all the changes in signal
1357             * level.
1358             */
1359            // TODO: The second arg to the call below needs to be a symbol somewhere, but
1360            // it's actually the size of an array of icons that's private
1361            // to StatusBar Policy.
1362            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
1363            if (newSignalLevel != mLastSignalLevel) {
1364                sendRssiChangeBroadcast(newRssi);
1365            }
1366            mLastSignalLevel = newSignalLevel;
1367        } else {
1368            mWifiInfo.setRssi(MIN_RSSI);
1369        }
1370        int newLinkSpeed = WifiNative.getLinkSpeedCommand();
1371        if (newLinkSpeed != -1) {
1372            mWifiInfo.setLinkSpeed(newLinkSpeed);
1373        }
1374    }
1375
1376    private void setHighPerfModeEnabledNative(boolean enable) {
1377        if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
1378            Log.e(TAG, "set suspend optimizations failed!");
1379        }
1380        if (enable) {
1381            if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
1382                Log.e(TAG, "set power mode active failed!");
1383            }
1384        } else {
1385            if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
1386                Log.e(TAG, "set power mode auto failed!");
1387            }
1388        }
1389    }
1390
1391    private void configureLinkProperties() {
1392        if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1393            mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
1394        } else {
1395            synchronized (mDhcpInfoInternal) {
1396                mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
1397            }
1398            mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1399        }
1400        mLinkProperties.setInterfaceName(mInterfaceName);
1401        Log.d(TAG, "netId=" + mLastNetworkId  + " Link configured: " + mLinkProperties.toString());
1402    }
1403
1404    private int getMaxDhcpRetries() {
1405        return Settings.Secure.getInt(mContext.getContentResolver(),
1406                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
1407                                      DEFAULT_MAX_DHCP_RETRIES);
1408    }
1409
1410    private void sendScanResultsAvailableBroadcast() {
1411        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1412        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1413        mContext.sendBroadcast(intent);
1414    }
1415
1416    private void sendRssiChangeBroadcast(final int newRssi) {
1417        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
1418        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1419        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
1420        mContext.sendBroadcast(intent);
1421    }
1422
1423    private void sendNetworkStateChangeBroadcast(String bssid) {
1424        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1425        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1426                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1427        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
1428        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
1429        if (bssid != null)
1430            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
1431        if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED)
1432            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
1433        mContext.sendStickyBroadcast(intent);
1434    }
1435
1436    private void sendErrorBroadcast(int errorCode) {
1437        Intent intent = new Intent(WifiManager.ERROR_ACTION);
1438        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1439        intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
1440        mContext.sendBroadcast(intent);
1441    }
1442
1443    private void sendLinkConfigurationChangedBroadcast() {
1444        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
1445        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1446        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
1447        mContext.sendBroadcast(intent);
1448    }
1449
1450    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
1451        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
1452        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1453        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
1454        mContext.sendBroadcast(intent);
1455    }
1456
1457    /**
1458     * Record the detailed state of a network.
1459     * @param state the new @{code DetailedState}
1460     */
1461    private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
1462        Log.d(TAG, "setDetailed state, old ="
1463                + mNetworkInfo.getDetailedState() + " and new state=" + state);
1464        if (state != mNetworkInfo.getDetailedState()) {
1465            mNetworkInfo.setDetailedState(state, null, null);
1466        }
1467    }
1468
1469    private DetailedState getNetworkDetailedState() {
1470        return mNetworkInfo.getDetailedState();
1471    }
1472
1473
1474    private SupplicantState handleSupplicantStateChange(Message message) {
1475        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
1476        SupplicantState state = stateChangeResult.state;
1477        // Supplicant state change
1478        // [31-13] Reserved for future use
1479        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
1480        // 50023 supplicant_state_changed (custom|1|5)
1481        EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
1482        mWifiInfo.setSupplicantState(state);
1483        // Network id is only valid when we start connecting
1484        if (SupplicantState.isConnecting(state)) {
1485            mWifiInfo.setNetworkId(stateChangeResult.networkId);
1486        } else {
1487            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1488        }
1489
1490        if (state == SupplicantState.ASSOCIATING) {
1491            /* BSSID is valid only in ASSOCIATING state */
1492            mWifiInfo.setBSSID(stateChangeResult.BSSID);
1493        }
1494
1495        mSupplicantStateTracker.sendMessage(Message.obtain(message));
1496        mWpsStateMachine.sendMessage(Message.obtain(message));
1497
1498        return state;
1499    }
1500
1501    /**
1502     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
1503     * using the interface, stopping DHCP & disabling interface
1504     */
1505    private void handleNetworkDisconnect() {
1506        Log.d(TAG, "Stopping DHCP and clearing IP");
1507
1508        /*
1509         * stop DHCP
1510         */
1511        if (mDhcpStateMachine != null) {
1512            mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
1513            mDhcpStateMachine.quit();
1514            mDhcpStateMachine = null;
1515        }
1516
1517        try {
1518            nwService.clearInterfaceAddresses(mInterfaceName);
1519        } catch (Exception e) {
1520            Log.e(TAG, "Failed to clear IP addresses on disconnect" + e);
1521        }
1522
1523        /* Reset data structures */
1524        mWifiInfo.setInetAddress(null);
1525        mWifiInfo.setBSSID(null);
1526        mWifiInfo.setSSID(null);
1527        mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
1528        mWifiInfo.setRssi(MIN_RSSI);
1529        mWifiInfo.setLinkSpeed(-1);
1530
1531        /* send event to CM & network change broadcast */
1532        setNetworkDetailedState(DetailedState.DISCONNECTED);
1533        sendNetworkStateChangeBroadcast(mLastBssid);
1534
1535        /* Clear network properties */
1536        mLinkProperties.clear();
1537        /* Clear IP settings if the network used DHCP */
1538        if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
1539            WifiConfigStore.clearIpConfiguration(mLastNetworkId);
1540        }
1541
1542        mLastBssid= null;
1543        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
1544    }
1545
1546    void handlePreDhcpSetup() {
1547        if (!mBluetoothConnectionActive) {
1548            /*
1549             * There are problems setting the Wi-Fi driver's power
1550             * mode to active when bluetooth coexistence mode is
1551             * enabled or sense.
1552             * <p>
1553             * We set Wi-Fi to active mode when
1554             * obtaining an IP address because we've found
1555             * compatibility issues with some routers with low power
1556             * mode.
1557             * <p>
1558             * In order for this active power mode to properly be set,
1559             * we disable coexistence mode until we're done with
1560             * obtaining an IP address.  One exception is if we
1561             * are currently connected to a headset, since disabling
1562             * coexistence would interrupt that connection.
1563             */
1564            // Disable the coexistence mode
1565            WifiNative.setBluetoothCoexistenceModeCommand(
1566                    WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
1567        }
1568
1569        mPowerMode =  WifiNative.getPowerModeCommand();
1570        if (mPowerMode < 0) {
1571            // Handle the case where supplicant driver does not support
1572            // getPowerModeCommand.
1573            mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
1574        }
1575        if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
1576            WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
1577        }
1578    }
1579
1580
1581    void handlePostDhcpSetup() {
1582        /* restore power mode */
1583        WifiNative.setPowerModeCommand(mPowerMode);
1584
1585        // Set the coexistence mode back to its default value
1586        WifiNative.setBluetoothCoexistenceModeCommand(
1587                WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
1588    }
1589
1590    private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
1591        synchronized (mDhcpInfoInternal) {
1592            mDhcpInfoInternal = dhcpInfoInternal;
1593        }
1594        mLastSignalLevel = -1; // force update of signal strength
1595        WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
1596        InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
1597        mWifiInfo.setInetAddress(addr);
1598        if (getNetworkDetailedState() == DetailedState.CONNECTED) {
1599            //DHCP renewal in connected state
1600            LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
1601            linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
1602            linkProperties.setInterfaceName(mInterfaceName);
1603            if (!linkProperties.equals(mLinkProperties)) {
1604                Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
1605                    + " old: " + mLinkProperties + "new: " + linkProperties);
1606                mLinkProperties = linkProperties;
1607                sendLinkConfigurationChangedBroadcast();
1608            }
1609        } else {
1610            configureLinkProperties();
1611            setNetworkDetailedState(DetailedState.CONNECTED);
1612            sendNetworkStateChangeBroadcast(mLastBssid);
1613        }
1614    }
1615
1616    private void handleFailedIpConfiguration() {
1617        Log.e(TAG, "IP configuration failed");
1618
1619        mWifiInfo.setInetAddress(null);
1620        /**
1621         * If we've exceeded the maximum number of retries for DHCP
1622         * to a given network, disable the network
1623         */
1624        if (++mReconnectCount > getMaxDhcpRetries()) {
1625            Log.e(TAG, "Failed " +
1626                    mReconnectCount + " times, Disabling " + mLastNetworkId);
1627            WifiConfigStore.disableNetwork(mLastNetworkId);
1628            mReconnectCount = 0;
1629        }
1630
1631        /* DHCP times out after about 30 seconds, we do a
1632         * disconnect and an immediate reconnect to try again
1633         */
1634        WifiNative.disconnectCommand();
1635        WifiNative.reconnectCommand();
1636    }
1637
1638    private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
1639        if (config == null) {
1640            config = WifiApConfigStore.getApConfiguration();
1641        } else {
1642            WifiApConfigStore.setApConfiguration(config);
1643        }
1644        try {
1645            if (currentStatus == SOFT_AP_STOPPED) {
1646                nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1647            } else if (currentStatus == SOFT_AP_RUNNING) {
1648                //nwService.setAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1649                //TODO: when we have a control channel to hostapd, we should not need to do this
1650                nwService.stopAccessPoint(mInterfaceName);
1651                nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1652            }
1653        } catch (Exception e) {
1654            Log.e(TAG, "Exception in softap start " + e);
1655            try {
1656                nwService.stopAccessPoint(mInterfaceName);
1657                nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
1658            } catch (Exception ee) {
1659                Log.e(TAG, "Exception during softap restart : " + ee);
1660                return false;
1661            }
1662        }
1663        return true;
1664    }
1665
1666
1667    /*********************************************************
1668     * Notifications from WifiMonitor
1669     ********************************************************/
1670
1671    /**
1672     * Stores supplicant state change information passed from WifiMonitor
1673     */
1674    static class StateChangeResult {
1675        StateChangeResult(int networkId, String BSSID, SupplicantState state) {
1676            this.state = state;
1677            this.BSSID = BSSID;
1678            this.networkId = networkId;
1679        }
1680        int networkId;
1681        String BSSID;
1682        SupplicantState state;
1683    }
1684
1685    /**
1686     * Send the tracker a notification that a user provided
1687     * configuration caused authentication failure - this could
1688     * be a password failure or a EAP authentication failure
1689     */
1690    void notifyAuthenticationFailure() {
1691        sendMessage(AUTHENTICATION_FAILURE_EVENT);
1692    }
1693
1694    /**
1695     * Send a notification that the supplicant has detected overlapped
1696     * WPS sessions
1697     */
1698    void notifyWpsOverlap() {
1699        sendMessage(WPS_OVERLAP_EVENT);
1700    }
1701
1702    /**
1703     * Send the tracker a notification that a connection to the supplicant
1704     * daemon has been established.
1705     */
1706    void notifySupplicantConnection() {
1707        sendMessage(SUP_CONNECTION_EVENT);
1708    }
1709
1710    /**
1711     * Send the tracker a notification that connection to the supplicant
1712     * daemon is lost
1713     */
1714    void notifySupplicantLost() {
1715        sendMessage(SUP_DISCONNECTION_EVENT);
1716    }
1717
1718    /**
1719     * Send the tracker a notification that the state of Wifi connectivity
1720     * has changed.
1721     * @param networkId the configured network on which the state change occurred
1722     * @param newState the new network state
1723     * @param BSSID when the new state is {@link DetailedState#CONNECTED
1724     * NetworkInfo.DetailedState.CONNECTED},
1725     * this is the MAC address of the access point. Otherwise, it
1726     * is {@code null}.
1727     */
1728    void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
1729        if (newState == NetworkInfo.DetailedState.CONNECTED) {
1730            sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, networkId, 0, BSSID));
1731        } else {
1732            sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, networkId, 0, BSSID));
1733        }
1734    }
1735
1736    /**
1737     * Send the tracker a notification that the state of the supplicant
1738     * has changed.
1739     * @param networkId the configured network on which the state change occurred
1740     * @param newState the new {@code SupplicantState}
1741     */
1742    void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
1743        sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
1744                new StateChangeResult(networkId, BSSID, newState)));
1745    }
1746
1747    /**
1748     * Send the tracker a notification that a scan has completed, and results
1749     * are available.
1750     */
1751    void notifyScanResultsAvailable() {
1752        /**
1753         * Switch scan mode over to passive.
1754         * Turning off scan-only mode happens only in "Connect" mode
1755         */
1756        setScanType(false);
1757        sendMessage(SCAN_RESULTS_EVENT);
1758    }
1759
1760    void notifyDriverHung() {
1761        setWifiEnabled(false);
1762        setWifiEnabled(true);
1763    }
1764
1765    /********************************************************
1766     * HSM states
1767     *******************************************************/
1768
1769    class DefaultState extends State {
1770        @Override
1771        public boolean processMessage(Message message) {
1772            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1773            switch (message.what) {
1774                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
1775                    mBluetoothConnectionActive = (message.arg1 !=
1776                            BluetoothAdapter.STATE_DISCONNECTED);
1777                    break;
1778                    /* Synchronous call returns */
1779                case CMD_PING_SUPPLICANT:
1780                case CMD_ENABLE_NETWORK:
1781                case CMD_DISABLE_NETWORK:
1782                case CMD_ADD_OR_UPDATE_NETWORK:
1783                case CMD_REMOVE_NETWORK:
1784                case CMD_SAVE_CONFIG:
1785                    mReplyChannel.replyToMessage(message, message.what, FAILURE);
1786                    break;
1787                case CMD_ENABLE_RSSI_POLL:
1788                    mEnableRssiPolling = (message.arg1 == 1);
1789                    break;
1790                case CMD_ENABLE_BACKGROUND_SCAN:
1791                    mEnableBackgroundScan = (message.arg1 == 1);
1792                    break;
1793                case CMD_SET_AP_CONFIG:
1794                    WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
1795                    break;
1796                case CMD_GET_AP_CONFIG:
1797                    WifiConfiguration config = WifiApConfigStore.getApConfiguration();
1798                    mReplyChannel.replyToMessage(message, message.what, config);
1799                    break;
1800                    /* Discard */
1801                case CMD_LOAD_DRIVER:
1802                case CMD_UNLOAD_DRIVER:
1803                case CMD_START_SUPPLICANT:
1804                case CMD_STOP_SUPPLICANT:
1805                case CMD_START_DRIVER:
1806                case CMD_STOP_DRIVER:
1807                case CMD_START_AP:
1808                case CMD_STOP_AP:
1809                case CMD_TETHER_INTERFACE:
1810                case CMD_START_SCAN:
1811                case CMD_DISCONNECT:
1812                case CMD_RECONNECT:
1813                case CMD_REASSOCIATE:
1814                case SUP_CONNECTION_EVENT:
1815                case SUP_DISCONNECTION_EVENT:
1816                case NETWORK_CONNECTION_EVENT:
1817                case NETWORK_DISCONNECTION_EVENT:
1818                case SCAN_RESULTS_EVENT:
1819                case SUPPLICANT_STATE_CHANGE_EVENT:
1820                case AUTHENTICATION_FAILURE_EVENT:
1821                case WPS_OVERLAP_EVENT:
1822                case CMD_BLACKLIST_NETWORK:
1823                case CMD_CLEAR_BLACKLIST:
1824                case CMD_SET_SCAN_MODE:
1825                case CMD_SET_SCAN_TYPE:
1826                case CMD_SET_HIGH_PERF_MODE:
1827                case CMD_SET_COUNTRY_CODE:
1828                case CMD_SET_FREQUENCY_BAND:
1829                case CMD_REQUEST_CM_WAKELOCK:
1830                case CMD_CONNECT_NETWORK:
1831                case CMD_SAVE_NETWORK:
1832                case CMD_FORGET_NETWORK:
1833                case CMD_RSSI_POLL:
1834                case CMD_ENABLE_ALL_NETWORKS:
1835                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
1836                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1837                    break;
1838                case CMD_START_WPS:
1839                    /* Return failure when the state machine cannot handle WPS initiation*/
1840                    mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
1841                                new WpsResult(Status.FAILURE));
1842                    break;
1843                default:
1844                    Log.e(TAG, "Error! unhandled message" + message);
1845                    break;
1846            }
1847            return HANDLED;
1848        }
1849    }
1850
1851    class InitialState extends State {
1852        @Override
1853        //TODO: could move logging into a common class
1854        public void enter() {
1855            if (DBG) Log.d(TAG, getName() + "\n");
1856            // [31-8] Reserved for future use
1857            // [7 - 0] HSM state change
1858            // 50021 wifi_state_changed (custom|1|5)
1859            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1860
1861            WifiApConfigStore.initialize(mContext);
1862
1863            if (WifiNative.isDriverLoaded()) {
1864                transitionTo(mDriverLoadedState);
1865            }
1866            else {
1867                transitionTo(mDriverUnloadedState);
1868            }
1869        }
1870    }
1871
1872    class DriverLoadingState extends State {
1873        @Override
1874        public void enter() {
1875            if (DBG) Log.d(TAG, getName() + "\n");
1876            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1877
1878            final Message message = new Message();
1879            message.copyFrom(getCurrentMessage());
1880            /* TODO: add a timeout to fail when driver load is hung.
1881             * Similarly for driver unload.
1882             */
1883            new Thread(new Runnable() {
1884                public void run() {
1885                    mWakeLock.acquire();
1886                    //enabling state
1887                    switch(message.arg1) {
1888                        case WIFI_STATE_ENABLING:
1889                            setWifiState(WIFI_STATE_ENABLING);
1890                            break;
1891                        case WIFI_AP_STATE_ENABLING:
1892                            setWifiApState(WIFI_AP_STATE_ENABLING);
1893                            break;
1894                    }
1895
1896                    if(WifiNative.loadDriver()) {
1897                        Log.d(TAG, "Driver load successful");
1898                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
1899                    } else {
1900                        Log.e(TAG, "Failed to load driver!");
1901                        switch(message.arg1) {
1902                            case WIFI_STATE_ENABLING:
1903                                setWifiState(WIFI_STATE_UNKNOWN);
1904                                break;
1905                            case WIFI_AP_STATE_ENABLING:
1906                                setWifiApState(WIFI_AP_STATE_FAILED);
1907                                break;
1908                        }
1909                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
1910                    }
1911                    mWakeLock.release();
1912                }
1913            }).start();
1914        }
1915
1916        @Override
1917        public boolean processMessage(Message message) {
1918            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1919            switch (message.what) {
1920                case CMD_LOAD_DRIVER_SUCCESS:
1921                    transitionTo(mDriverLoadedState);
1922                    break;
1923                case CMD_LOAD_DRIVER_FAILURE:
1924                    transitionTo(mDriverFailedState);
1925                    break;
1926                case CMD_LOAD_DRIVER:
1927                case CMD_UNLOAD_DRIVER:
1928                case CMD_START_SUPPLICANT:
1929                case CMD_STOP_SUPPLICANT:
1930                case CMD_START_AP:
1931                case CMD_STOP_AP:
1932                case CMD_START_DRIVER:
1933                case CMD_STOP_DRIVER:
1934                case CMD_SET_SCAN_MODE:
1935                case CMD_SET_SCAN_TYPE:
1936                case CMD_SET_HIGH_PERF_MODE:
1937                case CMD_SET_COUNTRY_CODE:
1938                case CMD_SET_FREQUENCY_BAND:
1939                case CMD_START_PACKET_FILTERING:
1940                case CMD_STOP_PACKET_FILTERING:
1941                    deferMessage(message);
1942                    break;
1943                default:
1944                    return NOT_HANDLED;
1945            }
1946            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1947            return HANDLED;
1948        }
1949    }
1950
1951    class DriverLoadedState extends State {
1952        @Override
1953        public void enter() {
1954            if (DBG) Log.d(TAG, getName() + "\n");
1955            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1956        }
1957        @Override
1958        public boolean processMessage(Message message) {
1959            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
1960            switch(message.what) {
1961                case CMD_UNLOAD_DRIVER:
1962                    transitionTo(mDriverUnloadingState);
1963                    break;
1964                case CMD_START_SUPPLICANT:
1965                    if(WifiNative.startSupplicant()) {
1966                        Log.d(TAG, "Supplicant start successful");
1967                        mWifiMonitor.startMonitoring();
1968                        transitionTo(mSupplicantStartingState);
1969                    } else {
1970                        Log.e(TAG, "Failed to start supplicant!");
1971                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
1972                    }
1973                    break;
1974                case CMD_START_AP:
1975                    if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_STOPPED)) {
1976                        Log.d(TAG, "Soft AP start successful");
1977                        setWifiApState(WIFI_AP_STATE_ENABLED);
1978                        transitionTo(mSoftApStartedState);
1979                    } else {
1980                        Log.d(TAG, "Soft AP start failed");
1981                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
1982                    }
1983                    break;
1984                default:
1985                    return NOT_HANDLED;
1986            }
1987            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
1988            return HANDLED;
1989        }
1990    }
1991
1992    class DriverUnloadingState extends State {
1993        @Override
1994        public void enter() {
1995            if (DBG) Log.d(TAG, getName() + "\n");
1996            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
1997
1998            final Message message = new Message();
1999            message.copyFrom(getCurrentMessage());
2000            new Thread(new Runnable() {
2001                public void run() {
2002                    if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2003                    mWakeLock.acquire();
2004                    if(WifiNative.unloadDriver()) {
2005                        Log.d(TAG, "Driver unload successful");
2006                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
2007
2008                        switch(message.arg1) {
2009                            case WIFI_STATE_DISABLED:
2010                            case WIFI_STATE_UNKNOWN:
2011                                setWifiState(message.arg1);
2012                                break;
2013                            case WIFI_AP_STATE_DISABLED:
2014                            case WIFI_AP_STATE_FAILED:
2015                                setWifiApState(message.arg1);
2016                                break;
2017                        }
2018                    } else {
2019                        Log.e(TAG, "Failed to unload driver!");
2020                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
2021
2022                        switch(message.arg1) {
2023                            case WIFI_STATE_DISABLED:
2024                            case WIFI_STATE_UNKNOWN:
2025                                setWifiState(WIFI_STATE_UNKNOWN);
2026                                break;
2027                            case WIFI_AP_STATE_DISABLED:
2028                            case WIFI_AP_STATE_FAILED:
2029                                setWifiApState(WIFI_AP_STATE_FAILED);
2030                                break;
2031                        }
2032                    }
2033                    mWakeLock.release();
2034                }
2035            }).start();
2036        }
2037
2038        @Override
2039        public boolean processMessage(Message message) {
2040            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2041            switch (message.what) {
2042                case CMD_UNLOAD_DRIVER_SUCCESS:
2043                    transitionTo(mDriverUnloadedState);
2044                    break;
2045                case CMD_UNLOAD_DRIVER_FAILURE:
2046                    transitionTo(mDriverFailedState);
2047                    break;
2048                case CMD_LOAD_DRIVER:
2049                case CMD_UNLOAD_DRIVER:
2050                case CMD_START_SUPPLICANT:
2051                case CMD_STOP_SUPPLICANT:
2052                case CMD_START_AP:
2053                case CMD_STOP_AP:
2054                case CMD_START_DRIVER:
2055                case CMD_STOP_DRIVER:
2056                case CMD_SET_SCAN_MODE:
2057                case CMD_SET_SCAN_TYPE:
2058                case CMD_SET_HIGH_PERF_MODE:
2059                case CMD_SET_COUNTRY_CODE:
2060                case CMD_SET_FREQUENCY_BAND:
2061                case CMD_START_PACKET_FILTERING:
2062                case CMD_STOP_PACKET_FILTERING:
2063                    deferMessage(message);
2064                    break;
2065                default:
2066                    return NOT_HANDLED;
2067            }
2068            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2069            return HANDLED;
2070        }
2071    }
2072
2073    class DriverUnloadedState extends State {
2074        @Override
2075        public void enter() {
2076            if (DBG) Log.d(TAG, getName() + "\n");
2077            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2078        }
2079        @Override
2080        public boolean processMessage(Message message) {
2081            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2082            switch (message.what) {
2083                case CMD_LOAD_DRIVER:
2084                    transitionTo(mDriverLoadingState);
2085                    break;
2086                default:
2087                    return NOT_HANDLED;
2088            }
2089            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2090            return HANDLED;
2091        }
2092    }
2093
2094    class DriverFailedState extends State {
2095        @Override
2096        public void enter() {
2097            Log.e(TAG, getName() + "\n");
2098            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2099        }
2100        @Override
2101        public boolean processMessage(Message message) {
2102            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2103            return NOT_HANDLED;
2104        }
2105    }
2106
2107
2108    class SupplicantStartingState extends State {
2109        @Override
2110        public void enter() {
2111            if (DBG) Log.d(TAG, getName() + "\n");
2112            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2113        }
2114        @Override
2115        public boolean processMessage(Message message) {
2116            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2117            switch(message.what) {
2118                case SUP_CONNECTION_EVENT:
2119                    Log.d(TAG, "Supplicant connection established");
2120                    setWifiState(WIFI_STATE_ENABLED);
2121                    mSupplicantRestartCount = 0;
2122                    /* Reset the supplicant state to indicate the supplicant
2123                     * state is not known at this time */
2124                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2125                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2126                    /* Initialize data structures */
2127                    mLastBssid = null;
2128                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
2129                    mLastSignalLevel = -1;
2130
2131                    mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
2132
2133                    WifiConfigStore.initialize(mContext);
2134
2135                    sendSupplicantConnectionChangedBroadcast(true);
2136                    transitionTo(mDriverStartedState);
2137                    break;
2138                case SUP_DISCONNECTION_EVENT:
2139                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
2140                        Log.e(TAG, "Failed to setup control channel, restart supplicant");
2141                        WifiNative.killSupplicant();
2142                        transitionTo(mDriverLoadedState);
2143                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2144                    } else {
2145                        Log.e(TAG, "Failed " + mSupplicantRestartCount +
2146                                " times to start supplicant, unload driver");
2147                        mSupplicantRestartCount = 0;
2148                        transitionTo(mDriverLoadedState);
2149                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
2150                    }
2151                    break;
2152                case CMD_LOAD_DRIVER:
2153                case CMD_UNLOAD_DRIVER:
2154                case CMD_START_SUPPLICANT:
2155                case CMD_STOP_SUPPLICANT:
2156                case CMD_START_AP:
2157                case CMD_STOP_AP:
2158                case CMD_START_DRIVER:
2159                case CMD_STOP_DRIVER:
2160                case CMD_SET_SCAN_MODE:
2161                case CMD_SET_SCAN_TYPE:
2162                case CMD_SET_HIGH_PERF_MODE:
2163                case CMD_SET_COUNTRY_CODE:
2164                case CMD_SET_FREQUENCY_BAND:
2165                case CMD_START_PACKET_FILTERING:
2166                case CMD_STOP_PACKET_FILTERING:
2167                    deferMessage(message);
2168                    break;
2169                default:
2170                    return NOT_HANDLED;
2171            }
2172            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2173            return HANDLED;
2174        }
2175    }
2176
2177    class SupplicantStartedState extends State {
2178        @Override
2179        public void enter() {
2180            if (DBG) Log.d(TAG, getName() + "\n");
2181            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2182            /* Initialize for connect mode operation at start */
2183            mIsScanMode = false;
2184            /* Wifi is available as long as we have a connection to supplicant */
2185            mNetworkInfo.setIsAvailable(true);
2186            /* Set scan interval */
2187            long supplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
2188                    Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
2189                    mDefaultSupplicantScanIntervalMs);
2190            WifiNative.setScanIntervalCommand((int)supplicantScanIntervalMs / 1000);
2191        }
2192        @Override
2193        public boolean processMessage(Message message) {
2194            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2195            WifiConfiguration config;
2196            boolean eventLoggingEnabled = true;
2197            switch(message.what) {
2198                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
2199                    transitionTo(mSupplicantStoppingState);
2200                    break;
2201                case SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
2202                    Log.e(TAG, "Connection lost, restart supplicant");
2203                    WifiNative.killSupplicant();
2204                    WifiNative.closeSupplicantConnection();
2205                    mNetworkInfo.setIsAvailable(false);
2206                    handleNetworkDisconnect();
2207                    sendSupplicantConnectionChangedBroadcast(false);
2208                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2209                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2210                    transitionTo(mDriverLoadedState);
2211                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
2212                    break;
2213                case SCAN_RESULTS_EVENT:
2214                    eventLoggingEnabled = false;
2215                    setScanResults(WifiNative.scanResultsCommand());
2216                    sendScanResultsAvailableBroadcast();
2217                    mScanResultIsPending = false;
2218                    break;
2219                case CMD_PING_SUPPLICANT:
2220                    boolean ok = WifiNative.pingCommand();
2221                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2222                    break;
2223                case CMD_ADD_OR_UPDATE_NETWORK:
2224                    config = (WifiConfiguration) message.obj;
2225                    mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
2226                            WifiConfigStore.addOrUpdateNetwork(config));
2227                    break;
2228                case CMD_REMOVE_NETWORK:
2229                    ok = WifiConfigStore.removeNetwork(message.arg1);
2230                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2231                    break;
2232                case CMD_ENABLE_NETWORK:
2233                    ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
2234                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2235                    break;
2236                case CMD_ENABLE_ALL_NETWORKS:
2237                    WifiConfigStore.enableAllNetworks();
2238                    break;
2239                case CMD_DISABLE_NETWORK:
2240                    ok = WifiConfigStore.disableNetwork(message.arg1);
2241                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
2242                    break;
2243                case CMD_BLACKLIST_NETWORK:
2244                    WifiNative.addToBlacklistCommand((String)message.obj);
2245                    break;
2246                case CMD_CLEAR_BLACKLIST:
2247                    WifiNative.clearBlacklistCommand();
2248                    break;
2249                case CMD_SAVE_CONFIG:
2250                    ok = WifiConfigStore.saveConfig();
2251                    mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
2252
2253                    // Inform the backup manager about a data change
2254                    IBackupManager ibm = IBackupManager.Stub.asInterface(
2255                            ServiceManager.getService(Context.BACKUP_SERVICE));
2256                    if (ibm != null) {
2257                        try {
2258                            ibm.dataChanged("com.android.providers.settings");
2259                        } catch (Exception e) {
2260                            // Try again later
2261                        }
2262                    }
2263                    break;
2264                    /* Cannot start soft AP while in client mode */
2265                case CMD_START_AP:
2266                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
2267                    setWifiApState(WIFI_AP_STATE_FAILED);
2268                    break;
2269                case CMD_SET_SCAN_MODE:
2270                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
2271                    break;
2272                case CMD_SAVE_NETWORK:
2273                    config = (WifiConfiguration) message.obj;
2274                    WifiConfigStore.saveNetwork(config);
2275                    break;
2276                case CMD_FORGET_NETWORK:
2277                    WifiConfigStore.forgetNetwork(message.arg1);
2278                    break;
2279                default:
2280                    return NOT_HANDLED;
2281            }
2282            if (eventLoggingEnabled) {
2283                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2284            }
2285            return HANDLED;
2286        }
2287
2288        @Override
2289        public void exit() {
2290            mNetworkInfo.setIsAvailable(false);
2291        }
2292    }
2293
2294    class SupplicantStoppingState extends State {
2295        @Override
2296        public void enter() {
2297            if (DBG) Log.d(TAG, getName() + "\n");
2298            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2299            Log.d(TAG, "stopping supplicant");
2300            if (!WifiNative.stopSupplicant()) {
2301                Log.e(TAG, "Failed to stop supplicant, issue kill");
2302                WifiNative.killSupplicant();
2303            }
2304            mNetworkInfo.setIsAvailable(false);
2305            handleNetworkDisconnect();
2306            setWifiState(WIFI_STATE_DISABLING);
2307            sendSupplicantConnectionChangedBroadcast(false);
2308            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
2309            mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
2310        }
2311        @Override
2312        public boolean processMessage(Message message) {
2313            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2314            switch(message.what) {
2315                case SUP_CONNECTION_EVENT:
2316                    Log.e(TAG, "Supplicant connection received while stopping");
2317                    break;
2318                case SUP_DISCONNECTION_EVENT:
2319                    Log.d(TAG, "Supplicant connection lost");
2320                    WifiNative.closeSupplicantConnection();
2321                    transitionTo(mDriverLoadedState);
2322                    break;
2323                case CMD_LOAD_DRIVER:
2324                case CMD_UNLOAD_DRIVER:
2325                case CMD_START_SUPPLICANT:
2326                case CMD_STOP_SUPPLICANT:
2327                case CMD_START_AP:
2328                case CMD_STOP_AP:
2329                case CMD_START_DRIVER:
2330                case CMD_STOP_DRIVER:
2331                case CMD_SET_SCAN_MODE:
2332                case CMD_SET_SCAN_TYPE:
2333                case CMD_SET_HIGH_PERF_MODE:
2334                case CMD_SET_COUNTRY_CODE:
2335                case CMD_SET_FREQUENCY_BAND:
2336                case CMD_START_PACKET_FILTERING:
2337                case CMD_STOP_PACKET_FILTERING:
2338                    deferMessage(message);
2339                    break;
2340                default:
2341                    return NOT_HANDLED;
2342            }
2343            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2344            return HANDLED;
2345        }
2346    }
2347
2348    class DriverStartingState extends State {
2349        @Override
2350        public void enter() {
2351            if (DBG) Log.d(TAG, getName() + "\n");
2352            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2353        }
2354        @Override
2355        public boolean processMessage(Message message) {
2356            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2357            switch(message.what) {
2358               case SUPPLICANT_STATE_CHANGE_EVENT:
2359                    SupplicantState state = handleSupplicantStateChange(message);
2360                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
2361                     * a state that indicates driver has started, it is ready to
2362                     * receive driver commands
2363                     */
2364                    if (SupplicantState.isDriverActive(state)) {
2365                        transitionTo(mDriverStartedState);
2366                    }
2367                    break;
2368                    /* Queue driver commands & connection events */
2369                case CMD_START_DRIVER:
2370                case CMD_STOP_DRIVER:
2371                case NETWORK_CONNECTION_EVENT:
2372                case NETWORK_DISCONNECTION_EVENT:
2373                case AUTHENTICATION_FAILURE_EVENT:
2374                case WPS_OVERLAP_EVENT:
2375                case CMD_SET_SCAN_TYPE:
2376                case CMD_SET_HIGH_PERF_MODE:
2377                case CMD_SET_COUNTRY_CODE:
2378                case CMD_SET_FREQUENCY_BAND:
2379                case CMD_START_PACKET_FILTERING:
2380                case CMD_STOP_PACKET_FILTERING:
2381                case CMD_START_SCAN:
2382                case CMD_DISCONNECT:
2383                case CMD_REASSOCIATE:
2384                case CMD_RECONNECT:
2385                    deferMessage(message);
2386                    break;
2387                default:
2388                    return NOT_HANDLED;
2389            }
2390            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2391            return HANDLED;
2392        }
2393    }
2394
2395    class DriverStartedState extends State {
2396        @Override
2397        public void enter() {
2398            if (DBG) Log.d(TAG, getName() + "\n");
2399            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2400
2401            mIsRunning = true;
2402            updateBatteryWorkSource(null);
2403
2404            /**
2405             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
2406             * When this mode is on, some of the low-level scan parameters used by the
2407             * driver are changed to reduce interference with bluetooth
2408             */
2409            WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2410            /* set country code */
2411            setCountryCode();
2412            /* set frequency band of operation */
2413            setFrequencyBand();
2414            /* initialize network state */
2415            setNetworkDetailedState(DetailedState.DISCONNECTED);
2416
2417            /* Remove any filtering on Multicast v6 at start */
2418            WifiNative.stopFilteringMulticastV6Packets();
2419
2420            /* Reset Multicast v4 filtering state */
2421            if (mFilteringMulticastV4Packets.get()) {
2422                WifiNative.startFilteringMulticastV4Packets();
2423            } else {
2424                WifiNative.stopFilteringMulticastV4Packets();
2425            }
2426
2427            if (mIsScanMode) {
2428                WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2429                WifiNative.disconnectCommand();
2430                transitionTo(mScanModeState);
2431            } else {
2432                WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2433                WifiNative.reconnectCommand();
2434                transitionTo(mDisconnectedState);
2435            }
2436        }
2437        @Override
2438        public boolean processMessage(Message message) {
2439            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2440            boolean eventLoggingEnabled = true;
2441            switch(message.what) {
2442                case CMD_SET_SCAN_TYPE:
2443                    if (message.arg1 == SCAN_ACTIVE) {
2444                        WifiNative.setScanModeCommand(true);
2445                    } else {
2446                        WifiNative.setScanModeCommand(false);
2447                    }
2448                    break;
2449                case CMD_START_SCAN:
2450                    eventLoggingEnabled = false;
2451                    WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
2452                    mScanResultIsPending = true;
2453                    break;
2454                case CMD_SET_HIGH_PERF_MODE:
2455                    setHighPerfModeEnabledNative(message.arg1 == 1);
2456                    break;
2457                case CMD_SET_COUNTRY_CODE:
2458                    String country = (String) message.obj;
2459                    Log.d(TAG, "set country code " + country);
2460                    if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) {
2461                        Log.e(TAG, "Failed to set country code " + country);
2462                    }
2463                    break;
2464                case CMD_SET_FREQUENCY_BAND:
2465                    int band =  message.arg1;
2466                    Log.d(TAG, "set frequency band " + band);
2467                    if (WifiNative.setBandCommand(band)) {
2468                        mFrequencyBand.set(band);
2469                        //Fetch the latest scan results when frequency band is set
2470                        startScan(true);
2471                    } else {
2472                        Log.e(TAG, "Failed to set frequency band " + band);
2473                    }
2474                    break;
2475                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
2476                    mBluetoothConnectionActive = (message.arg1 !=
2477                            BluetoothAdapter.STATE_DISCONNECTED);
2478                    WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
2479                    break;
2480                case CMD_STOP_DRIVER:
2481                    mWakeLock.acquire();
2482                    WifiNative.stopDriverCommand();
2483                    transitionTo(mDriverStoppingState);
2484                    mWakeLock.release();
2485                    break;
2486                case CMD_START_PACKET_FILTERING:
2487                    if (message.arg1 == MULTICAST_V6) {
2488                        WifiNative.startFilteringMulticastV6Packets();
2489                    } else if (message.arg1 == MULTICAST_V4) {
2490                        WifiNative.startFilteringMulticastV4Packets();
2491                    } else {
2492                        Log.e(TAG, "Illegal arugments to CMD_START_PACKET_FILTERING");
2493                    }
2494                    break;
2495                case CMD_STOP_PACKET_FILTERING:
2496                    if (message.arg1 == MULTICAST_V6) {
2497                        WifiNative.stopFilteringMulticastV6Packets();
2498                    } else if (message.arg1 == MULTICAST_V4) {
2499                        WifiNative.stopFilteringMulticastV4Packets();
2500                    } else {
2501                        Log.e(TAG, "Illegal arugments to CMD_STOP_PACKET_FILTERING");
2502                    }
2503                    break;
2504                default:
2505                    return NOT_HANDLED;
2506            }
2507            if (eventLoggingEnabled) {
2508                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2509            }
2510            return HANDLED;
2511        }
2512        @Override
2513        public void exit() {
2514            if (DBG) Log.d(TAG, getName() + "\n");
2515            mIsRunning = false;
2516            updateBatteryWorkSource(null);
2517            mScanResults = null;
2518        }
2519    }
2520
2521    class DriverStoppingState extends State {
2522        @Override
2523        public void enter() {
2524            if (DBG) Log.d(TAG, getName() + "\n");
2525            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2526        }
2527        @Override
2528        public boolean processMessage(Message message) {
2529            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2530            switch(message.what) {
2531                case SUPPLICANT_STATE_CHANGE_EVENT:
2532                    SupplicantState state = handleSupplicantStateChange(message);
2533                    if (state == SupplicantState.INTERFACE_DISABLED) {
2534                        transitionTo(mDriverStoppedState);
2535                    }
2536                    break;
2537                    /* Queue driver commands */
2538                case CMD_START_DRIVER:
2539                case CMD_STOP_DRIVER:
2540                case CMD_SET_SCAN_TYPE:
2541                case CMD_SET_HIGH_PERF_MODE:
2542                case CMD_SET_COUNTRY_CODE:
2543                case CMD_SET_FREQUENCY_BAND:
2544                case CMD_START_PACKET_FILTERING:
2545                case CMD_STOP_PACKET_FILTERING:
2546                case CMD_START_SCAN:
2547                case CMD_DISCONNECT:
2548                case CMD_REASSOCIATE:
2549                case CMD_RECONNECT:
2550                    deferMessage(message);
2551                    break;
2552                default:
2553                    return NOT_HANDLED;
2554            }
2555            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2556            return HANDLED;
2557        }
2558    }
2559
2560    class DriverStoppedState extends State {
2561        @Override
2562        public void enter() {
2563            if (DBG) Log.d(TAG, getName() + "\n");
2564            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2565        }
2566        @Override
2567        public boolean processMessage(Message message) {
2568            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2569            switch (message.what) {
2570               case CMD_START_DRIVER:
2571                   mWakeLock.acquire();
2572                   WifiNative.startDriverCommand();
2573                   mWakeLock.release();
2574                   break;
2575                case SUPPLICANT_STATE_CHANGE_EVENT:
2576                    SupplicantState state = handleSupplicantStateChange(message);
2577                    /* A driver start causes supplicant to first report an INTERFACE_DISABLED
2578                     * state before transitioning out of it for connection. Stay in
2579                     * DriverStoppedState until we get an INTERFACE_DISABLED state and transition
2580                     * to DriverStarting upon getting that
2581                     * TODO: Fix this when the supplicant can be made to just transition out of
2582                     * INTERFACE_DISABLED state when driver gets started
2583                     */
2584                    if (state == SupplicantState.INTERFACE_DISABLED) {
2585                        transitionTo(mDriverStartingState);
2586                    }
2587                    break;
2588                default:
2589                    return NOT_HANDLED;
2590            }
2591            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2592            return HANDLED;
2593        }
2594    }
2595
2596    class ScanModeState extends State {
2597        @Override
2598        public void enter() {
2599            if (DBG) Log.d(TAG, getName() + "\n");
2600            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2601        }
2602        @Override
2603        public boolean processMessage(Message message) {
2604            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2605            switch(message.what) {
2606                case CMD_SET_SCAN_MODE:
2607                    if (message.arg1 == SCAN_ONLY_MODE) {
2608                        /* Ignore */
2609                        return HANDLED;
2610                    } else {
2611                        WifiNative.setScanResultHandlingCommand(message.arg1);
2612                        WifiNative.reconnectCommand();
2613                        mIsScanMode = false;
2614                        transitionTo(mDisconnectedState);
2615                    }
2616                    break;
2617                    /* Ignore */
2618                case CMD_DISCONNECT:
2619                case CMD_RECONNECT:
2620                case CMD_REASSOCIATE:
2621                case SUPPLICANT_STATE_CHANGE_EVENT:
2622                case NETWORK_CONNECTION_EVENT:
2623                case NETWORK_DISCONNECTION_EVENT:
2624                    break;
2625                default:
2626                    return NOT_HANDLED;
2627            }
2628            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2629            return HANDLED;
2630        }
2631    }
2632
2633    class ConnectModeState extends State {
2634        @Override
2635        public void enter() {
2636            if (DBG) Log.d(TAG, getName() + "\n");
2637            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2638        }
2639        @Override
2640        public boolean processMessage(Message message) {
2641            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2642            StateChangeResult stateChangeResult;
2643            switch(message.what) {
2644                case AUTHENTICATION_FAILURE_EVENT:
2645                    mSupplicantStateTracker.sendMessage(AUTHENTICATION_FAILURE_EVENT);
2646                    break;
2647                case WPS_OVERLAP_EVENT:
2648                    /* We just need to broadcast the error */
2649                    sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
2650                    break;
2651                case SUPPLICANT_STATE_CHANGE_EVENT:
2652                    handleSupplicantStateChange(message);
2653                   break;
2654                    /* Do a redundant disconnect without transition */
2655                case CMD_DISCONNECT:
2656                    WifiNative.disconnectCommand();
2657                    break;
2658                case CMD_RECONNECT:
2659                    WifiNative.reconnectCommand();
2660                    break;
2661                case CMD_REASSOCIATE:
2662                    WifiNative.reassociateCommand();
2663                    break;
2664                case CMD_CONNECT_NETWORK:
2665                    int netId = message.arg1;
2666                    WifiConfiguration config = (WifiConfiguration) message.obj;
2667
2668                    /* We connect to a specific network by issuing a select
2669                     * to the WifiConfigStore. This enables the network,
2670                     * while disabling all other networks in the supplicant.
2671                     * Disabling a connected network will cause a disconnection
2672                     * from the network. A reconnectCommand() will then initiate
2673                     * a connection to the enabled network.
2674                     */
2675                    if (config != null) {
2676                        WifiConfigStore.selectNetwork(config);
2677                    } else {
2678                        WifiConfigStore.selectNetwork(netId);
2679                    }
2680
2681                    /* The state tracker handles enabling networks upon completion/failure */
2682                    mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
2683
2684                    WifiNative.reconnectCommand();
2685
2686                    /* Expect a disconnection from the old connection */
2687                    transitionTo(mDisconnectingState);
2688                    break;
2689                case CMD_START_WPS:
2690                    mWpsStateMachine.sendMessage(Message.obtain(message));
2691                    transitionTo(mWaitForWpsCompletionState);
2692                    break;
2693                case SCAN_RESULTS_EVENT:
2694                    /* Set the scan setting back to "connect" mode */
2695                    WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2696                    /* Handle scan results */
2697                    return NOT_HANDLED;
2698                case NETWORK_CONNECTION_EVENT:
2699                    Log.d(TAG,"Network connection established");
2700                    mLastNetworkId = message.arg1;
2701                    mLastBssid = (String) message.obj;
2702
2703                    //TODO: make supplicant modification to push this in events
2704                    mWifiInfo.setSSID(fetchSSID());
2705                    mWifiInfo.setBSSID(mLastBssid);
2706                    mWifiInfo.setNetworkId(mLastNetworkId);
2707                    /* send event to CM & network change broadcast */
2708                    setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
2709                    sendNetworkStateChangeBroadcast(mLastBssid);
2710                    transitionTo(mConnectingState);
2711                    break;
2712                case NETWORK_DISCONNECTION_EVENT:
2713                    Log.d(TAG,"Network connection lost");
2714                    handleNetworkDisconnect();
2715                    transitionTo(mDisconnectedState);
2716                    break;
2717                default:
2718                    return NOT_HANDLED;
2719            }
2720            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2721            return HANDLED;
2722        }
2723    }
2724
2725    class ConnectingState extends State {
2726
2727        @Override
2728        public void enter() {
2729            if (DBG) Log.d(TAG, getName() + "\n");
2730            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2731
2732             if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
2733                //start DHCP
2734                mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
2735                        mContext, WifiStateMachine.this, mInterfaceName);
2736                mDhcpStateMachine.registerForPreDhcpNotification();
2737                mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
2738            } else {
2739                DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
2740                        mLastNetworkId);
2741                InterfaceConfiguration ifcg = new InterfaceConfiguration();
2742                ifcg.addr = dhcpInfoInternal.makeLinkAddress();
2743                ifcg.interfaceFlags = "[up]";
2744                try {
2745                    nwService.setInterfaceConfig(mInterfaceName, ifcg);
2746                    Log.v(TAG, "Static IP configuration succeeded");
2747                    sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
2748                } catch (RemoteException re) {
2749                    Log.v(TAG, "Static IP configuration failed: " + re);
2750                    sendMessage(CMD_STATIC_IP_FAILURE);
2751                } catch (IllegalStateException e) {
2752                    Log.v(TAG, "Static IP configuration failed: " + e);
2753                    sendMessage(CMD_STATIC_IP_FAILURE);
2754                }
2755            }
2756         }
2757      @Override
2758      public boolean processMessage(Message message) {
2759          if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2760
2761          switch(message.what) {
2762              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2763                  handlePreDhcpSetup();
2764                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2765                  break;
2766              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2767                  handlePostDhcpSetup();
2768                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2769                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2770                      transitionTo(mConnectedState);
2771                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2772                      handleFailedIpConfiguration();
2773                      transitionTo(mDisconnectingState);
2774                  }
2775                  break;
2776              case CMD_STATIC_IP_SUCCESS:
2777                  handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2778                  transitionTo(mConnectedState);
2779                  break;
2780              case CMD_STATIC_IP_FAILURE:
2781                  handleFailedIpConfiguration();
2782                  transitionTo(mDisconnectingState);
2783                  break;
2784              case CMD_DISCONNECT:
2785                  WifiNative.disconnectCommand();
2786                  transitionTo(mDisconnectingState);
2787                  break;
2788                  /* Ignore connection to same network */
2789              case CMD_CONNECT_NETWORK:
2790                  int netId = message.arg1;
2791                  if (mWifiInfo.getNetworkId() == netId) {
2792                      break;
2793                  }
2794                  return NOT_HANDLED;
2795              case CMD_SAVE_NETWORK:
2796                  deferMessage(message);
2797                  break;
2798                  /* Ignore */
2799              case NETWORK_CONNECTION_EVENT:
2800                  break;
2801              case CMD_STOP_DRIVER:
2802                  sendMessage(CMD_DISCONNECT);
2803                  deferMessage(message);
2804                  break;
2805              case CMD_SET_SCAN_MODE:
2806                  if (message.arg1 == SCAN_ONLY_MODE) {
2807                      sendMessage(CMD_DISCONNECT);
2808                      deferMessage(message);
2809                  }
2810                  break;
2811                  /* Defer scan when IP is being fetched */
2812              case CMD_START_SCAN:
2813                  deferMessage(message);
2814                  break;
2815                  /* Defer any power mode changes since we must keep active power mode at DHCP */
2816              case CMD_SET_HIGH_PERF_MODE:
2817                  deferMessage(message);
2818                  break;
2819              default:
2820                return NOT_HANDLED;
2821          }
2822          EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2823          return HANDLED;
2824      }
2825    }
2826
2827    class ConnectedState extends State {
2828        @Override
2829        public void enter() {
2830            if (DBG) Log.d(TAG, getName() + "\n");
2831            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2832            mRssiPollToken++;
2833            if (mEnableRssiPolling) {
2834                sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0));
2835            }
2836        }
2837        @Override
2838        public boolean processMessage(Message message) {
2839            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2840            boolean eventLoggingEnabled = true;
2841            switch (message.what) {
2842              case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
2843                  handlePreDhcpSetup();
2844                  mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
2845                  break;
2846              case DhcpStateMachine.CMD_POST_DHCP_ACTION:
2847                  handlePostDhcpSetup();
2848                  if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
2849                      handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
2850                  } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
2851                      handleFailedIpConfiguration();
2852                      transitionTo(mDisconnectingState);
2853                  }
2854                  break;
2855                case CMD_DISCONNECT:
2856                    WifiNative.disconnectCommand();
2857                    transitionTo(mDisconnectingState);
2858                    break;
2859                case CMD_STOP_DRIVER:
2860                    sendMessage(CMD_DISCONNECT);
2861                    deferMessage(message);
2862                    break;
2863                case CMD_REQUEST_CM_WAKELOCK:
2864                    checkAndSetConnectivityInstance();
2865                    mCm.requestNetworkTransitionWakelock(TAG);
2866                    break;
2867                case CMD_SET_SCAN_MODE:
2868                    if (message.arg1 == SCAN_ONLY_MODE) {
2869                        sendMessage(CMD_DISCONNECT);
2870                        deferMessage(message);
2871                    }
2872                    break;
2873                case CMD_START_SCAN:
2874                    eventLoggingEnabled = false;
2875                    /* When the network is connected, re-scanning can trigger
2876                     * a reconnection. Put it in scan-only mode during scan.
2877                     * When scan results are received, the mode is switched
2878                     * back to CONNECT_MODE.
2879                     */
2880                    WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
2881                    /* Have the parent state handle the rest */
2882                    return NOT_HANDLED;
2883                    /* Ignore connection to same network */
2884                case CMD_CONNECT_NETWORK:
2885                    int netId = message.arg1;
2886                    if (mWifiInfo.getNetworkId() == netId) {
2887                        break;
2888                    }
2889                    return NOT_HANDLED;
2890                case CMD_SAVE_NETWORK:
2891                    WifiConfiguration config = (WifiConfiguration) message.obj;
2892                    NetworkUpdateResult result = WifiConfigStore.saveNetwork(config);
2893                    if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
2894                        if (result.hasIpChanged()) {
2895                            Log.d(TAG,"Reconfiguring IP on connection");
2896                            transitionTo(mConnectingState);
2897                        }
2898                        if (result.hasProxyChanged()) {
2899                            Log.d(TAG,"Reconfiguring proxy on connection");
2900                            configureLinkProperties();
2901                            sendLinkConfigurationChangedBroadcast();
2902                        }
2903                    }
2904                    break;
2905                    /* Ignore */
2906                case NETWORK_CONNECTION_EVENT:
2907                    break;
2908                case CMD_RSSI_POLL:
2909                    eventLoggingEnabled = false;
2910                    if (message.arg1 == mRssiPollToken) {
2911                        // Get Info and continue polling
2912                        fetchRssiAndLinkSpeedNative();
2913                        sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2914                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2915                    } else {
2916                        // Polling has completed
2917                    }
2918                    break;
2919                case CMD_ENABLE_RSSI_POLL:
2920                    mEnableRssiPolling = (message.arg1 == 1);
2921                    mRssiPollToken++;
2922                    if (mEnableRssiPolling) {
2923                        // first poll
2924                        fetchRssiAndLinkSpeedNative();
2925                        sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
2926                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
2927                    }
2928                    break;
2929                default:
2930                    return NOT_HANDLED;
2931            }
2932            if (eventLoggingEnabled) {
2933                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2934            }
2935            return HANDLED;
2936        }
2937        @Override
2938        public void exit() {
2939            /* If a scan result is pending in connected state, the supplicant
2940             * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
2941             */
2942            if (mScanResultIsPending) {
2943                WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
2944            }
2945        }
2946    }
2947
2948    class DisconnectingState extends State {
2949        @Override
2950        public void enter() {
2951            if (DBG) Log.d(TAG, getName() + "\n");
2952            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
2953        }
2954        @Override
2955        public boolean processMessage(Message message) {
2956            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
2957            switch (message.what) {
2958                case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
2959                    deferMessage(message);
2960                    break;
2961                case CMD_SET_SCAN_MODE:
2962                    if (message.arg1 == SCAN_ONLY_MODE) {
2963                        deferMessage(message);
2964                    }
2965                    break;
2966                    /* Handle in  DisconnectedState */
2967                case SUPPLICANT_STATE_CHANGE_EVENT:
2968                    deferMessage(message);
2969                    break;
2970                default:
2971                    return NOT_HANDLED;
2972            }
2973            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
2974            return HANDLED;
2975        }
2976    }
2977
2978    class DisconnectedState extends State {
2979        private boolean mAlarmEnabled = false;
2980        /* This is set from the overlay config file or from a secure setting.
2981         * A value of 0 disables scanning in the framework.
2982         */
2983        private long mFrameworkScanIntervalMs;
2984
2985        private void setScanAlarm(boolean enabled) {
2986            if (enabled == mAlarmEnabled) return;
2987            if (enabled) {
2988                if (mFrameworkScanIntervalMs > 0) {
2989                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
2990                            System.currentTimeMillis() + mFrameworkScanIntervalMs,
2991                            mFrameworkScanIntervalMs,
2992                            mScanIntent);
2993                    mAlarmEnabled = true;
2994                }
2995            } else {
2996                mAlarmManager.cancel(mScanIntent);
2997                mAlarmEnabled = false;
2998            }
2999        }
3000
3001        @Override
3002        public void enter() {
3003            if (DBG) Log.d(TAG, getName() + "\n");
3004            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3005
3006            mFrameworkScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
3007                    Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
3008                    mDefaultFrameworkScanIntervalMs);
3009            /*
3010             * We initiate background scanning if it is enabled, otherwise we
3011             * initiate an infrequent scan that wakes up the device to ensure
3012             * a user connects to an access point on the move
3013             */
3014            if (mEnableBackgroundScan) {
3015                /* If a regular scan result is pending, do not initiate background
3016                 * scan until the scan results are returned. This is needed because
3017                 * initiating a background scan will cancel the regular scan and
3018                 * scan results will not be returned until background scanning is
3019                 * cleared
3020                 */
3021                if (!mScanResultIsPending) {
3022                    WifiNative.enableBackgroundScanCommand(true);
3023                }
3024            } else {
3025                setScanAlarm(true);
3026            }
3027        }
3028        @Override
3029        public boolean processMessage(Message message) {
3030            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3031            switch (message.what) {
3032                case CMD_SET_SCAN_MODE:
3033                    if (message.arg1 == SCAN_ONLY_MODE) {
3034                        WifiNative.setScanResultHandlingCommand(message.arg1);
3035                        //Supplicant disconnect to prevent further connects
3036                        WifiNative.disconnectCommand();
3037                        mIsScanMode = true;
3038                        transitionTo(mScanModeState);
3039                    }
3040                    break;
3041                case CMD_ENABLE_BACKGROUND_SCAN:
3042                    mEnableBackgroundScan = (message.arg1 == 1);
3043                    if (mEnableBackgroundScan) {
3044                        WifiNative.enableBackgroundScanCommand(true);
3045                        setScanAlarm(false);
3046                    } else {
3047                        WifiNative.enableBackgroundScanCommand(false);
3048                        setScanAlarm(true);
3049                    }
3050                    break;
3051                    /* Ignore network disconnect */
3052                case NETWORK_DISCONNECTION_EVENT:
3053                    break;
3054                case SUPPLICANT_STATE_CHANGE_EVENT:
3055                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
3056                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
3057                    /* ConnectModeState does the rest of the handling */
3058                    return NOT_HANDLED;
3059                case CMD_START_SCAN:
3060                    /* Disable background scan temporarily during a regular scan */
3061                    if (mEnableBackgroundScan) {
3062                        WifiNative.enableBackgroundScanCommand(false);
3063                    }
3064                    /* Handled in parent state */
3065                    return NOT_HANDLED;
3066                case SCAN_RESULTS_EVENT:
3067                    /* Re-enable background scan when a pending scan result is received */
3068                    if (mEnableBackgroundScan && mScanResultIsPending) {
3069                        WifiNative.enableBackgroundScanCommand(true);
3070                    }
3071                    /* Handled in parent state */
3072                    return NOT_HANDLED;
3073                default:
3074                    return NOT_HANDLED;
3075            }
3076            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3077            return HANDLED;
3078        }
3079
3080        @Override
3081        public void exit() {
3082            /* No need for a background scan upon exit from a disconnected state */
3083            if (mEnableBackgroundScan) {
3084                WifiNative.enableBackgroundScanCommand(false);
3085            }
3086            setScanAlarm(false);
3087        }
3088    }
3089
3090    class WaitForWpsCompletionState extends State {
3091        @Override
3092        public void enter() {
3093            if (DBG) Log.d(TAG, getName() + "\n");
3094            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3095        }
3096        @Override
3097        public boolean processMessage(Message message) {
3098            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3099            switch (message.what) {
3100                /* Defer all commands that can cause connections to a different network
3101                 * or put the state machine out of connect mode
3102                 */
3103                case CMD_STOP_DRIVER:
3104                case CMD_SET_SCAN_MODE:
3105                case CMD_CONNECT_NETWORK:
3106                case CMD_ENABLE_NETWORK:
3107                case CMD_RECONNECT:
3108                case CMD_REASSOCIATE:
3109                case NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */
3110                    deferMessage(message);
3111                    break;
3112                case NETWORK_DISCONNECTION_EVENT:
3113                    Log.d(TAG,"Network connection lost");
3114                    handleNetworkDisconnect();
3115                    break;
3116                case WPS_COMPLETED_EVENT:
3117                    /* we are still disconnected until we see a network connection
3118                     * notification */
3119                    transitionTo(mDisconnectedState);
3120                    break;
3121                default:
3122                    return NOT_HANDLED;
3123            }
3124            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3125            return HANDLED;
3126        }
3127    }
3128
3129    class SoftApStartedState extends State {
3130        @Override
3131        public void enter() {
3132            if (DBG) Log.d(TAG, getName() + "\n");
3133            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3134        }
3135        @Override
3136        public boolean processMessage(Message message) {
3137            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3138            switch(message.what) {
3139                case CMD_STOP_AP:
3140                    Log.d(TAG,"Stopping Soft AP");
3141                    setWifiApState(WIFI_AP_STATE_DISABLING);
3142                    stopTethering();
3143                    try {
3144                        nwService.stopAccessPoint(mInterfaceName);
3145                    } catch(Exception e) {
3146                        Log.e(TAG, "Exception in stopAccessPoint()");
3147                    }
3148                    transitionTo(mDriverLoadedState);
3149                    break;
3150                case CMD_START_AP:
3151                    Log.d(TAG,"SoftAP set on a running access point");
3152                    if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_RUNNING)) {
3153                        Log.d(TAG, "Soft AP start successful");
3154                        setWifiApState(WIFI_AP_STATE_ENABLED);
3155                        transitionTo(mSoftApStartedState);
3156                    } else {
3157                        Log.d(TAG, "Soft AP start failed");
3158                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
3159                    }
3160                    break;
3161                /* Fail client mode operation when soft AP is enabled */
3162                case CMD_START_SUPPLICANT:
3163                    Log.e(TAG,"Cannot start supplicant with a running soft AP");
3164                    setWifiState(WIFI_STATE_UNKNOWN);
3165                    break;
3166                case CMD_TETHER_INTERFACE:
3167                    ArrayList<String> available = (ArrayList<String>) message.obj;
3168                    if (startTethering(available)) {
3169                        transitionTo(mTetheredState);
3170                    }
3171                    break;
3172                default:
3173                    return NOT_HANDLED;
3174            }
3175            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
3176            return HANDLED;
3177        }
3178    }
3179
3180    class TetheredState extends State {
3181        @Override
3182        public void enter() {
3183            if (DBG) Log.d(TAG, getName() + "\n");
3184            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
3185        }
3186        @Override
3187        public boolean processMessage(Message message) {
3188            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
3189            switch(message.what) {
3190               case CMD_TETHER_INTERFACE:
3191                    // Ignore any duplicate interface available notifications
3192                    // when in tethered state
3193                    return HANDLED;
3194                default:
3195                    return NOT_HANDLED;
3196            }
3197        }
3198    }
3199}
3200