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