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