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 private final Map<String, Boolean> mMonitoringMap = new HashMap<>(); 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 156 public void setMonitoring(String iface, boolean enabled) { 157 mMonitoringMap.put(iface, enabled); 158 } 159 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 */ 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 */ 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 */ 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 */ 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 */ 241 private void sendMessage(String iface, int what) { 242 sendMessage(iface, Message.obtain(null, what)); 243 } 244 245 private void sendMessage(String iface, int what, Object obj) { 246 sendMessage(iface, Message.obtain(null, what, obj)); 247 } 248 249 private void sendMessage(String iface, int what, int arg1) { 250 sendMessage(iface, Message.obtain(null, what, arg1, 0)); 251 } 252 253 private void sendMessage(String iface, int what, int arg1, int arg2) { 254 sendMessage(iface, Message.obtain(null, what, arg1, arg2)); 255 } 256 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 563 public void broadcastSupplicantDisconnectionEvent(String iface) { 564 sendMessage(iface, SUP_DISCONNECTION_EVENT); 565 } 566 } 567