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