WifiMonitor.java revision 7f21b7a68872183ae89545b07f716aafa7dc3674
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.NetworkInfo; 20import android.net.wifi.SupplicantState; 21import android.net.wifi.WifiEnterpriseConfig; 22import android.net.wifi.WifiManager; 23import android.net.wifi.WifiSsid; 24import android.net.wifi.p2p.WifiP2pConfig; 25import android.net.wifi.p2p.WifiP2pDevice; 26import android.net.wifi.p2p.WifiP2pGroup; 27import android.net.wifi.p2p.WifiP2pProvDiscEvent; 28import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 29import android.os.Handler; 30import android.os.Message; 31import android.text.TextUtils; 32import android.util.ArraySet; 33import android.util.Base64; 34import android.util.LocalLog; 35import android.util.Log; 36import android.util.SparseArray; 37 38import com.android.internal.annotations.VisibleForTesting; 39import com.android.internal.util.Protocol; 40import com.android.internal.util.StateMachine; 41import com.android.server.wifi.hotspot2.AnqpEvent; 42import com.android.server.wifi.hotspot2.IconEvent; 43import com.android.server.wifi.hotspot2.Utils; 44import com.android.server.wifi.hotspot2.WnmData; 45import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus; 46import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData; 47 48import java.io.IOException; 49import java.util.HashMap; 50import java.util.List; 51import java.util.Map; 52import java.util.Set; 53import java.util.regex.Matcher; 54import java.util.regex.Pattern; 55 56/** 57 * Listens for events from the wpa_supplicant server, and passes them on 58 * to the {@link StateMachine} for handling. Runs in its own thread. 59 * 60 * @hide 61 */ 62public class WifiMonitor { 63 64 private static final boolean DBG = false; 65 private static final String TAG = "WifiMonitor"; 66 67 /** Events we receive from the supplicant daemon */ 68 69 private static final int CONNECTED = 1; 70 private static final int DISCONNECTED = 2; 71 private static final int STATE_CHANGE = 3; 72 private static final int SCAN_RESULTS = 4; 73 private static final int LINK_SPEED = 5; 74 private static final int TERMINATING = 6; 75 private static final int DRIVER_STATE = 7; 76 private static final int EAP_FAILURE = 8; 77 private static final int ASSOC_REJECT = 9; 78 private static final int SSID_TEMP_DISABLE = 10; 79 private static final int SSID_REENABLE = 11; 80 private static final int BSS_ADDED = 12; 81 private static final int BSS_REMOVED = 13; 82 private static final int UNKNOWN = 14; 83 private static final int SCAN_FAILED = 15; 84 85 /** All events coming from the supplicant start with this prefix */ 86 private static final String EVENT_PREFIX_STR = "CTRL-EVENT-"; 87 private static final int EVENT_PREFIX_LEN_STR = EVENT_PREFIX_STR.length(); 88 89 /** All events coming from the supplicant start with this prefix */ 90 private static final String REQUEST_PREFIX_STR = "CTRL-REQ-"; 91 private static final int REQUEST_PREFIX_LEN_STR = REQUEST_PREFIX_STR.length(); 92 93 94 /** All WPA events coming from the supplicant start with this prefix */ 95 private static final String WPA_EVENT_PREFIX_STR = "WPA:"; 96 private static final String PASSWORD_MAY_BE_INCORRECT_STR = 97 "pre-shared key may be incorrect"; 98 99 /* WPS events */ 100 private static final String WPS_SUCCESS_STR = "WPS-SUCCESS"; 101 102 /* Format: WPS-FAIL msg=%d [config_error=%d] [reason=%d (%s)] */ 103 private static final String WPS_FAIL_STR = "WPS-FAIL"; 104 private static final String WPS_FAIL_PATTERN = 105 "WPS-FAIL msg=\\d+(?: config_error=(\\d+))?(?: reason=(\\d+))?"; 106 107 /* config error code values for config_error=%d */ 108 private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12; 109 private static final int CONFIG_AUTH_FAILURE = 18; 110 111 /* reason code values for reason=%d */ 112 private static final int REASON_TKIP_ONLY_PROHIBITED = 1; 113 private static final int REASON_WEP_PROHIBITED = 2; 114 115 private static final String WPS_OVERLAP_STR = "WPS-OVERLAP-DETECTED"; 116 private static final String WPS_TIMEOUT_STR = "WPS-TIMEOUT"; 117 118 /* Hotspot 2.0 ANQP query events */ 119 private static final String GAS_QUERY_PREFIX_STR = "GAS-QUERY-"; 120 private static final String GAS_QUERY_START_STR = "GAS-QUERY-START"; 121 private static final String GAS_QUERY_DONE_STR = "GAS-QUERY-DONE"; 122 private static final String RX_HS20_ANQP_ICON_STR = "RX-HS20-ANQP-ICON"; 123 private static final int RX_HS20_ANQP_ICON_STR_LEN = RX_HS20_ANQP_ICON_STR.length(); 124 125 /* Hotspot 2.0 events */ 126 private static final String HS20_PREFIX_STR = "HS20-"; 127 public static final String HS20_SUB_REM_STR = "HS20-SUBSCRIPTION-REMEDIATION"; 128 public static final String HS20_DEAUTH_STR = "HS20-DEAUTH-IMMINENT-NOTICE"; 129 130 private static final String IDENTITY_STR = "IDENTITY"; 131 132 private static final String SIM_STR = "SIM"; 133 134 //used to debug and detect if we miss an event 135 private static int eventLogCounter = 0; 136 137 /** 138 * Names of events from wpa_supplicant (minus the prefix). In the 139 * format descriptions, * "<code>x</code>" 140 * designates a dynamic value that needs to be parsed out from the event 141 * string 142 */ 143 /** 144 * <pre> 145 * CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed 146 * </pre> 147 * <code>xx:xx:xx:xx:xx:xx</code> is the BSSID of the associated access point 148 */ 149 private static final String CONNECTED_STR = "CONNECTED"; 150 private static final String ConnectPrefix = "Connection to "; 151 private static final String ConnectSuffix = " completed"; 152 153 /** 154 * <pre> 155 * CTRL-EVENT-DISCONNECTED - Disconnect event - remove keys 156 * </pre> 157 */ 158 private static final String DISCONNECTED_STR = "DISCONNECTED"; 159 /** 160 * <pre> 161 * CTRL-EVENT-STATE-CHANGE x 162 * </pre> 163 * <code>x</code> is the numerical value of the new state. 164 */ 165 private static final String STATE_CHANGE_STR = "STATE-CHANGE"; 166 /** 167 * <pre> 168 * CTRL-EVENT-SCAN-RESULTS ready 169 * </pre> 170 */ 171 private static final String SCAN_RESULTS_STR = "SCAN-RESULTS"; 172 173 /** 174 * <pre> 175 * CTRL-EVENT-SCAN-FAILED ret=code[ retry=1] 176 * </pre> 177 */ 178 private static final String SCAN_FAILED_STR = "SCAN-FAILED"; 179 180 /** 181 * <pre> 182 * CTRL-EVENT-LINK-SPEED x Mb/s 183 * </pre> 184 * {@code x} is the link speed in Mb/sec. 185 */ 186 private static final String LINK_SPEED_STR = "LINK-SPEED"; 187 /** 188 * <pre> 189 * CTRL-EVENT-TERMINATING - signal x 190 * </pre> 191 * <code>x</code> is the signal that caused termination. 192 */ 193 private static final String TERMINATING_STR = "TERMINATING"; 194 /** 195 * <pre> 196 * CTRL-EVENT-DRIVER-STATE state 197 * </pre> 198 * <code>state</code> can be HANGED 199 */ 200 private static final String DRIVER_STATE_STR = "DRIVER-STATE"; 201 /** 202 * <pre> 203 * CTRL-EVENT-EAP-FAILURE EAP authentication failed 204 * </pre> 205 */ 206 private static final String EAP_FAILURE_STR = "EAP-FAILURE"; 207 208 /** 209 * This indicates an authentication failure on EAP FAILURE event 210 */ 211 private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed"; 212 213 /* EAP authentication timeout events */ 214 private static final String AUTH_EVENT_PREFIX_STR = "Authentication with"; 215 private static final String AUTH_TIMEOUT_STR = "timed out."; 216 217 /** 218 * This indicates an assoc reject event 219 */ 220 private static final String ASSOC_REJECT_STR = "ASSOC-REJECT"; 221 222 /** 223 * This indicates auth or association failure bad enough so as network got disabled 224 * - WPA_PSK auth failure suspecting shared key mismatch 225 * - failed multiple Associations 226 */ 227 private static final String TEMP_DISABLED_STR = "SSID-TEMP-DISABLED"; 228 229 /** 230 * This indicates a previously disabled SSID was reenabled by supplicant 231 */ 232 private static final String REENABLED_STR = "SSID-REENABLED"; 233 234 /** 235 * This indicates supplicant found a given BSS 236 */ 237 private static final String BSS_ADDED_STR = "BSS-ADDED"; 238 239 /** 240 * This indicates supplicant removed a given BSS 241 */ 242 private static final String BSS_REMOVED_STR = "BSS-REMOVED"; 243 244 /** 245 * Regex pattern for extracting an Ethernet-style MAC address from a string. 246 * Matches a strings like the following:<pre> 247 * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]</pre> 248 */ 249 private static Pattern mConnectedEventPattern = 250 Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) "); 251 252 /** 253 * Regex pattern for extracting an Ethernet-style MAC address from a string. 254 * Matches a strings like the following:<pre> 255 * CTRL-EVENT-DISCONNECTED - bssid=ac:22:0b:24:70:74 reason=3 locally_generated=1 256 */ 257 private static Pattern mDisconnectedEventPattern = 258 Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) +" + 259 "reason=([0-9]+) +locally_generated=([0-1])"); 260 261 /** 262 * Regex pattern for extracting an Ethernet-style MAC address from a string. 263 * Matches a strings like the following:<pre> 264 * CTRL-EVENT-ASSOC-REJECT - bssid=ac:22:0b:24:70:74 status_code=1 265 */ 266 private static Pattern mAssocRejectEventPattern = 267 Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) +" + 268 "status_code=([0-9]+)"); 269 270 /** 271 * Regex pattern for extracting an Ethernet-style MAC address from a string. 272 * Matches a strings like the following:<pre> 273 * IFNAME=wlan0 Trying to associate with 6c:f3:7f:ae:87:71 274 */ 275 private static final String TARGET_BSSID_STR = "Trying to associate with "; 276 277 private static Pattern mTargetBSSIDPattern = 278 Pattern.compile("Trying to associate with ((?:[0-9a-f]{2}:){5}[0-9a-f]{2}).*"); 279 280 /** 281 * Regex pattern for extracting an Ethernet-style MAC address from a string. 282 * Matches a strings like the following:<pre> 283 * IFNAME=wlan0 Associated with 6c:f3:7f:ae:87:71 284 */ 285 private static final String ASSOCIATED_WITH_STR = "Associated with "; 286 287 private static Pattern mAssociatedPattern = 288 Pattern.compile("Associated with ((?:[0-9a-f]{2}:){5}[0-9a-f]{2}).*"); 289 290 /** 291 * Regex pattern for extracting an external GSM sim authentication request from a string. 292 * Matches a strings like the following:<pre> 293 * CTRL-REQ-SIM-<network id>:GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>] needed for SSID <SSID> 294 * This pattern should find 295 * 0 - id 296 * 1 - Rand1 297 * 2 - Rand2 298 * 3 - Rand3 299 * 4 - SSID 300 */ 301 private static Pattern mRequestGsmAuthPattern = 302 Pattern.compile("SIM-([0-9]*):GSM-AUTH((:[0-9a-f]+)+) needed for SSID (.+)"); 303 304 /** 305 * Regex pattern for extracting an external 3G sim authentication request from a string. 306 * Matches a strings like the following:<pre> 307 * CTRL-REQ-SIM-<network id>:UMTS-AUTH:<RAND>:<AUTN> needed for SSID <SSID> 308 * This pattern should find 309 * 1 - id 310 * 2 - Rand 311 * 3 - Autn 312 * 4 - SSID 313 */ 314 private static Pattern mRequestUmtsAuthPattern = 315 Pattern.compile("SIM-([0-9]*):UMTS-AUTH:([0-9a-f]+):([0-9a-f]+) needed for SSID (.+)"); 316 317 /** 318 * Regex pattern for extracting SSIDs from request identity string. 319 * Matches a strings like the following:<pre> 320 * CTRL-REQ-IDENTITY-xx:Identity needed for SSID XXXX</pre> 321 */ 322 private static Pattern mRequestIdentityPattern = 323 Pattern.compile("IDENTITY-([0-9]+):Identity needed for SSID (.+)"); 324 325 /** P2P events */ 326 private static final String P2P_EVENT_PREFIX_STR = "P2P"; 327 328 /* P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 pri_dev_type=1-0050F204-1 329 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ 330 private static final String P2P_DEVICE_FOUND_STR = "P2P-DEVICE-FOUND"; 331 332 /* P2P-DEVICE-LOST p2p_dev_addr=42:fc:89:e1:e2:27 */ 333 private static final String P2P_DEVICE_LOST_STR = "P2P-DEVICE-LOST"; 334 335 /* P2P-FIND-STOPPED */ 336 private static final String P2P_FIND_STOPPED_STR = "P2P-FIND-STOPPED"; 337 338 /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */ 339 private static final String P2P_GO_NEG_REQUEST_STR = "P2P-GO-NEG-REQUEST"; 340 341 private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS"; 342 343 /* P2P-GO-NEG-FAILURE status=x */ 344 private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE"; 345 346 private static final String P2P_GROUP_FORMATION_SUCCESS_STR = 347 "P2P-GROUP-FORMATION-SUCCESS"; 348 349 private static final String P2P_GROUP_FORMATION_FAILURE_STR = 350 "P2P-GROUP-FORMATION-FAILURE"; 351 352 /* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437 353 [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"] 354 go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT] */ 355 private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED"; 356 357 /* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */ 358 private static final String P2P_GROUP_REMOVED_STR = "P2P-GROUP-REMOVED"; 359 360 /* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13 361 bssid=fa:7b:7a:42:82:13 unknown-network */ 362 private static final String P2P_INVITATION_RECEIVED_STR = "P2P-INVITATION-RECEIVED"; 363 364 /* P2P-INVITATION-RESULT status=1 */ 365 private static final String P2P_INVITATION_RESULT_STR = "P2P-INVITATION-RESULT"; 366 367 /* P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 368 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 369 group_capab=0x0 */ 370 private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ"; 371 372 /* P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 */ 373 private static final String P2P_PROV_DISC_PBC_RSP_STR = "P2P-PROV-DISC-PBC-RESP"; 374 375 /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 376 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 377 group_capab=0x0 */ 378 private static final String P2P_PROV_DISC_ENTER_PIN_STR = "P2P-PROV-DISC-ENTER-PIN"; 379 /* P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 380 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 381 group_capab=0x0 */ 382 private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN"; 383 /* P2P-PROV-DISC-FAILURE p2p_dev_addr=42:fc:89:e1:e2:27 */ 384 private static final String P2P_PROV_DISC_FAILURE_STR = "P2P-PROV-DISC-FAILURE"; 385 386 /* 387 * Protocol format is as follows.<br> 388 * See the Table.62 in the WiFi Direct specification for the detail. 389 * ______________________________________________________________ 390 * | Length(2byte) | Type(1byte) | TransId(1byte)}| 391 * ______________________________________________________________ 392 * | status(1byte) | vendor specific(variable) | 393 * 394 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300000101 395 * length=3, service type=0(ALL Service), transaction id=1, 396 * status=1(service protocol type not available)<br> 397 * 398 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300020201 399 * length=3, service type=2(UPnP), transaction id=2, 400 * status=1(service protocol type not available) 401 * 402 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 990002030010757569643a3131323 403 * 2646534652d383537342d353961622d393332322d3333333435363738393034343a3 404 * a75726e3a736368656d61732d75706e702d6f72673a736572766963653a436f6e746 405 * 56e744469726563746f72793a322c757569643a36383539646564652d383537342d3 406 * 53961622d393333322d3132333435363738393031323a3a75706e703a726f6f74646 407 * 576696365 408 * length=153,type=2(UPnP),transaction id=3,status=0 409 * 410 * UPnP Protocol format is as follows. 411 * ______________________________________________________ 412 * | Version (1) | USN (Variable) | 413 * 414 * version=0x10(UPnP1.0) data=usn:uuid:1122de4e-8574-59ab-9322-33345678 415 * 9044::urn:schemas-upnp-org:service:ContentDirectory:2,usn:uuid:6859d 416 * ede-8574-59ab-9332-123456789012::upnp:rootdevice 417 * 418 * P2P-SERV-DISC-RESP 58:17:0c:bc:dd:ca 21 1900010200045f6970 419 * 70c00c000c01094d795072696e746572c027 420 * length=25, type=1(Bonjour),transaction id=2,status=0 421 * 422 * Bonjour Protocol format is as follows. 423 * __________________________________________________________ 424 * |DNS Name(Variable)|DNS Type(1)|Version(1)|RDATA(Variable)| 425 * 426 * DNS Name=_ipp._tcp.local.,DNS type=12(PTR), Version=1, 427 * RDATA=MyPrinter._ipp._tcp.local. 428 * 429 */ 430 private static final String P2P_SERV_DISC_RESP_STR = "P2P-SERV-DISC-RESP"; 431 432 private static final String HOST_AP_EVENT_PREFIX_STR = "AP"; 433 /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */ 434 private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED"; 435 /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ 436 private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; 437 private static final String ANQP_DONE_STR = "ANQP-QUERY-DONE"; 438 private static final String HS20_ICON_STR = "RX-HS20-ICON"; 439 440 /* Supplicant events reported to a state machine */ 441 private static final int BASE = Protocol.BASE_WIFI_MONITOR; 442 443 /* Connection to supplicant established */ 444 public static final int SUP_CONNECTION_EVENT = BASE + 1; 445 /* Connection to supplicant lost */ 446 public static final int SUP_DISCONNECTION_EVENT = BASE + 2; 447 /* Network connection completed */ 448 public static final int NETWORK_CONNECTION_EVENT = BASE + 3; 449 /* Network disconnection completed */ 450 public static final int NETWORK_DISCONNECTION_EVENT = BASE + 4; 451 /* Scan results are available */ 452 public static final int SCAN_RESULTS_EVENT = BASE + 5; 453 /* Supplicate state changed */ 454 public static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 6; 455 /* Password failure and EAP authentication failure */ 456 public static final int AUTHENTICATION_FAILURE_EVENT = BASE + 7; 457 /* WPS success detected */ 458 public static final int WPS_SUCCESS_EVENT = BASE + 8; 459 /* WPS failure detected */ 460 public static final int WPS_FAIL_EVENT = BASE + 9; 461 /* WPS overlap detected */ 462 public static final int WPS_OVERLAP_EVENT = BASE + 10; 463 /* WPS timeout detected */ 464 public static final int WPS_TIMEOUT_EVENT = BASE + 11; 465 /* Driver was hung */ 466 public static final int DRIVER_HUNG_EVENT = BASE + 12; 467 /* SSID was disabled due to auth failure or excessive 468 * connection failures */ 469 public static final int SSID_TEMP_DISABLED = BASE + 13; 470 /* SSID reenabled by supplicant */ 471 public static final int SSID_REENABLED = BASE + 14; 472 473 /* Request Identity */ 474 public static final int SUP_REQUEST_IDENTITY = BASE + 15; 475 476 /* Request SIM Auth */ 477 public static final int SUP_REQUEST_SIM_AUTH = BASE + 16; 478 479 public static final int SCAN_FAILED_EVENT = BASE + 17; 480 481 /* P2P events */ 482 public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21; 483 public static final int P2P_DEVICE_LOST_EVENT = BASE + 22; 484 public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23; 485 public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25; 486 public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26; 487 public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27; 488 public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28; 489 public static final int P2P_GROUP_STARTED_EVENT = BASE + 29; 490 public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30; 491 public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; 492 public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; 493 public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; 494 public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34; 495 public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35; 496 public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36; 497 public static final int P2P_FIND_STOPPED_EVENT = BASE + 37; 498 public static final int P2P_SERV_DISC_RESP_EVENT = BASE + 38; 499 public static final int P2P_PROV_DISC_FAILURE_EVENT = BASE + 39; 500 501 /* hostap events */ 502 public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; 503 public static final int AP_STA_CONNECTED_EVENT = BASE + 42; 504 505 /* Indicates assoc reject event */ 506 public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43; 507 public static final int ANQP_DONE_EVENT = BASE + 44; 508 509 /* hotspot 2.0 ANQP events */ 510 public static final int GAS_QUERY_START_EVENT = BASE + 51; 511 public static final int GAS_QUERY_DONE_EVENT = BASE + 52; 512 public static final int RX_HS20_ANQP_ICON_EVENT = BASE + 53; 513 514 /* hotspot 2.0 events */ 515 public static final int HS20_REMEDIATION_EVENT = BASE + 61; 516 517 /** 518 * This indicates a read error on the monitor socket conenction 519 */ 520 private static final String WPA_RECV_ERROR_STR = "recv error"; 521 522 /** 523 * Max errors before we close supplicant connection 524 */ 525 private static final int MAX_RECV_ERRORS = 10; 526 527 /** 528 * Authentication Failure reasonCode, used internally by WifiStateMachine 529 * @hide 530 */ 531 public static final int AUTHENTICATION_FAILURE_REASON_DEFAULT = 0; 532 public static final int AUTHENTICATION_FAILURE_REASON_TIMEOUT = 1; 533 public static final int AUTHENTICATION_FAILURE_REASON_WRONG_PSWD = 2; 534 public static final int AUTHENTICATION_FAILURE_REASON_EAP_FAILURE = 3; 535 536 /** 537 * Used for icon retrieval. 538 */ 539 private static final int ICON_CHUNK_SIZE = 1400; // 2K*3/4 - overhead 540 541 // Singleton instance 542 private static WifiMonitor sWifiMonitor = new WifiMonitor(); 543 public static WifiMonitor getInstance() { 544 return sWifiMonitor; 545 } 546 547 private final WifiNative mWifiNative; 548 private WifiMonitor() { 549 mWifiNative = WifiNative.getWlanNativeInterface(); 550 } 551 552 private int mRecvErrors = 0; 553 private boolean mVerboseLoggingEnabled = false; 554 555 void enableVerboseLogging(int verbose) { 556 if (verbose > 0) { 557 mVerboseLoggingEnabled = true; 558 } else { 559 mVerboseLoggingEnabled = false; 560 } 561 } 562 563 private boolean mConnected = false; 564 565 // TODO(b/27569474) remove support for multiple handlers for the same event 566 private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>(); 567 public synchronized void registerHandler(String iface, int what, Handler handler) { 568 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 569 if (ifaceHandlers == null) { 570 ifaceHandlers = new SparseArray<>(); 571 mHandlerMap.put(iface, ifaceHandlers); 572 } 573 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what); 574 if (ifaceWhatHandlers == null) { 575 ifaceWhatHandlers = new ArraySet<>(); 576 ifaceHandlers.put(what, ifaceWhatHandlers); 577 } 578 ifaceWhatHandlers.add(handler); 579 } 580 581 private final Map<String, Boolean> mMonitoringMap = new HashMap<>(); 582 private boolean isMonitoring(String iface) { 583 Boolean val = mMonitoringMap.get(iface); 584 if (val == null) { 585 return false; 586 } 587 else { 588 return val.booleanValue(); 589 } 590 } 591 592 /** 593 * Enable/Disable monitoring for the provided iface. 594 * 595 * @param iface Name of the iface. 596 * @param enabled true to enable, false to disable. 597 */ 598 @VisibleForTesting 599 public void setMonitoring(String iface, boolean enabled) { 600 mMonitoringMap.put(iface, enabled); 601 } 602 603 private void setMonitoringNone() { 604 for (String iface : mMonitoringMap.keySet()) { 605 setMonitoring(iface, false); 606 } 607 } 608 609 610 private boolean ensureConnectedLocked() { 611 if (mConnected) { 612 return true; 613 } 614 615 if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant"); 616 int connectTries = 0; 617 while (true) { 618 if (mWifiNative.connectToSupplicant()) { 619 mConnected = true; 620 new MonitorThread(mWifiNative.getLocalLog()).start(); 621 return true; 622 } 623 if (connectTries++ < 5) { 624 try { 625 Thread.sleep(1000); 626 } catch (InterruptedException ignore) { 627 } 628 } else { 629 return false; 630 } 631 } 632 } 633 634 public synchronized void startMonitoring(String iface) { 635 Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected); 636 637 if (ensureConnectedLocked()) { 638 setMonitoring(iface, true); 639 sendMessage(iface, SUP_CONNECTION_EVENT); 640 } 641 else { 642 boolean originalMonitoring = isMonitoring(iface); 643 setMonitoring(iface, true); 644 sendMessage(iface, SUP_DISCONNECTION_EVENT); 645 setMonitoring(iface, originalMonitoring); 646 Log.e(TAG, "startMonitoring(" + iface + ") failed!"); 647 } 648 } 649 650 public synchronized void stopMonitoring(String iface) { 651 if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")"); 652 setMonitoring(iface, true); 653 sendMessage(iface, SUP_DISCONNECTION_EVENT); 654 setMonitoring(iface, false); 655 } 656 657 public synchronized void stopSupplicant() { 658 mWifiNative.stopSupplicant(); 659 } 660 661 public synchronized void stopAllMonitoring() { 662 mConnected = false; 663 setMonitoringNone(); 664 } 665 666 667 /** 668 * Similar functions to Handler#sendMessage that send the message to the registered handler 669 * for the given interface and message what. 670 * All of these should be called with the WifiMonitor class lock 671 */ 672 private void sendMessage(String iface, int what) { 673 sendMessage(iface, Message.obtain(null, what)); 674 } 675 676 private void sendMessage(String iface, int what, Object obj) { 677 sendMessage(iface, Message.obtain(null, what, obj)); 678 } 679 680 private void sendMessage(String iface, int what, int arg1) { 681 sendMessage(iface, Message.obtain(null, what, arg1, 0)); 682 } 683 684 private void sendMessage(String iface, int what, int arg1, int arg2) { 685 sendMessage(iface, Message.obtain(null, what, arg1, arg2)); 686 } 687 688 private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) { 689 sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj)); 690 } 691 692 private void sendMessage(String iface, Message message) { 693 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 694 if (iface != null && ifaceHandlers != null) { 695 if (isMonitoring(iface)) { 696 boolean firstHandler = true; 697 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what); 698 if (ifaceWhatHandlers != null) { 699 for (Handler handler : ifaceWhatHandlers) { 700 if (firstHandler) { 701 firstHandler = false; 702 sendMessage(handler, message); 703 } 704 else { 705 sendMessage(handler, Message.obtain(message)); 706 } 707 } 708 } 709 } else { 710 if (mVerboseLoggingEnabled) { 711 Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); 712 } 713 } 714 } else { 715 if (mVerboseLoggingEnabled) { 716 Log.d(TAG, "Sending to all monitors because there's no matching iface"); 717 } 718 boolean firstHandler = true; 719 for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) { 720 if (isMonitoring(entry.getKey())) { 721 Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what); 722 for (Handler handler : ifaceWhatHandlers) { 723 if (firstHandler) { 724 firstHandler = false; 725 sendMessage(handler, message); 726 } 727 else { 728 sendMessage(handler, Message.obtain(message)); 729 } 730 } 731 } 732 } 733 } 734 } 735 736 private void sendMessage(Handler handler, Message message) { 737 if (handler != null) { 738 message.setTarget(handler); 739 message.sendToTarget(); 740 } 741 } 742 743 private class MonitorThread extends Thread { 744 private final LocalLog mLocalLog; 745 746 public MonitorThread(LocalLog localLog) { 747 super("WifiMonitor"); 748 mLocalLog = localLog; 749 } 750 751 public void run() { 752 if (mVerboseLoggingEnabled) { 753 Log.d(TAG, "MonitorThread start with mConnected=" + mConnected); 754 } 755 //noinspection InfiniteLoopStatement 756 for (;;) { 757 if (!mConnected) { 758 if (mVerboseLoggingEnabled) { 759 Log.d(TAG, "MonitorThread exit because mConnected is false"); 760 } 761 break; 762 } 763 String eventStr = mWifiNative.waitForEvent(); 764 765 // Skip logging the common but mostly uninteresting events 766 if (!eventStr.contains(BSS_ADDED_STR) && !eventStr.contains(BSS_REMOVED_STR)) { 767 if (mVerboseLoggingEnabled) Log.d(TAG, "Event [" + eventStr + "]"); 768 mLocalLog.log("Event [" + eventStr + "]"); 769 } 770 771 if (dispatchEvent(eventStr)) { 772 if (mVerboseLoggingEnabled) { 773 Log.d(TAG, "Disconnecting from the supplicant, no more events"); 774 } 775 break; 776 } 777 } 778 } 779 } 780 781 private synchronized boolean dispatchEvent(String eventStr) { 782 String iface; 783 // IFNAME=wlan0 ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS 784 if (eventStr.startsWith("IFNAME=")) { 785 int space = eventStr.indexOf(' '); 786 if (space != -1) { 787 iface = eventStr.substring(7, space); 788 if (!mHandlerMap.containsKey(iface) && iface.startsWith("p2p-")) { 789 // p2p interfaces are created dynamically, but we have 790 // only one P2p state machine monitoring all of them; look 791 // for it explicitly, and send messages there .. 792 iface = "p2p0"; 793 } 794 eventStr = eventStr.substring(space + 1); 795 } else { 796 // No point dispatching this event to any interface, the dispatched 797 // event string will begin with "IFNAME=" which dispatchEvent can't really 798 // do anything about. 799 Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr); 800 return false; 801 } 802 } else { 803 // events without prefix belong to p2p0 monitor 804 iface = "p2p0"; 805 } 806 807 if (DBG) Log.d(TAG, "Dispatching event to interface: " + iface); 808 809 if (dispatchEvent(eventStr, iface)) { 810 mConnected = false; 811 return true; 812 } 813 return false; 814 } 815 816 private Map<String, Long> mLastConnectBSSIDs = new HashMap<String, Long>() { 817 public Long get(String iface) { 818 Long value = super.get(iface); 819 if (value != null) { 820 return value; 821 } 822 return 0L; 823 } 824 }; 825 826 /* @return true if the event was supplicant disconnection */ 827 private boolean dispatchEvent(String eventStr, String iface) { 828 if (mVerboseLoggingEnabled) { 829 // Dont log CTRL-EVENT-BSS-ADDED which are too verbose and not handled 830 if (eventStr != null && !eventStr.contains("CTRL-EVENT-BSS-ADDED")) { 831 Log.d(TAG, iface + " cnt=" + Integer.toString(eventLogCounter) 832 + " dispatchEvent: " + eventStr); 833 } 834 } 835 836 if (!eventStr.startsWith(EVENT_PREFIX_STR)) { 837 if (eventStr.startsWith(WPS_SUCCESS_STR)) { 838 broadcastWpsSuccessEvent(iface); 839 } else if (eventStr.startsWith(WPS_FAIL_STR)) { 840 handleWpsFailEvent(eventStr, iface); 841 } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { 842 broadcastWpsOverlapEvent(iface); 843 } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { 844 broadcastWpsTimeoutEvent(iface); 845 } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { 846 handleP2pEvents(eventStr, iface); 847 } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { 848 handleHostApEvents(eventStr, iface); 849 } else if (eventStr.startsWith(ANQP_DONE_STR)) { 850 try { 851 handleAnqpResult(eventStr, iface); 852 } 853 catch (IllegalArgumentException iae) { 854 Log.e(TAG, "Bad ANQP event string: '" + eventStr + "': " + iae); 855 } 856 } else if (eventStr.startsWith(HS20_ICON_STR)) { 857 try { 858 handleIconResult(eventStr, iface); 859 } 860 catch (IllegalArgumentException iae) { 861 Log.e(TAG, "Bad Icon event string: '" + eventStr + "': " + iae); 862 } 863 } 864 else if (eventStr.startsWith(HS20_SUB_REM_STR)) { 865 // Tack on the last connected BSSID so we have some idea what AP the WNM pertains to 866 handleWnmFrame(String.format("%012x %s", 867 mLastConnectBSSIDs.get(iface), eventStr), iface); 868 } else if (eventStr.startsWith(HS20_DEAUTH_STR)) { 869 handleWnmFrame(String.format("%012x %s", 870 mLastConnectBSSIDs.get(iface), eventStr), iface); 871 } else if (eventStr.startsWith(REQUEST_PREFIX_STR)) { 872 handleRequests(eventStr, iface); 873 } else if (eventStr.startsWith(TARGET_BSSID_STR)) { 874 handleTargetBSSIDEvent(eventStr, iface); 875 } else if (eventStr.startsWith(ASSOCIATED_WITH_STR)) { 876 handleAssociatedBSSIDEvent(eventStr, iface); 877 } else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR) 878 && eventStr.endsWith(AUTH_TIMEOUT_STR)) { 879 sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, eventLogCounter, 880 AUTHENTICATION_FAILURE_REASON_TIMEOUT); 881 } else if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) 882 && eventStr.endsWith(PASSWORD_MAY_BE_INCORRECT_STR)) { 883 sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, eventLogCounter, 884 AUTHENTICATION_FAILURE_REASON_WRONG_PSWD); 885 } else { 886 if (mVerboseLoggingEnabled) { 887 Log.w(TAG, "couldn't identify event type - " + eventStr); 888 } 889 } 890 eventLogCounter++; 891 return false; 892 } 893 894 String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); 895 int nameEnd = eventName.indexOf(' '); 896 if (nameEnd != -1) 897 eventName = eventName.substring(0, nameEnd); 898 if (eventName.length() == 0) { 899 if (mVerboseLoggingEnabled) { 900 Log.i(TAG, "Received wpa_supplicant event with empty event name"); 901 } 902 eventLogCounter++; 903 return false; 904 } 905 /* 906 * Map event name into event enum 907 */ 908 int event; 909 if (eventName.equals(CONNECTED_STR)) { 910 event = CONNECTED; 911 long bssid = -1L; 912 int prefix = eventStr.indexOf(ConnectPrefix); 913 if (prefix >= 0) { 914 int suffix = eventStr.indexOf(ConnectSuffix); 915 if (suffix > prefix) { 916 try { 917 bssid = Utils.parseMac( 918 eventStr.substring(prefix + ConnectPrefix.length(), suffix)); 919 } catch (IllegalArgumentException iae) { 920 bssid = -1L; 921 } 922 } 923 } 924 mLastConnectBSSIDs.put(iface, bssid); 925 if (bssid == -1L) { 926 Log.w(TAG, "Failed to parse out BSSID from '" + eventStr + "'"); 927 } 928 } 929 else if (eventName.equals(DISCONNECTED_STR)) 930 event = DISCONNECTED; 931 else if (eventName.equals(STATE_CHANGE_STR)) 932 event = STATE_CHANGE; 933 else if (eventName.equals(SCAN_RESULTS_STR)) 934 event = SCAN_RESULTS; 935 else if (eventName.equals(SCAN_FAILED_STR)) 936 event = SCAN_FAILED; 937 else if (eventName.equals(LINK_SPEED_STR)) 938 event = LINK_SPEED; 939 else if (eventName.equals(TERMINATING_STR)) 940 event = TERMINATING; 941 else if (eventName.equals(DRIVER_STATE_STR)) 942 event = DRIVER_STATE; 943 else if (eventName.equals(EAP_FAILURE_STR)) 944 event = EAP_FAILURE; 945 else if (eventName.equals(ASSOC_REJECT_STR)) 946 event = ASSOC_REJECT; 947 else if (eventName.equals(TEMP_DISABLED_STR)) { 948 event = SSID_TEMP_DISABLE; 949 } else if (eventName.equals(REENABLED_STR)) { 950 event = SSID_REENABLE; 951 } else if (eventName.equals(BSS_ADDED_STR)) { 952 event = BSS_ADDED; 953 } else if (eventName.equals(BSS_REMOVED_STR)) { 954 event = BSS_REMOVED; 955 } else 956 event = UNKNOWN; 957 958 String eventData = eventStr; 959 if (event == DRIVER_STATE || event == LINK_SPEED) 960 eventData = eventData.split(" ")[1]; 961 else if (event == STATE_CHANGE || event == EAP_FAILURE) { 962 int ind = eventStr.indexOf(" "); 963 if (ind != -1) { 964 eventData = eventStr.substring(ind + 1); 965 } 966 } else { 967 int ind = eventStr.indexOf(" - "); 968 if (ind != -1) { 969 eventData = eventStr.substring(ind + 3); 970 } 971 } 972 973 if ((event == SSID_TEMP_DISABLE)||(event == SSID_REENABLE)) { 974 String substr = null; 975 int netId = -1; 976 int ind = eventStr.indexOf(" "); 977 if (ind != -1) { 978 substr = eventStr.substring(ind + 1); 979 } 980 if (substr != null) { 981 String status[] = substr.split(" "); 982 for (String key : status) { 983 if (key.regionMatches(0, "id=", 0, 3)) { 984 int idx = 3; 985 netId = 0; 986 while (idx < key.length()) { 987 char c = key.charAt(idx); 988 if ((c >= 0x30) && (c <= 0x39)) { 989 netId *= 10; 990 netId += c - 0x30; 991 idx++; 992 } else { 993 break; 994 } 995 } 996 } 997 } 998 } 999 sendMessage(iface, (event == SSID_TEMP_DISABLE)? 1000 SSID_TEMP_DISABLED:SSID_REENABLED, netId, 0, substr); 1001 } else if (event == STATE_CHANGE) { 1002 handleSupplicantStateChange(eventData, iface); 1003 } else if (event == DRIVER_STATE) { 1004 handleDriverEvent(eventData, iface); 1005 } else if (event == TERMINATING) { 1006 /** 1007 * Close the supplicant connection if we see 1008 * too many recv errors 1009 */ 1010 if (eventData.startsWith(WPA_RECV_ERROR_STR)) { 1011 if (++mRecvErrors > MAX_RECV_ERRORS) { 1012 if (mVerboseLoggingEnabled) { 1013 Log.d(TAG, "too many recv errors, closing connection"); 1014 } 1015 } else { 1016 eventLogCounter++; 1017 return false; 1018 } 1019 } 1020 1021 // Notify and exit 1022 sendMessage(null, SUP_DISCONNECTION_EVENT, eventLogCounter); 1023 return true; 1024 } else if (event == EAP_FAILURE) { 1025 if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { 1026 sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, eventLogCounter, 1027 AUTHENTICATION_FAILURE_REASON_EAP_FAILURE); 1028 } 1029 } else if (event == ASSOC_REJECT) { 1030 Matcher match = mAssocRejectEventPattern.matcher(eventData); 1031 String BSSID = ""; 1032 int status = -1; 1033 if (!match.find()) { 1034 if (mVerboseLoggingEnabled) { 1035 Log.d(TAG, "Assoc Reject: Could not parse assoc reject string"); 1036 } 1037 } else { 1038 int groupNumber = match.groupCount(); 1039 int statusGroupNumber = -1; 1040 if (groupNumber == 2) { 1041 BSSID = match.group(1); 1042 statusGroupNumber = 2; 1043 } else { 1044 // Under such case Supplicant does not report BSSID 1045 BSSID = null; 1046 statusGroupNumber = 1; 1047 } 1048 try { 1049 status = Integer.parseInt(match.group(statusGroupNumber)); 1050 } catch (NumberFormatException e) { 1051 status = -1; 1052 } 1053 } 1054 sendMessage(iface, ASSOCIATION_REJECTION_EVENT, eventLogCounter, status, BSSID); 1055 } else if (event == BSS_ADDED && !DBG) { 1056 // Ignore that event - it is not handled, and dont log it as it is too verbose 1057 } else if (event == BSS_REMOVED && !DBG) { 1058 // Ignore that event - it is not handled, and dont log it as it is too verbose 1059 } else { 1060 handleEvent(event, eventData, iface); 1061 } 1062 mRecvErrors = 0; 1063 eventLogCounter++; 1064 return false; 1065 } 1066 1067 private void handleDriverEvent(String state, String iface) { 1068 if (state == null) { 1069 return; 1070 } 1071 if (state.equals("HANGED")) { 1072 sendMessage(iface, DRIVER_HUNG_EVENT); 1073 } 1074 } 1075 1076 /** 1077 * Handle all supplicant events except STATE-CHANGE 1078 * @param event the event type 1079 * @param remainder the rest of the string following the 1080 * event name and " — " 1081 */ 1082 private void handleEvent(int event, String remainder, String iface) { 1083 if (mVerboseLoggingEnabled) { 1084 Log.d(TAG, "handleEvent " + Integer.toString(event) + " " + remainder); 1085 } 1086 switch (event) { 1087 case DISCONNECTED: 1088 handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder, iface); 1089 break; 1090 1091 case CONNECTED: 1092 handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder, iface); 1093 break; 1094 1095 case SCAN_RESULTS: 1096 sendMessage(iface, SCAN_RESULTS_EVENT); 1097 break; 1098 1099 case SCAN_FAILED: 1100 sendMessage(iface, SCAN_FAILED_EVENT); 1101 break; 1102 1103 case UNKNOWN: 1104 if (mVerboseLoggingEnabled) { 1105 Log.w(TAG, "handleEvent unknown: " + Integer.toString(event) + " " + remainder); 1106 } 1107 break; 1108 default: 1109 break; 1110 } 1111 } 1112 1113 private void handleTargetBSSIDEvent(String eventStr, String iface) { 1114 String BSSID = null; 1115 Matcher match = mTargetBSSIDPattern.matcher(eventStr); 1116 if (match.find()) { 1117 BSSID = match.group(1); 1118 } 1119 sendMessage(iface, WifiStateMachine.CMD_TARGET_BSSID, eventLogCounter, 0, BSSID); 1120 } 1121 1122 private void handleAssociatedBSSIDEvent(String eventStr, String iface) { 1123 String BSSID = null; 1124 Matcher match = mAssociatedPattern.matcher(eventStr); 1125 if (match.find()) { 1126 BSSID = match.group(1); 1127 } 1128 sendMessage(iface, WifiStateMachine.CMD_ASSOCIATED_BSSID, eventLogCounter, 0, BSSID); 1129 } 1130 1131 1132 private void handleWpsFailEvent(String dataString, String iface) { 1133 final Pattern p = Pattern.compile(WPS_FAIL_PATTERN); 1134 Matcher match = p.matcher(dataString); 1135 int vendorErrorCodeInt = 0; 1136 int cfgErrInt = 0; 1137 if (match.find()) { 1138 String cfgErrStr = match.group(1); 1139 String vendorErrorCodeStr = match.group(2); 1140 if (vendorErrorCodeStr != null) { 1141 vendorErrorCodeInt = Integer.parseInt(vendorErrorCodeStr); 1142 } 1143 if (cfgErrStr != null) { 1144 cfgErrInt = Integer.parseInt(cfgErrStr); 1145 } 1146 } 1147 broadcastWpsFailEvent(iface, cfgErrInt, vendorErrorCodeInt); 1148 } 1149 1150 /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */ 1151 private P2pStatus p2pError(String dataString) { 1152 P2pStatus err = P2pStatus.UNKNOWN; 1153 String[] tokens = dataString.split(" "); 1154 if (tokens.length < 2) return err; 1155 String[] nameValue = tokens[1].split("="); 1156 if (nameValue.length != 2) return err; 1157 1158 /* Handle the special case of reason=FREQ+CONFLICT */ 1159 if (nameValue[1].equals("FREQ_CONFLICT")) { 1160 return P2pStatus.NO_COMMON_CHANNEL; 1161 } 1162 try { 1163 err = P2pStatus.valueOf(Integer.parseInt(nameValue[1])); 1164 } catch (NumberFormatException e) { 1165 e.printStackTrace(); 1166 } 1167 return err; 1168 } 1169 1170 private WifiP2pDevice getWifiP2pDevice(String dataString) { 1171 try { 1172 return new WifiP2pDevice(dataString); 1173 } catch (IllegalArgumentException e) { 1174 return null; 1175 } 1176 } 1177 1178 private WifiP2pGroup getWifiP2pGroup(String dataString) { 1179 try { 1180 return new WifiP2pGroup(dataString); 1181 } catch (IllegalArgumentException e) { 1182 return null; 1183 } 1184 } 1185 1186 /** 1187 * Handle p2p events 1188 */ 1189 private void handleP2pEvents(String dataString, String iface) { 1190 if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { 1191 WifiP2pDevice device = getWifiP2pDevice(dataString); 1192 if (device != null) sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device); 1193 } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { 1194 WifiP2pDevice device = getWifiP2pDevice(dataString); 1195 if (device != null) sendMessage(iface, P2P_DEVICE_LOST_EVENT, device); 1196 } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) { 1197 sendMessage(iface, P2P_FIND_STOPPED_EVENT); 1198 } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { 1199 sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, new WifiP2pConfig(dataString)); 1200 } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { 1201 sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT); 1202 } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { 1203 sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString)); 1204 } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { 1205 sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT); 1206 } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { 1207 sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString)); 1208 } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { 1209 WifiP2pGroup group = getWifiP2pGroup(dataString); 1210 if (group != null) sendMessage(iface, P2P_GROUP_STARTED_EVENT, group); 1211 } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { 1212 WifiP2pGroup group = getWifiP2pGroup(dataString); 1213 if (group != null) sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group); 1214 } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { 1215 sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, new WifiP2pGroup(dataString)); 1216 } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { 1217 sendMessage(iface, P2P_INVITATION_RESULT_EVENT, p2pError(dataString)); 1218 } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { 1219 sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, new WifiP2pProvDiscEvent(dataString)); 1220 } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { 1221 sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, new WifiP2pProvDiscEvent(dataString)); 1222 } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { 1223 sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, new WifiP2pProvDiscEvent(dataString)); 1224 } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { 1225 sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, new WifiP2pProvDiscEvent(dataString)); 1226 } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) { 1227 sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT); 1228 } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) { 1229 List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString); 1230 if (list != null) { 1231 sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, list); 1232 } else { 1233 Log.e(TAG, "Null service resp " + dataString); 1234 } 1235 } 1236 } 1237 1238 /** 1239 * Handle hostap events 1240 */ 1241 private void handleHostApEvents(String dataString, String iface) { 1242 String[] tokens = dataString.split(" "); 1243 /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ 1244 if (tokens[0].equals(AP_STA_CONNECTED_STR)) { 1245 sendMessage(iface, AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString)); 1246 /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ 1247 } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { 1248 sendMessage(iface, AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString)); 1249 } 1250 } 1251 1252 private static final String ADDR_STRING = "addr="; 1253 private static final String RESULT_STRING = "result="; 1254 1255 // ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS 1256 1257 private void handleAnqpResult(String eventStr, String iface) { 1258 int addrPos = eventStr.indexOf(ADDR_STRING); 1259 int resPos = eventStr.indexOf(RESULT_STRING); 1260 if (addrPos < 0 || resPos < 0) { 1261 throw new IllegalArgumentException("Unexpected ANQP result notification"); 1262 } 1263 int eoaddr = eventStr.indexOf(' ', addrPos + ADDR_STRING.length()); 1264 if (eoaddr < 0) { 1265 eoaddr = eventStr.length(); 1266 } 1267 int eoresult = eventStr.indexOf(' ', resPos + RESULT_STRING.length()); 1268 if (eoresult < 0) { 1269 eoresult = eventStr.length(); 1270 } 1271 1272 long bssid = 0; 1273 int result = 0; 1274 try { 1275 bssid = Utils.parseMac(eventStr.substring(addrPos + ADDR_STRING.length(), eoaddr)); 1276 result = eventStr.substring( 1277 resPos + RESULT_STRING.length(), eoresult).equalsIgnoreCase("success") ? 1 : 0; 1278 } 1279 catch (IllegalArgumentException iae) { 1280 Log.e(TAG, "Bad MAC address in ANQP response: " + iae.getMessage()); 1281 return; 1282 } 1283 AnqpEvent anqpEvent = null; 1284 // If there are no errors fetch the ANQP elements from wpa_supplicant, otherwise return 1285 // empty ANQP elements. 1286 if (bssid != 0 && result != 0) { 1287 String bssData = mWifiNative.scanResult(Utils.macToString(bssid)); 1288 anqpEvent = AnqpEvent.buildAnqpEvent(bssid, bssData); 1289 } else { 1290 anqpEvent = AnqpEvent.buildAnqpEvent(bssid, null); 1291 } 1292 broadcastAnqpDoneEvent(iface, anqpEvent); 1293 } 1294 1295 private void handleIconResult(String eventStr, String iface) { 1296 // RX-HS20-ICON c0:c5:20:27:d1:e8 <file> <size> 1297 String[] segments = eventStr.split(" "); 1298 if (segments.length != 4) { 1299 throw new IllegalArgumentException("Incorrect number of segments"); 1300 } 1301 1302 try { 1303 String bssid = segments[1]; 1304 String fileName = segments[2]; 1305 int size = Integer.parseInt(segments[3]); 1306 byte[] iconData = null; 1307 if (!TextUtils.isEmpty(bssid) && !TextUtils.isEmpty(fileName) && size > 0) { 1308 try { 1309 iconData = retrieveIcon(Utils.parseMac(bssid), fileName, size); 1310 } catch (IOException ioe) { 1311 Log.e(TAG, "Failed to retrieve icon: " + ioe.toString() + ": " + fileName); 1312 } 1313 } 1314 broadcastIconDoneEvent( 1315 iface, new IconEvent(Utils.parseMac(bssid), fileName, size, iconData)); 1316 } 1317 catch (NumberFormatException nfe) { 1318 throw new IllegalArgumentException("Bad numeral"); 1319 } 1320 } 1321 1322 // Retrieve the icon data from wpa_supplicant. 1323 private byte[] retrieveIcon(long bssid, String fileName, int fileSize) throws IOException { 1324 byte[] iconData = new byte[fileSize]; 1325 try { 1326 int offset = 0; 1327 while (offset < fileSize) { 1328 int size = Math.min(fileSize - offset, ICON_CHUNK_SIZE); 1329 1330 String command = String.format("GET_HS20_ICON %s %s %d %d", 1331 Utils.macToString(bssid), fileName, offset, size); 1332 Log.d(TAG, "Issuing '" + command + "'"); 1333 String response = mWifiNative.doCustomSupplicantCommand(command); 1334 if (response == null) { 1335 throw new IOException("No icon data returned"); 1336 } 1337 1338 try { 1339 byte[] fragment = Base64.decode(response, Base64.DEFAULT); 1340 if (fragment.length == 0) { 1341 throw new IOException("Null data for '" + command + "': " + response); 1342 } 1343 if (fragment.length + offset > iconData.length) { 1344 throw new IOException("Icon chunk exceeds image size"); 1345 } 1346 System.arraycopy(fragment, 0, iconData, offset, fragment.length); 1347 offset += fragment.length; 1348 } catch (IllegalArgumentException iae) { 1349 throw new IOException("Failed to parse response to '" + command 1350 + "': " + response); 1351 } 1352 } 1353 if (offset != fileSize) { 1354 Log.w(TAG, "Partial icon data: " + offset + ", expected " + fileSize); 1355 } 1356 } finally { 1357 // Delete the icon file in supplicant. 1358 Log.d(TAG, "Deleting icon for " + fileName); 1359 String result = mWifiNative.doCustomSupplicantCommand("DEL_HS20_ICON " 1360 + Utils.macToString(bssid) + " " + fileName); 1361 Log.d(TAG, "Result: " + result); 1362 } 1363 return iconData; 1364 } 1365 1366 private void handleWnmFrame(String eventStr, String iface) { 1367 try { 1368 WnmData wnmData = WnmData.buildWnmData(eventStr); 1369 broadcastWnmEvent(iface, wnmData); 1370 } catch (IOException | NumberFormatException e) { 1371 Log.w(TAG, "Bad WNM event: '" + eventStr + "'"); 1372 } 1373 } 1374 1375 /** 1376 * Handle Supplicant Requests 1377 */ 1378 private void handleRequests(String dataString, String iface) { 1379 String SSID = null; 1380 int reason = -2; 1381 String requestName = dataString.substring(REQUEST_PREFIX_LEN_STR); 1382 if (TextUtils.isEmpty(requestName)) { 1383 return; 1384 } 1385 if (requestName.startsWith(IDENTITY_STR)) { 1386 Matcher match = mRequestIdentityPattern.matcher(requestName); 1387 if (match.find()) { 1388 SSID = match.group(2); 1389 try { 1390 reason = Integer.parseInt(match.group(1)); 1391 } catch (NumberFormatException e) { 1392 reason = -1; 1393 } 1394 } else { 1395 Log.e(TAG, "didn't find SSID " + requestName); 1396 } 1397 sendMessage(iface, SUP_REQUEST_IDENTITY, eventLogCounter, reason, SSID); 1398 } else if (requestName.startsWith(SIM_STR)) { 1399 Matcher matchGsm = mRequestGsmAuthPattern.matcher(requestName); 1400 Matcher matchUmts = mRequestUmtsAuthPattern.matcher(requestName); 1401 SimAuthRequestData data = new SimAuthRequestData(); 1402 if (matchGsm.find()) { 1403 data.networkId = Integer.parseInt(matchGsm.group(1)); 1404 data.protocol = WifiEnterpriseConfig.Eap.SIM; 1405 data.ssid = matchGsm.group(4); 1406 data.data = matchGsm.group(2).split(":"); 1407 sendMessage(iface, SUP_REQUEST_SIM_AUTH, data); 1408 } else if (matchUmts.find()) { 1409 data.networkId = Integer.parseInt(matchUmts.group(1)); 1410 data.protocol = WifiEnterpriseConfig.Eap.AKA; 1411 data.ssid = matchUmts.group(4); 1412 data.data = new String[2]; 1413 data.data[0] = matchUmts.group(2); 1414 data.data[1] = matchUmts.group(3); 1415 sendMessage(iface, SUP_REQUEST_SIM_AUTH, data); 1416 } else { 1417 Log.e(TAG, "couldn't parse SIM auth request - " + requestName); 1418 } 1419 1420 } else { 1421 if (mVerboseLoggingEnabled) { 1422 Log.w(TAG, "couldn't identify request type - " + dataString); 1423 } 1424 } 1425 } 1426 1427 /** 1428 * Handle the supplicant STATE-CHANGE event 1429 * @param dataString New supplicant state string in the format: 1430 * id=network-id state=new-state 1431 */ 1432 private void handleSupplicantStateChange(String dataString, String iface) { 1433 WifiSsid wifiSsid = null; 1434 int index = dataString.lastIndexOf("SSID="); 1435 if (index != -1) { 1436 wifiSsid = WifiSsid.createFromAsciiEncoded( 1437 dataString.substring(index + 5)); 1438 } 1439 String[] dataTokens = dataString.split(" "); 1440 1441 String BSSID = null; 1442 int networkId = -1; 1443 int newState = -1; 1444 for (String token : dataTokens) { 1445 String[] nameValue = token.split("="); 1446 if (nameValue.length != 2) { 1447 continue; 1448 } 1449 1450 if (nameValue[0].equals("BSSID")) { 1451 BSSID = nameValue[1]; 1452 continue; 1453 } 1454 1455 int value; 1456 try { 1457 value = Integer.parseInt(nameValue[1]); 1458 } catch (NumberFormatException e) { 1459 continue; 1460 } 1461 1462 if (nameValue[0].equals("id")) { 1463 networkId = value; 1464 } else if (nameValue[0].equals("state")) { 1465 newState = value; 1466 } 1467 } 1468 1469 if (newState == -1) return; 1470 1471 SupplicantState newSupplicantState = SupplicantState.INVALID; 1472 for (SupplicantState state : SupplicantState.values()) { 1473 if (state.ordinal() == newState) { 1474 newSupplicantState = state; 1475 break; 1476 } 1477 } 1478 if (newSupplicantState == SupplicantState.INVALID) { 1479 Log.w(TAG, "Invalid supplicant state: " + newState); 1480 } 1481 sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, eventLogCounter, 0, 1482 new StateChangeResult(networkId, wifiSsid, BSSID, newSupplicantState)); 1483 } 1484 1485 private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data, 1486 String iface) { 1487 String BSSID = null; 1488 int networkId = -1; 1489 int reason = 0; 1490 int ind = -1; 1491 int local = 0; 1492 Matcher match; 1493 if (newState == NetworkInfo.DetailedState.CONNECTED) { 1494 match = mConnectedEventPattern.matcher(data); 1495 if (!match.find()) { 1496 if (mVerboseLoggingEnabled) { 1497 Log.d(TAG, "handleNetworkStateChange: Couldnt find BSSID in event string"); 1498 } 1499 } else { 1500 BSSID = match.group(1); 1501 try { 1502 networkId = Integer.parseInt(match.group(2)); 1503 } catch (NumberFormatException e) { 1504 networkId = -1; 1505 } 1506 } 1507 sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, reason, BSSID); 1508 } else if (newState == NetworkInfo.DetailedState.DISCONNECTED) { 1509 match = mDisconnectedEventPattern.matcher(data); 1510 if (!match.find()) { 1511 if (mVerboseLoggingEnabled) { 1512 Log.d(TAG, "handleNetworkStateChange: Could not parse disconnect string"); 1513 } 1514 } else { 1515 BSSID = match.group(1); 1516 try { 1517 reason = Integer.parseInt(match.group(2)); 1518 } catch (NumberFormatException e) { 1519 reason = -1; 1520 } 1521 try { 1522 local = Integer.parseInt(match.group(3)); 1523 } catch (NumberFormatException e) { 1524 local = -1; 1525 } 1526 } 1527 if (mVerboseLoggingEnabled) { 1528 Log.d(TAG, "WifiMonitor notify network disconnect: " + BSSID 1529 + " reason=" + Integer.toString(reason)); 1530 } 1531 sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, BSSID); 1532 } 1533 } 1534 1535 /** 1536 * Broadcast the WPS fail event to all the handlers registered for this event. 1537 * 1538 * @param iface Name of iface on which this occurred. 1539 * @param cfgError Configuration error code. 1540 * @param vendorErrorCode Vendor specific error indication code. 1541 */ 1542 public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) { 1543 int reason = 0; 1544 switch(vendorErrorCode) { 1545 case REASON_TKIP_ONLY_PROHIBITED: 1546 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED); 1547 return; 1548 case REASON_WEP_PROHIBITED: 1549 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED); 1550 return; 1551 default: 1552 reason = vendorErrorCode; 1553 break; 1554 } 1555 switch(cfgError) { 1556 case CONFIG_AUTH_FAILURE: 1557 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE); 1558 return; 1559 case CONFIG_MULTIPLE_PBC_DETECTED: 1560 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR); 1561 return; 1562 default: 1563 if (reason == 0) { 1564 reason = cfgError; 1565 } 1566 break; 1567 } 1568 //For all other errors, return a generic internal error 1569 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason); 1570 } 1571 1572 /** 1573 * Broadcast the WPS succes event to all the handlers registered for this event. 1574 * 1575 * @param iface Name of iface on which this occurred. 1576 */ 1577 public void broadcastWpsSuccessEvent(String iface) { 1578 sendMessage(iface, WPS_SUCCESS_EVENT); 1579 } 1580 1581 /** 1582 * Broadcast the WPS overlap event to all the handlers registered for this event. 1583 * 1584 * @param iface Name of iface on which this occurred. 1585 */ 1586 public void broadcastWpsOverlapEvent(String iface) { 1587 sendMessage(iface, WPS_OVERLAP_EVENT); 1588 } 1589 1590 /** 1591 * Broadcast the WPS timeout event to all the handlers registered for this event. 1592 * 1593 * @param iface Name of iface on which this occurred. 1594 */ 1595 public void broadcastWpsTimeoutEvent(String iface) { 1596 sendMessage(iface, WPS_TIMEOUT_EVENT); 1597 } 1598 1599 /** 1600 * Broadcast the ANQP done event to all the handlers registered for this event. 1601 * 1602 * @param iface Name of iface on which this occurred. 1603 * @param anqpEvent ANQP result retrieved. 1604 */ 1605 public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) { 1606 sendMessage(iface, ANQP_DONE_EVENT, anqpEvent); 1607 } 1608 1609 /** 1610 * Broadcast the Icon done event to all the handlers registered for this event. 1611 * 1612 * @param iface Name of iface on which this occurred. 1613 * @param iconEvent Instance of IconEvent containing the icon data retrieved. 1614 */ 1615 public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) { 1616 sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent); 1617 } 1618 1619 /** 1620 * Broadcast the WNM event to all the handlers registered for this event. 1621 * 1622 * @param iface Name of iface on which this occurred. 1623 * @param wnmData Instance of WnmData containing the event data. 1624 */ 1625 public void broadcastWnmEvent(String iface, WnmData wnmData) { 1626 sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData); 1627 } 1628} 1629