WifiMonitor.java revision 446db2d5457456743e4476029e14d7c3bb9f5bcc
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.WifiManager; 22import android.net.wifi.WifiSsid; 23import android.net.wifi.p2p.WifiP2pConfig; 24import android.net.wifi.p2p.WifiP2pDevice; 25import android.net.wifi.p2p.WifiP2pGroup; 26import android.net.wifi.p2p.WifiP2pProvDiscEvent; 27import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 28import android.os.Message; 29import android.os.SystemClock; 30import android.util.Log; 31 32import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus; 33 34import com.android.internal.util.Protocol; 35import com.android.internal.util.StateMachine; 36 37import java.util.HashMap; 38import java.util.List; 39import java.util.regex.Matcher; 40import java.util.regex.Pattern; 41 42/** 43 * Listens for events from the wpa_supplicant server, and passes them on 44 * to the {@link StateMachine} for handling. Runs in its own thread. 45 * 46 * @hide 47 */ 48public class WifiMonitor { 49 50 private static final boolean DBG = false; 51 private static final String TAG = "WifiMonitor"; 52 53 /** Events we receive from the supplicant daemon */ 54 55 private static final int CONNECTED = 1; 56 private static final int DISCONNECTED = 2; 57 private static final int STATE_CHANGE = 3; 58 private static final int SCAN_RESULTS = 4; 59 private static final int LINK_SPEED = 5; 60 private static final int TERMINATING = 6; 61 private static final int DRIVER_STATE = 7; 62 private static final int EAP_FAILURE = 8; 63 private static final int ASSOC_REJECT = 9; 64 private static final int SSID_TEMP_DISABLE = 10; 65 private static final int SSID_REENABLE = 11; 66 private static final int UNKNOWN = 12; 67 68 /** All events coming from the supplicant start with this prefix */ 69 private static final String EVENT_PREFIX_STR = "CTRL-EVENT-"; 70 private static final int EVENT_PREFIX_LEN_STR = EVENT_PREFIX_STR.length(); 71 72 /** All WPA events coming from the supplicant start with this prefix */ 73 private static final String WPA_EVENT_PREFIX_STR = "WPA:"; 74 private static final String PASSWORD_MAY_BE_INCORRECT_STR = 75 "pre-shared key may be incorrect"; 76 77 /* WPS events */ 78 private static final String WPS_SUCCESS_STR = "WPS-SUCCESS"; 79 80 /* Format: WPS-FAIL msg=%d [config_error=%d] [reason=%d (%s)] */ 81 private static final String WPS_FAIL_STR = "WPS-FAIL"; 82 private static final String WPS_FAIL_PATTERN = 83 "WPS-FAIL msg=\\d+(?: config_error=(\\d+))?(?: reason=(\\d+))?"; 84 85 /* config error code values for config_error=%d */ 86 private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12; 87 private static final int CONFIG_AUTH_FAILURE = 18; 88 89 /* reason code values for reason=%d */ 90 private static final int REASON_TKIP_ONLY_PROHIBITED = 1; 91 private static final int REASON_WEP_PROHIBITED = 2; 92 93 private static final String WPS_OVERLAP_STR = "WPS-OVERLAP-DETECTED"; 94 private static final String WPS_TIMEOUT_STR = "WPS-TIMEOUT"; 95 96 /* Hotspot 2.0 ANQP query events */ 97 private static final String GAS_QUERY_PREFIX_STR = "GAS-QUERY-"; 98 private static final String GAS_QUERY_START_STR = "GAS-QUERY-START"; 99 private static final String GAS_QUERY_DONE_STR = "GAS-QUERY-DONE"; 100 private static final String RX_HS20_ANQP_ICON_STR = "RX-HS20-ANQP-ICON"; 101 private static final int RX_HS20_ANQP_ICON_STR_LEN = RX_HS20_ANQP_ICON_STR.length(); 102 103 /** 104 * Names of events from wpa_supplicant (minus the prefix). In the 105 * format descriptions, * "<code>x</code>" 106 * designates a dynamic value that needs to be parsed out from the event 107 * string 108 */ 109 /** 110 * <pre> 111 * CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed 112 * </pre> 113 * <code>xx:xx:xx:xx:xx:xx</code> is the BSSID of the associated access point 114 */ 115 private static final String CONNECTED_STR = "CONNECTED"; 116 /** 117 * <pre> 118 * CTRL-EVENT-DISCONNECTED - Disconnect event - remove keys 119 * </pre> 120 */ 121 private static final String DISCONNECTED_STR = "DISCONNECTED"; 122 /** 123 * <pre> 124 * CTRL-EVENT-STATE-CHANGE x 125 * </pre> 126 * <code>x</code> is the numerical value of the new state. 127 */ 128 private static final String STATE_CHANGE_STR = "STATE-CHANGE"; 129 /** 130 * <pre> 131 * CTRL-EVENT-SCAN-RESULTS ready 132 * </pre> 133 */ 134 private static final String SCAN_RESULTS_STR = "SCAN-RESULTS"; 135 136 /** 137 * <pre> 138 * CTRL-EVENT-LINK-SPEED x Mb/s 139 * </pre> 140 * {@code x} is the link speed in Mb/sec. 141 */ 142 private static final String LINK_SPEED_STR = "LINK-SPEED"; 143 /** 144 * <pre> 145 * CTRL-EVENT-TERMINATING - signal x 146 * </pre> 147 * <code>x</code> is the signal that caused termination. 148 */ 149 private static final String TERMINATING_STR = "TERMINATING"; 150 /** 151 * <pre> 152 * CTRL-EVENT-DRIVER-STATE state 153 * </pre> 154 * <code>state</code> can be HANGED 155 */ 156 private static final String DRIVER_STATE_STR = "DRIVER-STATE"; 157 /** 158 * <pre> 159 * CTRL-EVENT-EAP-FAILURE EAP authentication failed 160 * </pre> 161 */ 162 private static final String EAP_FAILURE_STR = "EAP-FAILURE"; 163 164 /** 165 * This indicates an authentication failure on EAP FAILURE event 166 */ 167 private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed"; 168 169 /** 170 * This indicates an assoc reject event 171 */ 172 private static final String ASSOC_REJECT_STR = "ASSOC-REJECT"; 173 174 /** 175 * This indicates auth or association failure bad enough so as network got disabled 176 * - WPA_PSK auth failure suspecting shared key mismatch 177 * - failed multiple Associations 178 */ 179 private static final String TEMP_DISABLED_STR = "SSID-TEMP-DISABLED"; 180 181 /** 182 * This indicates a previously disabled SSID was reenabled by supplicant 183 */ 184 private static final String REENABLED_STR = "SSID-REENABLED"; 185 186 187 /** 188 * Regex pattern for extracting an Ethernet-style MAC address from a string. 189 * Matches a strings like the following:<pre> 190 * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]</pre> 191 */ 192 private static Pattern mConnectedEventPattern = 193 Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) "); 194 195 /** P2P events */ 196 private static final String P2P_EVENT_PREFIX_STR = "P2P"; 197 198 /* P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 pri_dev_type=1-0050F204-1 199 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ 200 private static final String P2P_DEVICE_FOUND_STR = "P2P-DEVICE-FOUND"; 201 202 /* P2P-DEVICE-LOST p2p_dev_addr=42:fc:89:e1:e2:27 */ 203 private static final String P2P_DEVICE_LOST_STR = "P2P-DEVICE-LOST"; 204 205 /* P2P-FIND-STOPPED */ 206 private static final String P2P_FIND_STOPPED_STR = "P2P-FIND-STOPPED"; 207 208 /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */ 209 private static final String P2P_GO_NEG_REQUEST_STR = "P2P-GO-NEG-REQUEST"; 210 211 private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS"; 212 213 /* P2P-GO-NEG-FAILURE status=x */ 214 private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE"; 215 216 private static final String P2P_GROUP_FORMATION_SUCCESS_STR = 217 "P2P-GROUP-FORMATION-SUCCESS"; 218 219 private static final String P2P_GROUP_FORMATION_FAILURE_STR = 220 "P2P-GROUP-FORMATION-FAILURE"; 221 222 /* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437 223 [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"] 224 go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT] */ 225 private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED"; 226 227 /* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */ 228 private static final String P2P_GROUP_REMOVED_STR = "P2P-GROUP-REMOVED"; 229 230 /* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13 231 bssid=fa:7b:7a:42:82:13 unknown-network */ 232 private static final String P2P_INVITATION_RECEIVED_STR = "P2P-INVITATION-RECEIVED"; 233 234 /* P2P-INVITATION-RESULT status=1 */ 235 private static final String P2P_INVITATION_RESULT_STR = "P2P-INVITATION-RESULT"; 236 237 /* P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 238 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 239 group_capab=0x0 */ 240 private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ"; 241 242 /* P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 */ 243 private static final String P2P_PROV_DISC_PBC_RSP_STR = "P2P-PROV-DISC-PBC-RESP"; 244 245 /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 246 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 247 group_capab=0x0 */ 248 private static final String P2P_PROV_DISC_ENTER_PIN_STR = "P2P-PROV-DISC-ENTER-PIN"; 249 /* P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 250 pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 251 group_capab=0x0 */ 252 private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN"; 253 /* P2P-PROV-DISC-FAILURE p2p_dev_addr=42:fc:89:e1:e2:27 */ 254 private static final String P2P_PROV_DISC_FAILURE_STR = "P2P-PROV-DISC-FAILURE"; 255 256 /* 257 * Protocol format is as follows.<br> 258 * See the Table.62 in the WiFi Direct specification for the detail. 259 * ______________________________________________________________ 260 * | Length(2byte) | Type(1byte) | TransId(1byte)}| 261 * ______________________________________________________________ 262 * | status(1byte) | vendor specific(variable) | 263 * 264 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300000101 265 * length=3, service type=0(ALL Service), transaction id=1, 266 * status=1(service protocol type not available)<br> 267 * 268 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300020201 269 * length=3, service type=2(UPnP), transaction id=2, 270 * status=1(service protocol type not available) 271 * 272 * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 990002030010757569643a3131323 273 * 2646534652d383537342d353961622d393332322d3333333435363738393034343a3 274 * a75726e3a736368656d61732d75706e702d6f72673a736572766963653a436f6e746 275 * 56e744469726563746f72793a322c757569643a36383539646564652d383537342d3 276 * 53961622d393333322d3132333435363738393031323a3a75706e703a726f6f74646 277 * 576696365 278 * length=153,type=2(UPnP),transaction id=3,status=0 279 * 280 * UPnP Protocol format is as follows. 281 * ______________________________________________________ 282 * | Version (1) | USN (Variable) | 283 * 284 * version=0x10(UPnP1.0) data=usn:uuid:1122de4e-8574-59ab-9322-33345678 285 * 9044::urn:schemas-upnp-org:service:ContentDirectory:2,usn:uuid:6859d 286 * ede-8574-59ab-9332-123456789012::upnp:rootdevice 287 * 288 * P2P-SERV-DISC-RESP 58:17:0c:bc:dd:ca 21 1900010200045f6970 289 * 70c00c000c01094d795072696e746572c027 290 * length=25, type=1(Bonjour),transaction id=2,status=0 291 * 292 * Bonjour Protocol format is as follows. 293 * __________________________________________________________ 294 * |DNS Name(Variable)|DNS Type(1)|Version(1)|RDATA(Variable)| 295 * 296 * DNS Name=_ipp._tcp.local.,DNS type=12(PTR), Version=1, 297 * RDATA=MyPrinter._ipp._tcp.local. 298 * 299 */ 300 private static final String P2P_SERV_DISC_RESP_STR = "P2P-SERV-DISC-RESP"; 301 302 private static final String HOST_AP_EVENT_PREFIX_STR = "AP"; 303 /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */ 304 private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED"; 305 /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ 306 private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; 307 308 /* Supplicant events reported to a state machine */ 309 private static final int BASE = Protocol.BASE_WIFI_MONITOR; 310 311 /* Connection to supplicant established */ 312 public static final int SUP_CONNECTION_EVENT = BASE + 1; 313 /* Connection to supplicant lost */ 314 public static final int SUP_DISCONNECTION_EVENT = BASE + 2; 315 /* Network connection completed */ 316 public static final int NETWORK_CONNECTION_EVENT = BASE + 3; 317 /* Network disconnection completed */ 318 public static final int NETWORK_DISCONNECTION_EVENT = BASE + 4; 319 /* Scan results are available */ 320 public static final int SCAN_RESULTS_EVENT = BASE + 5; 321 /* Supplicate state changed */ 322 public static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 6; 323 /* Password failure and EAP authentication failure */ 324 public static final int AUTHENTICATION_FAILURE_EVENT = BASE + 7; 325 /* WPS success detected */ 326 public static final int WPS_SUCCESS_EVENT = BASE + 8; 327 /* WPS failure detected */ 328 public static final int WPS_FAIL_EVENT = BASE + 9; 329 /* WPS overlap detected */ 330 public static final int WPS_OVERLAP_EVENT = BASE + 10; 331 /* WPS timeout detected */ 332 public static final int WPS_TIMEOUT_EVENT = BASE + 11; 333 /* Driver was hung */ 334 public static final int DRIVER_HUNG_EVENT = BASE + 12; 335 /* SSID was disabled due to auth failure or excessive 336 * connection failures */ 337 public static final int SSID_TEMP_DISABLED = BASE + 13; 338 /* SSID was reenabled */ 339 public static final int SSID_REENABLED = BASE + 14; 340 341 /* P2P events */ 342 public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21; 343 public static final int P2P_DEVICE_LOST_EVENT = BASE + 22; 344 public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23; 345 public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25; 346 public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26; 347 public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27; 348 public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28; 349 public static final int P2P_GROUP_STARTED_EVENT = BASE + 29; 350 public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30; 351 public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; 352 public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; 353 public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; 354 public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34; 355 public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35; 356 public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36; 357 public static final int P2P_FIND_STOPPED_EVENT = BASE + 37; 358 public static final int P2P_SERV_DISC_RESP_EVENT = BASE + 38; 359 public static final int P2P_PROV_DISC_FAILURE_EVENT = BASE + 39; 360 361 /* hostap events */ 362 public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; 363 public static final int AP_STA_CONNECTED_EVENT = BASE + 42; 364 365 /* Indicates assoc reject event */ 366 public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43; 367 368 /* hotspot 2.0 ANQP events */ 369 public static final int GAS_QUERY_START_EVENT = BASE + 51; 370 public static final int GAS_QUERY_DONE_EVENT = BASE + 52; 371 public static final int RX_HS20_ANQP_ICON_EVENT = BASE + 53; 372 373 /** 374 * This indicates a read error on the monitor socket conenction 375 */ 376 private static final String WPA_RECV_ERROR_STR = "recv error"; 377 378 /** 379 * Max errors before we close supplicant connection 380 */ 381 private static final int MAX_RECV_ERRORS = 10; 382 383 private final String mInterfaceName; 384 private final WifiNative mWifiNative; 385 private final StateMachine mStateMachine; 386 private StateMachine mStateMachine2; 387 private boolean mMonitoring; 388 389 // This is a global counter, since it's not monitor specific. However, the existing 390 // implementation forwards all "global" control events like CTRL-EVENT-TERMINATING 391 // to the p2p0 monitor. Is that expected ? It seems a bit surprising. 392 // 393 // TODO: If the p2p0 monitor isn't registered, the behaviour is even more surprising. 394 // The event will be dispatched to all monitors, and each of them will end up incrementing 395 // it in their dispatchXXX method. If we have 5 registered monitors (say), 2 consecutive 396 // recv errors will cause us to disconnect from the supplicant (instead of the intended 10). 397 // 398 // This variable is always accessed and modified under a WifiMonitorSingleton lock. 399 private static int sRecvErrors; 400 401 public WifiMonitor(StateMachine stateMachine, WifiNative wifiNative) { 402 if (DBG) Log.d(TAG, "Creating WifiMonitor"); 403 mWifiNative = wifiNative; 404 mInterfaceName = wifiNative.mInterfaceName; 405 mStateMachine = stateMachine; 406 mStateMachine2 = null; 407 mMonitoring = false; 408 409 WifiMonitorSingleton.sInstance.registerInterfaceMonitor(mInterfaceName, this); 410 } 411 412 // TODO: temporary hack, should be handle by supplicant manager (new component in future) 413 public void setStateMachine2(StateMachine stateMachine) { 414 mStateMachine2 = stateMachine; 415 } 416 417 public void startMonitoring() { 418 WifiMonitorSingleton.sInstance.startMonitoring(mInterfaceName); 419 } 420 421 public void stopMonitoring() { 422 WifiMonitorSingleton.sInstance.stopMonitoring(mInterfaceName); 423 } 424 425 public void stopSupplicant() { 426 WifiMonitorSingleton.sInstance.stopSupplicant(); 427 } 428 429 public void killSupplicant(boolean p2pSupported) { 430 WifiMonitorSingleton.sInstance.killSupplicant(p2pSupported); 431 } 432 433 private static class WifiMonitorSingleton { 434 private static final WifiMonitorSingleton sInstance = new WifiMonitorSingleton(); 435 436 private final HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>(); 437 private boolean mConnected = false; 438 private WifiNative mWifiNative; 439 440 private WifiMonitorSingleton() { 441 } 442 443 public synchronized void startMonitoring(String iface) { 444 WifiMonitor m = mIfaceMap.get(iface); 445 if (m == null) { 446 Log.e(TAG, "startMonitor called with unknown iface=" + iface); 447 return; 448 } 449 450 Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected); 451 452 if (mConnected) { 453 m.mMonitoring = true; 454 m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); 455 } else { 456 if (DBG) Log.d(TAG, "connecting to supplicant"); 457 int connectTries = 0; 458 while (true) { 459 if (mWifiNative.connectToSupplicant()) { 460 m.mMonitoring = true; 461 m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); 462 new MonitorThread(mWifiNative, this).start(); 463 mConnected = true; 464 break; 465 } 466 if (connectTries++ < 5) { 467 try { 468 Thread.sleep(1000); 469 } catch (InterruptedException ignore) { 470 } 471 } else { 472 mIfaceMap.remove(iface); 473 m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); 474 Log.e(TAG, "startMonitoring(" + iface + ") failed!"); 475 break; 476 } 477 } 478 } 479 } 480 481 public synchronized void stopMonitoring(String iface) { 482 WifiMonitor m = mIfaceMap.get(iface); 483 if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mStateMachine); 484 m.mMonitoring = false; 485 m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); 486 } 487 488 public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) { 489 if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mStateMachine + ")"); 490 mIfaceMap.put(iface, m); 491 if (mWifiNative == null) { 492 mWifiNative = m.mWifiNative; 493 } 494 } 495 496 public synchronized void unregisterInterfaceMonitor(String iface) { 497 // REVIEW: When should we call this? If this isn't called, then WifiMonitor 498 // objects will remain in the mIfaceMap; and won't ever get deleted 499 500 WifiMonitor m = mIfaceMap.remove(iface); 501 if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mStateMachine + ")"); 502 } 503 504 public synchronized void stopSupplicant() { 505 mWifiNative.stopSupplicant(); 506 } 507 508 public synchronized void killSupplicant(boolean p2pSupported) { 509 WifiNative.killSupplicant(p2pSupported); 510 mConnected = false; 511 for (WifiMonitor m : mIfaceMap.values()) { 512 m.mMonitoring = false; 513 } 514 } 515 516 private synchronized boolean dispatchEvent(String eventStr) { 517 String iface; 518 if (eventStr.startsWith("IFNAME=")) { 519 int space = eventStr.indexOf(' '); 520 if (space != -1) { 521 iface = eventStr.substring(7, space); 522 if (!mIfaceMap.containsKey(iface) && iface.startsWith("p2p-")) { 523 // p2p interfaces are created dynamically, but we have 524 // only one P2p state machine monitoring all of them; look 525 // for it explicitly, and send messages there .. 526 iface = "p2p0"; 527 } 528 eventStr = eventStr.substring(space + 1); 529 } else { 530 // No point dispatching this event to any interface, the dispatched 531 // event string will begin with "IFNAME=" which dispatchEvent can't really 532 // do anything about. 533 Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr); 534 return false; 535 } 536 } else { 537 // events without prefix belong to p2p0 monitor 538 iface = "p2p0"; 539 } 540 541 if (DBG) Log.d(TAG, "Dispatching event to interface: " + iface); 542 543 WifiMonitor m = mIfaceMap.get(iface); 544 if (m != null) { 545 if (m.mMonitoring) { 546 if (m.dispatchEvent(eventStr)) { 547 mConnected = false; 548 return true; 549 } 550 551 return false; 552 } else { 553 if (DBG) Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); 554 return false; 555 } 556 } else { 557 if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface"); 558 boolean done = false; 559 for (WifiMonitor monitor : mIfaceMap.values()) { 560 if (monitor.mMonitoring && monitor.dispatchEvent(eventStr)) { 561 done = true; 562 } 563 } 564 565 if (done) { 566 mConnected = false; 567 } 568 569 return done; 570 } 571 } 572 } 573 574 private static class MonitorThread extends Thread { 575 private final WifiNative mWifiNative; 576 private final WifiMonitorSingleton mWifiMonitorSingleton; 577 578 public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) { 579 super("WifiMonitor"); 580 mWifiNative = wifiNative; 581 mWifiMonitorSingleton = wifiMonitorSingleton; 582 } 583 584 public void run() { 585 //noinspection InfiniteLoopStatement 586 for (;;) { 587 String eventStr = mWifiNative.waitForEvent(); 588 589 // Skip logging the common but mostly uninteresting scan-results event 590 if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { 591 Log.d(TAG, "Event [" + eventStr + "]"); 592 } 593 594 if (mWifiMonitorSingleton.dispatchEvent(eventStr)) { 595 if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); 596 break; 597 } 598 } 599 } 600 } 601 602 private void logDbg(String debug) { 603 long now = SystemClock.elapsedRealtimeNanos(); 604 String ts = String.format("[%,d us] ", now/1000); 605 Log.e(TAG, ts+debug+ " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 606 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 607 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 608 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 609 610 } 611 612 /* @return true if the event was supplicant disconnection */ 613 private boolean dispatchEvent(String eventStr) { 614 615 if (DBG) logDbg("WifiMonitor dispatchEvent " + eventStr); 616 617 if (!eventStr.startsWith(EVENT_PREFIX_STR)) { 618 if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && 619 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { 620 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); 621 } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { 622 mStateMachine.sendMessage(WPS_SUCCESS_EVENT); 623 } else if (eventStr.startsWith(WPS_FAIL_STR)) { 624 handleWpsFailEvent(eventStr); 625 } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { 626 mStateMachine.sendMessage(WPS_OVERLAP_EVENT); 627 } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { 628 mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); 629 } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { 630 handleP2pEvents(eventStr); 631 } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { 632 handleHostApEvents(eventStr); 633 } else if (eventStr.startsWith(GAS_QUERY_PREFIX_STR)) { 634 handleGasQueryEvents(eventStr); 635 } else if (eventStr.startsWith(RX_HS20_ANQP_ICON_STR)) { 636 if (mStateMachine2 != null) 637 mStateMachine2.sendMessage(RX_HS20_ANQP_ICON_EVENT, 638 eventStr.substring(RX_HS20_ANQP_ICON_STR_LEN + 1)); 639 } 640 else { 641 if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); 642 } 643 return false; 644 } 645 646 String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); 647 int nameEnd = eventName.indexOf(' '); 648 if (nameEnd != -1) 649 eventName = eventName.substring(0, nameEnd); 650 if (eventName.length() == 0) { 651 if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name"); 652 return false; 653 } 654 /* 655 * Map event name into event enum 656 */ 657 int event; 658 if (eventName.equals(CONNECTED_STR)) 659 event = CONNECTED; 660 else if (eventName.equals(DISCONNECTED_STR)) 661 event = DISCONNECTED; 662 else if (eventName.equals(STATE_CHANGE_STR)) 663 event = STATE_CHANGE; 664 else if (eventName.equals(SCAN_RESULTS_STR)) 665 event = SCAN_RESULTS; 666 else if (eventName.equals(LINK_SPEED_STR)) 667 event = LINK_SPEED; 668 else if (eventName.equals(TERMINATING_STR)) 669 event = TERMINATING; 670 else if (eventName.equals(DRIVER_STATE_STR)) 671 event = DRIVER_STATE; 672 else if (eventName.equals(EAP_FAILURE_STR)) 673 event = EAP_FAILURE; 674 else if (eventName.equals(ASSOC_REJECT_STR)) 675 event = ASSOC_REJECT; 676 else if (eventName.equals(TEMP_DISABLED_STR)) { 677 event = SSID_TEMP_DISABLE; 678 } else if (eventName.equals(REENABLED_STR)) { 679 event = SSID_REENABLE; 680 } 681 else 682 event = UNKNOWN; 683 684 String eventData = eventStr; 685 if (event == DRIVER_STATE || event == LINK_SPEED) 686 eventData = eventData.split(" ")[1]; 687 else if (event == STATE_CHANGE || event == EAP_FAILURE) { 688 int ind = eventStr.indexOf(" "); 689 if (ind != -1) { 690 eventData = eventStr.substring(ind + 1); 691 } 692 } else { 693 int ind = eventStr.indexOf(" - "); 694 if (ind != -1) { 695 eventData = eventStr.substring(ind + 3); 696 } 697 } 698 699 if ((event == SSID_TEMP_DISABLE)||(event == SSID_REENABLE)) { 700 String substr = null; 701 int netId = -1; 702 int ind = eventStr.indexOf(" "); 703 if (ind != -1) { 704 substr = eventStr.substring(ind + 1); 705 } 706 if (substr != null) { 707 String status[] = substr.split(" "); 708 for (String key : status) { 709 if (key.regionMatches(0, "id=", 0, 3)) { 710 int idx = 3; 711 netId = 0; 712 while (idx < key.length()) { 713 char c = key.charAt(idx); 714 if ((c >= 0x30) && (c <= 0x39)) { 715 netId *= 10; 716 netId += c - 0x30; 717 idx++; 718 } else { 719 break; 720 } 721 } 722 } 723 } 724 } 725 mStateMachine.sendMessage((event == SSID_TEMP_DISABLE)? 726 SSID_TEMP_DISABLED:SSID_REENABLED, netId, 0, substr); 727 } else if (event == STATE_CHANGE) { 728 handleSupplicantStateChange(eventData); 729 } else if (event == DRIVER_STATE) { 730 handleDriverEvent(eventData); 731 } else if (event == TERMINATING) { 732 /** 733 * Close the supplicant connection if we see 734 * too many recv errors 735 */ 736 if (eventData.startsWith(WPA_RECV_ERROR_STR)) { 737 if (++sRecvErrors > MAX_RECV_ERRORS) { 738 if (DBG) { 739 Log.d(TAG, "too many recv errors, closing connection"); 740 } 741 } else { 742 return false; 743 } 744 } 745 746 // notify and exit 747 mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); 748 return true; 749 } else if (event == EAP_FAILURE) { 750 if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { 751 logDbg("WifiMonitor send auth failure (EAP_AUTH_FAILURE) "); 752 mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); 753 } 754 } else if (event == ASSOC_REJECT) { 755 mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); 756 } else { 757 handleEvent(event, eventData); 758 } 759 sRecvErrors = 0; 760 return false; 761 } 762 763 private void handleDriverEvent(String state) { 764 if (state == null) { 765 return; 766 } 767 if (state.equals("HANGED")) { 768 mStateMachine.sendMessage(DRIVER_HUNG_EVENT); 769 } 770 } 771 772 /** 773 * Handle all supplicant events except STATE-CHANGE 774 * @param event the event type 775 * @param remainder the rest of the string following the 776 * event name and " — " 777 */ 778 void handleEvent(int event, String remainder) { 779 switch (event) { 780 case DISCONNECTED: 781 handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder); 782 break; 783 784 case CONNECTED: 785 handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder); 786 break; 787 788 case SCAN_RESULTS: 789 mStateMachine.sendMessage(SCAN_RESULTS_EVENT); 790 break; 791 792 case UNKNOWN: 793 break; 794 } 795 } 796 797 private void handleWpsFailEvent(String dataString) { 798 final Pattern p = Pattern.compile(WPS_FAIL_PATTERN); 799 Matcher match = p.matcher(dataString); 800 if (match.find()) { 801 String cfgErr = match.group(1); 802 String reason = match.group(2); 803 804 if (reason != null) { 805 switch(Integer.parseInt(reason)) { 806 case REASON_TKIP_ONLY_PROHIBITED: 807 mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, 808 WifiManager.WPS_TKIP_ONLY_PROHIBITED, 0)); 809 return; 810 case REASON_WEP_PROHIBITED: 811 mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, 812 WifiManager.WPS_WEP_PROHIBITED, 0)); 813 return; 814 } 815 } 816 if (cfgErr != null) { 817 switch(Integer.parseInt(cfgErr)) { 818 case CONFIG_AUTH_FAILURE: 819 mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, 820 WifiManager.WPS_AUTH_FAILURE, 0)); 821 return; 822 case CONFIG_MULTIPLE_PBC_DETECTED: 823 mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, 824 WifiManager.WPS_OVERLAP_ERROR, 0)); 825 return; 826 } 827 } 828 } 829 //For all other errors, return a generic internal error 830 mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, 831 WifiManager.ERROR, 0)); 832 } 833 834 /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */ 835 private P2pStatus p2pError(String dataString) { 836 P2pStatus err = P2pStatus.UNKNOWN; 837 String[] tokens = dataString.split(" "); 838 if (tokens.length < 2) return err; 839 String[] nameValue = tokens[1].split("="); 840 if (nameValue.length != 2) return err; 841 842 /* Handle the special case of reason=FREQ+CONFLICT */ 843 if (nameValue[1].equals("FREQ_CONFLICT")) { 844 return P2pStatus.NO_COMMON_CHANNEL; 845 } 846 try { 847 err = P2pStatus.valueOf(Integer.parseInt(nameValue[1])); 848 } catch (NumberFormatException e) { 849 e.printStackTrace(); 850 } 851 return err; 852 } 853 854 /** 855 * Handle p2p events 856 */ 857 private void handleP2pEvents(String dataString) { 858 if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { 859 mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString)); 860 } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { 861 mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString)); 862 } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) { 863 mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT); 864 } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { 865 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT, 866 new WifiP2pConfig(dataString)); 867 } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { 868 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT); 869 } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { 870 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString)); 871 } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { 872 mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT); 873 } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { 874 mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString)); 875 } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { 876 mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString)); 877 } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { 878 mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString)); 879 } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { 880 mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT, 881 new WifiP2pGroup(dataString)); 882 } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { 883 mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString)); 884 } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { 885 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, 886 new WifiP2pProvDiscEvent(dataString)); 887 } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { 888 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT, 889 new WifiP2pProvDiscEvent(dataString)); 890 } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { 891 mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, 892 new WifiP2pProvDiscEvent(dataString)); 893 } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { 894 mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT, 895 new WifiP2pProvDiscEvent(dataString)); 896 } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) { 897 mStateMachine.sendMessage(P2P_PROV_DISC_FAILURE_EVENT); 898 } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) { 899 List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString); 900 if (list != null) { 901 mStateMachine.sendMessage(P2P_SERV_DISC_RESP_EVENT, list); 902 } else { 903 Log.e(TAG, "Null service resp " + dataString); 904 } 905 } 906 } 907 908 /** 909 * Handle hostap events 910 */ 911 private void handleHostApEvents(String dataString) { 912 String[] tokens = dataString.split(" "); 913 /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ 914 if (tokens[0].equals(AP_STA_CONNECTED_STR)) { 915 mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString)); 916 /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ 917 } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { 918 mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString)); 919 } 920 } 921 922 /** 923 * Handle ANQP events 924 */ 925 private void handleGasQueryEvents(String dataString) { 926 // hs20 927 if (mStateMachine2 == null) return; 928 if (dataString.startsWith(GAS_QUERY_START_STR)) { 929 mStateMachine2.sendMessage(GAS_QUERY_START_EVENT); 930 } else if (dataString.startsWith(GAS_QUERY_DONE_STR)) { 931 String[] dataTokens = dataString.split(" "); 932 String bssid = null; 933 int success = 0; 934 for (String token : dataTokens) { 935 String[] nameValue = token.split("="); 936 if (nameValue.length != 2) { 937 continue; 938 } 939 if (nameValue[0].equals("addr")) { 940 bssid = nameValue[1]; 941 continue; 942 } 943 if (nameValue[0].equals("result")) { 944 success = nameValue[1].equals("SUCCESS") ? 1 : 0; 945 continue; 946 } 947 } 948 mStateMachine2.sendMessage(GAS_QUERY_DONE_EVENT, success, 0, bssid); 949 } else { 950 if (DBG) Log.d(TAG, "Unknown handled GAS query event"); 951 } 952 } 953 954 /** 955 * Handle the supplicant STATE-CHANGE event 956 * @param dataString New supplicant state string in the format: 957 * id=network-id state=new-state 958 */ 959 private void handleSupplicantStateChange(String dataString) { 960 WifiSsid wifiSsid = null; 961 int index = dataString.lastIndexOf("SSID="); 962 if (index != -1) { 963 wifiSsid = WifiSsid.createFromAsciiEncoded( 964 dataString.substring(index + 5)); 965 } 966 String[] dataTokens = dataString.split(" "); 967 968 String BSSID = null; 969 int networkId = -1; 970 int newState = -1; 971 for (String token : dataTokens) { 972 String[] nameValue = token.split("="); 973 if (nameValue.length != 2) { 974 continue; 975 } 976 977 if (nameValue[0].equals("BSSID")) { 978 BSSID = nameValue[1]; 979 continue; 980 } 981 982 int value; 983 try { 984 value = Integer.parseInt(nameValue[1]); 985 } catch (NumberFormatException e) { 986 continue; 987 } 988 989 if (nameValue[0].equals("id")) { 990 networkId = value; 991 } else if (nameValue[0].equals("state")) { 992 newState = value; 993 } 994 } 995 996 if (newState == -1) return; 997 998 SupplicantState newSupplicantState = SupplicantState.INVALID; 999 for (SupplicantState state : SupplicantState.values()) { 1000 if (state.ordinal() == newState) { 1001 newSupplicantState = state; 1002 break; 1003 } 1004 } 1005 if (newSupplicantState == SupplicantState.INVALID) { 1006 Log.w(TAG, "Invalid supplicant state: " + newState); 1007 } 1008 notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState); 1009 } 1010 1011 private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { 1012 String BSSID = null; 1013 int networkId = -1; 1014 if (newState == NetworkInfo.DetailedState.CONNECTED) { 1015 Matcher match = mConnectedEventPattern.matcher(data); 1016 if (!match.find()) { 1017 if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); 1018 } else { 1019 BSSID = match.group(1); 1020 try { 1021 networkId = Integer.parseInt(match.group(2)); 1022 } catch (NumberFormatException e) { 1023 networkId = -1; 1024 } 1025 } 1026 notifyNetworkStateChange(newState, BSSID, networkId); 1027 } 1028 } 1029 1030 /** 1031 * Send the state machine a notification that the state of Wifi connectivity 1032 * has changed. 1033 * @param newState the new network state 1034 * @param BSSID when the new state is {@link NetworkInfo.DetailedState#CONNECTED}, 1035 * this is the MAC address of the access point. Otherwise, it 1036 * is {@code null}. 1037 * @param netId the configured network on which the state change occurred 1038 */ 1039 void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { 1040 if (newState == NetworkInfo.DetailedState.CONNECTED) { 1041 Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, 1042 netId, 0, BSSID); 1043 mStateMachine.sendMessage(m); 1044 } else { 1045 Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, 1046 netId, 0, BSSID); 1047 mStateMachine.sendMessage(m); 1048 } 1049 } 1050 1051 /** 1052 * Send the state machine a notification that the state of the supplicant 1053 * has changed. 1054 * @param networkId the configured network on which the state change occurred 1055 * @param wifiSsid network name 1056 * @param BSSID network address 1057 * @param newState the new {@code SupplicantState} 1058 */ 1059 void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, 1060 SupplicantState newState) { 1061 mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, 1062 new StateChangeResult(networkId, wifiSsid, BSSID, newState))); 1063 } 1064} 1065