WifiMonitor.java revision 8aebfed96d10c3ef93ece3974e602b36c3e81f4a
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.net.wifi.SupplicantState;
20import android.net.wifi.WifiEnterpriseConfig;
21import android.net.wifi.WifiManager;
22import android.net.wifi.WifiSsid;
23import android.os.Handler;
24import android.os.Message;
25import android.util.ArraySet;
26import android.util.Log;
27import android.util.SparseArray;
28
29import com.android.internal.annotations.VisibleForTesting;
30import com.android.internal.util.Protocol;
31import com.android.internal.util.StateMachine;
32import com.android.server.wifi.hotspot2.AnqpEvent;
33import com.android.server.wifi.hotspot2.IconEvent;
34import com.android.server.wifi.hotspot2.WnmData;
35import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
36
37import java.util.HashMap;
38import java.util.Map;
39import java.util.Set;
40
41/**
42 * Listens for events from the wpa_supplicant server, and passes them on
43 * to the {@link StateMachine} for handling.
44 *
45 * @hide
46 */
47public class WifiMonitor {
48    private static final String TAG = "WifiMonitor";
49
50    /* Supplicant events reported to a state machine */
51    private static final int BASE = Protocol.BASE_WIFI_MONITOR;
52
53    /* Connection to supplicant established */
54    public static final int SUP_CONNECTION_EVENT                 = BASE + 1;
55    /* Connection to supplicant lost */
56    public static final int SUP_DISCONNECTION_EVENT              = BASE + 2;
57   /* Network connection completed */
58    public static final int NETWORK_CONNECTION_EVENT             = BASE + 3;
59    /* Network disconnection completed */
60    public static final int NETWORK_DISCONNECTION_EVENT          = BASE + 4;
61    /* Scan results are available */
62    public static final int SCAN_RESULTS_EVENT                   = BASE + 5;
63    /* Supplicate state changed */
64    public static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 6;
65    /* Password failure and EAP authentication failure */
66    public static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 7;
67    /* WPS success detected */
68    public static final int WPS_SUCCESS_EVENT                    = BASE + 8;
69    /* WPS failure detected */
70    public static final int WPS_FAIL_EVENT                       = BASE + 9;
71     /* WPS overlap detected */
72    public static final int WPS_OVERLAP_EVENT                    = BASE + 10;
73     /* WPS timeout detected */
74    public static final int WPS_TIMEOUT_EVENT                    = BASE + 11;
75
76    /* Request Identity */
77    public static final int SUP_REQUEST_IDENTITY                 = BASE + 15;
78
79    /* Request SIM Auth */
80    public static final int SUP_REQUEST_SIM_AUTH                 = BASE + 16;
81
82    public static final int SCAN_FAILED_EVENT                    = BASE + 17;
83    /* Pno scan results are available */
84    public static final int PNO_SCAN_RESULTS_EVENT               = BASE + 18;
85
86
87    /* Indicates assoc reject event */
88    public static final int ASSOCIATION_REJECTION_EVENT          = BASE + 43;
89    public static final int ANQP_DONE_EVENT                      = BASE + 44;
90
91    /* hotspot 2.0 ANQP events */
92    public static final int GAS_QUERY_START_EVENT                = BASE + 51;
93    public static final int GAS_QUERY_DONE_EVENT                 = BASE + 52;
94    public static final int RX_HS20_ANQP_ICON_EVENT              = BASE + 53;
95
96    /* hotspot 2.0 events */
97    public static final int HS20_REMEDIATION_EVENT               = BASE + 61;
98
99    /**
100     * Authentication Failure reasonCode, used internally by WifiStateMachine
101     * @hide
102     */
103    public static final int AUTHENTICATION_FAILURE_REASON_DEFAULT = 0;
104    public static final int AUTHENTICATION_FAILURE_REASON_TIMEOUT = 1;
105    public static final int AUTHENTICATION_FAILURE_REASON_WRONG_PSWD = 2;
106    public static final int AUTHENTICATION_FAILURE_REASON_EAP_FAILURE = 3;
107
108    /* WPS config errrors */
109    private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12;
110    private static final int CONFIG_AUTH_FAILURE = 18;
111
112    /* WPS error indications */
113    private static final int REASON_TKIP_ONLY_PROHIBITED = 1;
114    private static final int REASON_WEP_PROHIBITED = 2;
115
116    private final WifiInjector mWifiInjector;
117    private boolean mVerboseLoggingEnabled = false;
118    private boolean mConnected = false;
119
120    public WifiMonitor(WifiInjector wifiInjector) {
121        mWifiInjector = wifiInjector;
122    }
123
124    void enableVerboseLogging(int verbose) {
125        if (verbose > 0) {
126            mVerboseLoggingEnabled = true;
127        } else {
128            mVerboseLoggingEnabled = false;
129        }
130    }
131
132    // TODO(b/27569474) remove support for multiple handlers for the same event
133    private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>();
134    public synchronized void registerHandler(String iface, int what, Handler handler) {
135        SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
136        if (ifaceHandlers == null) {
137            ifaceHandlers = new SparseArray<>();
138            mHandlerMap.put(iface, ifaceHandlers);
139        }
140        Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what);
141        if (ifaceWhatHandlers == null) {
142            ifaceWhatHandlers = new ArraySet<>();
143            ifaceHandlers.put(what, ifaceWhatHandlers);
144        }
145        ifaceWhatHandlers.add(handler);
146    }
147
148    private final Map<String, Boolean> mMonitoringMap = new HashMap<>();
149    private boolean isMonitoring(String iface) {
150        Boolean val = mMonitoringMap.get(iface);
151        if (val == null) {
152            return false;
153        } else {
154            return val.booleanValue();
155        }
156    }
157
158    /**
159     * Enable/Disable monitoring for the provided iface.
160     *
161     * @param iface Name of the iface.
162     * @param enabled true to enable, false to disable.
163     */
164    @VisibleForTesting
165    public void setMonitoring(String iface, boolean enabled) {
166        mMonitoringMap.put(iface, enabled);
167    }
168
169    private void setMonitoringNone() {
170        for (String iface : mMonitoringMap.keySet()) {
171            setMonitoring(iface, false);
172        }
173    }
174
175    /**
176     * Wait for wpa_supplicant's control interface to be ready.
177     *
178     * TODO: Add unit tests for these once we remove the legacy code.
179     */
180    private boolean ensureConnectedLocked() {
181        if (mConnected) {
182            return true;
183        }
184        if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant");
185        int connectTries = 0;
186        while (true) {
187            mConnected = mWifiInjector.getWifiNative().connectToSupplicant();
188            if (mConnected) {
189                return true;
190            }
191            if (connectTries++ < 5) {
192                try {
193                    Thread.sleep(1000);
194                } catch (InterruptedException ignore) {
195                }
196            } else {
197                return false;
198            }
199        }
200    }
201
202    /**
203     * Start Monitoring for wpa_supplicant events.
204     *
205     * @param iface Name of iface.
206     * TODO: Add unit tests for these once we remove the legacy code.
207     */
208    public synchronized void startMonitoring(String iface, boolean isStaIface) {
209        if (ensureConnectedLocked()) {
210            setMonitoring(iface, true);
211            broadcastSupplicantConnectionEvent(iface);
212        } else {
213            boolean originalMonitoring = isMonitoring(iface);
214            setMonitoring(iface, true);
215            broadcastSupplicantDisconnectionEvent(iface);
216            setMonitoring(iface, originalMonitoring);
217            Log.e(TAG, "startMonitoring(" + iface + ") failed!");
218        }
219    }
220
221    /**
222     * Stop Monitoring for wpa_supplicant events.
223     *
224     * @param iface Name of iface.
225     * TODO: Add unit tests for these once we remove the legacy code.
226     */
227    public synchronized void stopMonitoring(String iface) {
228        if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")");
229        setMonitoring(iface, true);
230        broadcastSupplicantDisconnectionEvent(iface);
231        setMonitoring(iface, false);
232    }
233
234    /**
235     * Stop Monitoring for wpa_supplicant events.
236     *
237     * TODO: Add unit tests for these once we remove the legacy code.
238     */
239    public synchronized void stopAllMonitoring() {
240        mConnected = false;
241        setMonitoringNone();
242    }
243
244
245    /**
246     * Similar functions to Handler#sendMessage that send the message to the registered handler
247     * for the given interface and message what.
248     * All of these should be called with the WifiMonitor class lock
249     */
250    private void sendMessage(String iface, int what) {
251        sendMessage(iface, Message.obtain(null, what));
252    }
253
254    private void sendMessage(String iface, int what, Object obj) {
255        sendMessage(iface, Message.obtain(null, what, obj));
256    }
257
258    private void sendMessage(String iface, int what, int arg1) {
259        sendMessage(iface, Message.obtain(null, what, arg1, 0));
260    }
261
262    private void sendMessage(String iface, int what, int arg1, int arg2) {
263        sendMessage(iface, Message.obtain(null, what, arg1, arg2));
264    }
265
266    private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
267        sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
268    }
269
270    private void sendMessage(String iface, Message message) {
271        SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
272        if (iface != null && ifaceHandlers != null) {
273            if (isMonitoring(iface)) {
274                boolean firstHandler = true;
275                Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
276                if (ifaceWhatHandlers != null) {
277                    for (Handler handler : ifaceWhatHandlers) {
278                        if (firstHandler) {
279                            firstHandler = false;
280                            sendMessage(handler, message);
281                        } else {
282                            sendMessage(handler, Message.obtain(message));
283                        }
284                    }
285                }
286            } else {
287                if (mVerboseLoggingEnabled) {
288                    Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
289                }
290            }
291        } else {
292            if (mVerboseLoggingEnabled) {
293                Log.d(TAG, "Sending to all monitors because there's no matching iface");
294            }
295            boolean firstHandler = true;
296            for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
297                if (isMonitoring(entry.getKey())) {
298                    Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
299                    for (Handler handler : ifaceWhatHandlers) {
300                        if (firstHandler) {
301                            firstHandler = false;
302                            sendMessage(handler, message);
303                        } else {
304                            sendMessage(handler, Message.obtain(message));
305                        }
306                    }
307                }
308            }
309        }
310    }
311
312    private void sendMessage(Handler handler, Message message) {
313        if (handler != null) {
314            message.setTarget(handler);
315            message.sendToTarget();
316        }
317    }
318
319    /**
320     * Broadcast the WPS fail event to all the handlers registered for this event.
321     *
322     * @param iface Name of iface on which this occurred.
323     * @param cfgError Configuration error code.
324     * @param vendorErrorCode Vendor specific error indication code.
325     */
326    public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) {
327        int reason = 0;
328        switch(vendorErrorCode) {
329            case REASON_TKIP_ONLY_PROHIBITED:
330                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED);
331                return;
332            case REASON_WEP_PROHIBITED:
333                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED);
334                return;
335            default:
336                reason = vendorErrorCode;
337                break;
338        }
339        switch(cfgError) {
340            case CONFIG_AUTH_FAILURE:
341                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE);
342                return;
343            case CONFIG_MULTIPLE_PBC_DETECTED:
344                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR);
345                return;
346            default:
347                if (reason == 0) {
348                    reason = cfgError;
349                }
350                break;
351        }
352        //For all other errors, return a generic internal error
353        sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason);
354    }
355
356   /**
357    * Broadcast the WPS succes event to all the handlers registered for this event.
358    *
359    * @param iface Name of iface on which this occurred.
360    */
361    public void broadcastWpsSuccessEvent(String iface) {
362        sendMessage(iface, WPS_SUCCESS_EVENT);
363    }
364
365    /**
366     * Broadcast the WPS overlap event to all the handlers registered for this event.
367     *
368     * @param iface Name of iface on which this occurred.
369     */
370    public void broadcastWpsOverlapEvent(String iface) {
371        sendMessage(iface, WPS_OVERLAP_EVENT);
372    }
373
374    /**
375     * Broadcast the WPS timeout event to all the handlers registered for this event.
376     *
377     * @param iface Name of iface on which this occurred.
378     */
379    public void broadcastWpsTimeoutEvent(String iface) {
380        sendMessage(iface, WPS_TIMEOUT_EVENT);
381    }
382
383    /**
384     * Broadcast the ANQP done event to all the handlers registered for this event.
385     *
386     * @param iface Name of iface on which this occurred.
387     * @param anqpEvent ANQP result retrieved.
388     */
389    public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) {
390        sendMessage(iface, ANQP_DONE_EVENT, anqpEvent);
391    }
392
393    /**
394     * Broadcast the Icon done event to all the handlers registered for this event.
395     *
396     * @param iface Name of iface on which this occurred.
397     * @param iconEvent Instance of IconEvent containing the icon data retrieved.
398     */
399    public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) {
400        sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent);
401    }
402
403    /**
404     * Broadcast the WNM event to all the handlers registered for this event.
405     *
406     * @param iface Name of iface on which this occurred.
407     * @param wnmData Instance of WnmData containing the event data.
408     */
409    public void broadcastWnmEvent(String iface, WnmData wnmData) {
410        sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData);
411    }
412
413    /**
414     * Broadcast the Network identity request event to all the handlers registered for this event.
415     *
416     * @param iface Name of iface on which this occurred.
417     * @param networkId ID of the network in wpa_supplicant.
418     * @param ssid SSID of the network.
419     */
420    public void broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid) {
421        sendMessage(iface, SUP_REQUEST_IDENTITY, 0, networkId, ssid);
422    }
423
424    /**
425     * Broadcast the Network Gsm Sim auth request event to all the handlers registered for this
426     * event.
427     *
428     * @param iface Name of iface on which this occurred.
429     * @param networkId ID of the network in wpa_supplicant.
430     * @param ssid SSID of the network.
431     * @param data Accompanying event data.
432     */
433    public void broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid,
434                                                    String[] data) {
435        sendMessage(iface, SUP_REQUEST_SIM_AUTH,
436                new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.SIM, ssid, data));
437    }
438
439    /**
440     * Broadcast the Network Umts Sim auth request event to all the handlers registered for this
441     * event.
442     *
443     * @param iface Name of iface on which this occurred.
444     * @param networkId ID of the network in wpa_supplicant.
445     * @param ssid SSID of the network.
446     * @param data Accompanying event data.
447     */
448    public void broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid,
449                                                     String[] data) {
450        sendMessage(iface, SUP_REQUEST_SIM_AUTH,
451                new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.AKA, ssid, data));
452    }
453
454    /**
455     * Broadcast scan result event to all the handlers registered for this event.
456     * @param iface Name of iface on which this occurred.
457     */
458    public void broadcastScanResultEvent(String iface) {
459        sendMessage(iface, SCAN_RESULTS_EVENT);
460    }
461
462    /**
463     * Broadcast pno scan result event to all the handlers registered for this event.
464     * @param iface Name of iface on which this occurred.
465     */
466    public void broadcastPnoScanResultEvent(String iface) {
467        sendMessage(iface, PNO_SCAN_RESULTS_EVENT);
468    }
469
470    /**
471     * Broadcast scan failed event to all the handlers registered for this event.
472     * @param iface Name of iface on which this occurred.
473     */
474    public void broadcastScanFailedEvent(String iface) {
475        sendMessage(iface, SCAN_FAILED_EVENT);
476    }
477
478    /**
479     * Broadcast the authentication failure event to all the handlers registered for this event.
480     *
481     * @param iface Name of iface on which this occurred.
482     * @param reason Reason for authentication failure. This has to be one of the
483     *               |AUTHENTICATION_FAILURE_REASON_*| reason codes.
484     */
485    public void broadcastAuthenticationFailureEvent(String iface, int reason) {
486        sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, 0, reason);
487    }
488
489    /**
490     * Broadcast the association rejection event to all the handlers registered for this event.
491     *
492     * @param iface Name of iface on which this occurred.
493     * @param status Status code for association rejection.
494     * @param timedOut Indicates if the association timed out.
495     * @param bssid BSSID of the access point from which we received the reject.
496     */
497    public void broadcastAssociationRejectionEvent(String iface, int status, boolean timedOut,
498                                                   String bssid) {
499        sendMessage(iface, ASSOCIATION_REJECTION_EVENT, timedOut ? 1 : 0, status, bssid);
500    }
501
502    /**
503     * Broadcast the association success event to all the handlers registered for this event.
504     *
505     * @param iface Name of iface on which this occurred.
506     * @param bssid BSSID of the access point.
507     */
508    public void broadcastAssociatedBssidEvent(String iface, String bssid) {
509        sendMessage(iface, WifiStateMachine.CMD_ASSOCIATED_BSSID, 0, 0, bssid);
510    }
511
512    /**
513     * Broadcast the start of association event to all the handlers registered for this event.
514     *
515     * @param iface Name of iface on which this occurred.
516     * @param bssid BSSID of the access point.
517     */
518    public void broadcastTargetBssidEvent(String iface, String bssid) {
519        sendMessage(iface, WifiStateMachine.CMD_TARGET_BSSID, 0, 0, bssid);
520    }
521
522    /**
523     * Broadcast the network connection event to all the handlers registered for this event.
524     *
525     * @param iface Name of iface on which this occurred.
526     * @param networkId ID of the network in wpa_supplicant.
527     * @param bssid BSSID of the access point.
528     */
529    public void broadcastNetworkConnectionEvent(String iface, int networkId, String bssid) {
530        sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, 0, bssid);
531    }
532
533    /**
534     * Broadcast the network disconnection event to all the handlers registered for this event.
535     *
536     * @param iface Name of iface on which this occurred.
537     * @param local Whether the disconnect was locally triggered.
538     * @param reason Disconnect reason code.
539     * @param bssid BSSID of the access point.
540     */
541    public void broadcastNetworkDisconnectionEvent(String iface, int local, int reason,
542                                                   String bssid) {
543        sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, bssid);
544    }
545
546    /**
547     * Broadcast the supplicant state change event to all the handlers registered for this event.
548     *
549     * @param iface Name of iface on which this occurred.
550     * @param networkId ID of the network in wpa_supplicant.
551     * @param bssid BSSID of the access point.
552     * @param newSupplicantState New supplicant state.
553     */
554    public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid,
555                                                    String bssid,
556                                                    SupplicantState newSupplicantState) {
557        sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
558                new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState));
559    }
560
561    /**
562     * Broadcast the connection to wpa_supplicant event to all the handlers registered for
563     * this event.
564     *
565     * @param iface Name of iface on which this occurred.
566     */
567    public void broadcastSupplicantConnectionEvent(String iface) {
568        sendMessage(iface, SUP_CONNECTION_EVENT);
569    }
570
571    /**
572     * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
573     * this event.
574     *
575     * @param iface Name of iface on which this occurred.
576     */
577    public void broadcastSupplicantDisconnectionEvent(String iface) {
578        sendMessage(iface, SUP_DISCONNECTION_EVENT);
579    }
580}
581