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