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