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