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