WifiMonitor.java revision 70a9b25ee5d051660b8aeb15ffa97d36a181741d
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 stopSupplicant() {
644        mWifiNative.stopSupplicant();
645    }
646
647    public synchronized void stopAllMonitoring() {
648        mConnected = false;
649        setMonitoringNone();
650    }
651
652
653    /**
654     * Similar functions to Handler#sendMessage that send the message to the registered handler
655     * for the given interface and message what.
656     * All of these should be called with the WifiMonitor class lock
657     */
658    private void sendMessage(String iface, int what) {
659        sendMessage(iface, Message.obtain(null, what));
660    }
661
662    private void sendMessage(String iface, int what, Object obj) {
663        sendMessage(iface, Message.obtain(null, what, obj));
664    }
665
666    private void sendMessage(String iface, int what, int arg1) {
667        sendMessage(iface, Message.obtain(null, what, arg1, 0));
668    }
669
670    private void sendMessage(String iface, int what, int arg1, int arg2) {
671        sendMessage(iface, Message.obtain(null, what, arg1, arg2));
672    }
673
674    private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
675        sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
676    }
677
678    private void sendMessage(String iface, Message message) {
679        SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
680        if (iface != null && ifaceHandlers != null) {
681            if (isMonitoring(iface)) {
682                boolean firstHandler = true;
683                Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
684                if (ifaceWhatHandlers != null) {
685                    for (Handler handler : ifaceWhatHandlers) {
686                        if (firstHandler) {
687                            firstHandler = false;
688                            sendMessage(handler, message);
689                        }
690                        else {
691                            sendMessage(handler, Message.obtain(message));
692                        }
693                    }
694                }
695            } else {
696                if (mVerboseLoggingEnabled) {
697                    Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
698                }
699            }
700        } else {
701            if (mVerboseLoggingEnabled) {
702                Log.d(TAG, "Sending to all monitors because there's no matching iface");
703            }
704            boolean firstHandler = true;
705            for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
706                if (isMonitoring(entry.getKey())) {
707                    Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
708                    for (Handler handler : ifaceWhatHandlers) {
709                        if (firstHandler) {
710                            firstHandler = false;
711                            sendMessage(handler, message);
712                        }
713                        else {
714                            sendMessage(handler, Message.obtain(message));
715                        }
716                    }
717                }
718            }
719        }
720    }
721
722    private void sendMessage(Handler handler, Message message) {
723        if (handler != null) {
724            message.setTarget(handler);
725            message.sendToTarget();
726        }
727    }
728
729    private class MonitorThread extends Thread {
730        private final LocalLog mLocalLog;
731
732        public MonitorThread(LocalLog localLog) {
733            super("WifiMonitor");
734            mLocalLog = localLog;
735        }
736
737        public void run() {
738            if (mVerboseLoggingEnabled) {
739                Log.d(TAG, "MonitorThread start with mConnected=" + mConnected);
740            }
741            //noinspection InfiniteLoopStatement
742            for (;;) {
743                if (!mConnected) {
744                    if (mVerboseLoggingEnabled) {
745                        Log.d(TAG, "MonitorThread exit because mConnected is false");
746                    }
747                    break;
748                }
749                String eventStr = mWifiNative.waitForEvent();
750
751                // Skip logging the common but mostly uninteresting events
752                if (!eventStr.contains(BSS_ADDED_STR) && !eventStr.contains(BSS_REMOVED_STR)) {
753                    if (mVerboseLoggingEnabled) Log.d(TAG, "Event [" + eventStr + "]");
754                    mLocalLog.log("Event [" + eventStr + "]");
755                }
756
757                if (dispatchEvent(eventStr)) {
758                    if (mVerboseLoggingEnabled) {
759                        Log.d(TAG, "Disconnecting from the supplicant, no more events");
760                    }
761                    break;
762                }
763            }
764        }
765    }
766
767    private synchronized boolean dispatchEvent(String eventStr) {
768        String iface;
769        // IFNAME=wlan0 ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS
770        if (eventStr.startsWith("IFNAME=")) {
771            int space = eventStr.indexOf(' ');
772            if (space != -1) {
773                iface = eventStr.substring(7, space);
774                if (!mHandlerMap.containsKey(iface) && iface.startsWith("p2p-")) {
775                    // p2p interfaces are created dynamically, but we have
776                    // only one P2p state machine monitoring all of them; look
777                    // for it explicitly, and send messages there ..
778                    iface = "p2p0";
779                }
780                eventStr = eventStr.substring(space + 1);
781            } else {
782                // No point dispatching this event to any interface, the dispatched
783                // event string will begin with "IFNAME=" which dispatchEvent can't really
784                // do anything about.
785                Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr);
786                return false;
787            }
788        } else {
789            // events without prefix belong to p2p0 monitor
790            iface = "p2p0";
791        }
792
793        if (DBG) Log.d(TAG, "Dispatching event to interface: " + iface);
794
795        if (dispatchEvent(eventStr, iface)) {
796            mConnected = false;
797            return true;
798        }
799        return false;
800    }
801
802    private Map<String, Long> mLastConnectBSSIDs = new HashMap<String, Long>() {
803        public Long get(String iface) {
804            Long value = super.get(iface);
805            if (value != null) {
806                return value;
807            }
808            return 0L;
809        }
810    };
811
812    /* @return true if the event was supplicant disconnection */
813    private boolean dispatchEvent(String eventStr, String iface) {
814        if (mVerboseLoggingEnabled) {
815            // Dont log CTRL-EVENT-BSS-ADDED which are too verbose and not handled
816            if (eventStr != null && !eventStr.contains("CTRL-EVENT-BSS-ADDED")) {
817                Log.d(TAG, iface + " cnt=" + Integer.toString(eventLogCounter)
818                        + " dispatchEvent: " + eventStr);
819            }
820        }
821
822        if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
823            if (eventStr.startsWith(WPS_SUCCESS_STR)) {
824                broadcastWpsSuccessEvent(iface);
825            } else if (eventStr.startsWith(WPS_FAIL_STR)) {
826                handleWpsFailEvent(eventStr, iface);
827            } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
828                broadcastWpsOverlapEvent(iface);
829            } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
830                broadcastWpsTimeoutEvent(iface);
831            } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
832                handleP2pEvents(eventStr, iface);
833            } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
834                handleHostApEvents(eventStr, iface);
835            } else if (eventStr.startsWith(ANQP_DONE_STR)) {
836                try {
837                    handleAnqpResult(eventStr, iface);
838                }
839                catch (IllegalArgumentException iae) {
840                    Log.e(TAG, "Bad ANQP event string: '" + eventStr + "': " + iae);
841                }
842            } else if (eventStr.startsWith(HS20_ICON_STR)) {
843                try {
844                    handleIconResult(eventStr, iface);
845                }
846                catch (IllegalArgumentException iae) {
847                    Log.e(TAG, "Bad Icon event string: '" + eventStr + "': " + iae);
848                }
849            }
850            else if (eventStr.startsWith(HS20_SUB_REM_STR)) {
851                // Tack on the last connected BSSID so we have some idea what AP the WNM pertains to
852                handleWnmFrame(String.format("%012x %s",
853                                mLastConnectBSSIDs.get(iface), eventStr), iface);
854            } else if (eventStr.startsWith(HS20_DEAUTH_STR)) {
855                handleWnmFrame(String.format("%012x %s",
856                                mLastConnectBSSIDs.get(iface), eventStr), iface);
857            } else if (eventStr.startsWith(REQUEST_PREFIX_STR)) {
858                handleRequests(eventStr, iface);
859            } else if (eventStr.startsWith(TARGET_BSSID_STR)) {
860                handleTargetBSSIDEvent(eventStr, iface);
861            } else if (eventStr.startsWith(ASSOCIATED_WITH_STR)) {
862                handleAssociatedBSSIDEvent(eventStr, iface);
863            } else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR)
864                    && eventStr.endsWith(AUTH_TIMEOUT_STR)) {
865                broadcastAuthenticationFailureEvent(iface, AUTHENTICATION_FAILURE_REASON_TIMEOUT);
866            } else if (eventStr.startsWith(WPA_EVENT_PREFIX_STR)
867                    && eventStr.endsWith(PASSWORD_MAY_BE_INCORRECT_STR)) {
868                broadcastAuthenticationFailureEvent(
869                        iface, AUTHENTICATION_FAILURE_REASON_WRONG_PSWD);
870            } else {
871                if (mVerboseLoggingEnabled) {
872                    Log.w(TAG, "couldn't identify event type - " + eventStr);
873                }
874            }
875            eventLogCounter++;
876            return false;
877        }
878
879        String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
880        int nameEnd = eventName.indexOf(' ');
881        if (nameEnd != -1)
882            eventName = eventName.substring(0, nameEnd);
883        if (eventName.length() == 0) {
884            if (mVerboseLoggingEnabled) {
885                Log.i(TAG, "Received wpa_supplicant event with empty event name");
886            }
887            eventLogCounter++;
888            return false;
889        }
890        /*
891        * Map event name into event enum
892        */
893        int event;
894        if (eventName.equals(CONNECTED_STR)) {
895            event = CONNECTED;
896            long bssid = -1L;
897            int prefix = eventStr.indexOf(ConnectPrefix);
898            if (prefix >= 0) {
899                int suffix = eventStr.indexOf(ConnectSuffix);
900                if (suffix > prefix) {
901                    try {
902                        bssid = Utils.parseMac(
903                                eventStr.substring(prefix + ConnectPrefix.length(), suffix));
904                    } catch (IllegalArgumentException iae) {
905                        bssid = -1L;
906                    }
907                }
908            }
909            mLastConnectBSSIDs.put(iface, bssid);
910            if (bssid == -1L) {
911                Log.w(TAG, "Failed to parse out BSSID from '" + eventStr + "'");
912            }
913        }
914        else if (eventName.equals(DISCONNECTED_STR))
915            event = DISCONNECTED;
916        else if (eventName.equals(STATE_CHANGE_STR))
917            event = STATE_CHANGE;
918        else if (eventName.equals(LINK_SPEED_STR))
919            event = LINK_SPEED;
920        else if (eventName.equals(TERMINATING_STR))
921            event = TERMINATING;
922        else if (eventName.equals(DRIVER_STATE_STR))
923            event = DRIVER_STATE;
924        else if (eventName.equals(EAP_FAILURE_STR))
925            event = EAP_FAILURE;
926        else if (eventName.equals(ASSOC_REJECT_STR))
927            event = ASSOC_REJECT;
928        else if (eventName.equals(TEMP_DISABLED_STR)) {
929            event = SSID_TEMP_DISABLE;
930        } else if (eventName.equals(REENABLED_STR)) {
931            event = SSID_REENABLE;
932        } else if (eventName.equals(BSS_ADDED_STR)) {
933            event = BSS_ADDED;
934        } else if (eventName.equals(BSS_REMOVED_STR)) {
935            event = BSS_REMOVED;
936        } else
937            event = UNKNOWN;
938
939        String eventData = eventStr;
940        if (event == DRIVER_STATE || event == LINK_SPEED)
941            eventData = eventData.split(" ")[1];
942        else if (event == STATE_CHANGE || event == EAP_FAILURE) {
943            int ind = eventStr.indexOf(" ");
944            if (ind != -1) {
945                eventData = eventStr.substring(ind + 1);
946            }
947        } else {
948            int ind = eventStr.indexOf(" - ");
949            if (ind != -1) {
950                eventData = eventStr.substring(ind + 3);
951            }
952        }
953
954        if ((event == SSID_TEMP_DISABLE)||(event == SSID_REENABLE)) {
955            String substr = null;
956            int netId = -1;
957            int ind = eventStr.indexOf(" ");
958            if (ind != -1) {
959                substr = eventStr.substring(ind + 1);
960            }
961            if (substr != null) {
962                String status[] = substr.split(" ");
963                for (String key : status) {
964                    if (key.regionMatches(0, "id=", 0, 3)) {
965                        int idx = 3;
966                        netId = 0;
967                        while (idx < key.length()) {
968                            char c = key.charAt(idx);
969                            if ((c >= 0x30) && (c <= 0x39)) {
970                                netId *= 10;
971                                netId += c - 0x30;
972                                idx++;
973                            } else {
974                                break;
975                            }
976                        }
977                    }
978                }
979            }
980            sendMessage(iface, (event == SSID_TEMP_DISABLE)?
981                    SSID_TEMP_DISABLED:SSID_REENABLED, netId, 0, substr);
982        } else if (event == STATE_CHANGE) {
983            handleSupplicantStateChange(eventData, iface);
984        } else if (event == DRIVER_STATE) {
985            handleDriverEvent(eventData, iface);
986        } else if (event == TERMINATING) {
987            /**
988             * Close the supplicant connection if we see
989             * too many recv errors
990             */
991            if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
992                if (++mRecvErrors > MAX_RECV_ERRORS) {
993                    if (mVerboseLoggingEnabled) {
994                        Log.d(TAG, "too many recv errors, closing connection");
995                    }
996                } else {
997                    eventLogCounter++;
998                    return false;
999                }
1000            }
1001
1002            // Notify and exit
1003            broadcastSupplicantDisconnectionEvent(null);
1004            return true;
1005        } else if (event == EAP_FAILURE) {
1006            if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
1007                broadcastAuthenticationFailureEvent(
1008                        iface, AUTHENTICATION_FAILURE_REASON_EAP_FAILURE);
1009            }
1010        } else if (event == ASSOC_REJECT) {
1011            Matcher match = mAssocRejectEventPattern.matcher(eventData);
1012            String BSSID = "";
1013            int status = -1;
1014            if (!match.find()) {
1015                if (mVerboseLoggingEnabled) {
1016                    Log.d(TAG, "Assoc Reject: Could not parse assoc reject string");
1017                }
1018            } else {
1019                int groupNumber = match.groupCount();
1020                int statusGroupNumber = -1;
1021                if (groupNumber == 2) {
1022                    BSSID = match.group(1);
1023                    statusGroupNumber = 2;
1024                } else {
1025                    // Under such case Supplicant does not report BSSID
1026                    BSSID = null;
1027                    statusGroupNumber = 1;
1028                }
1029                try {
1030                    status = Integer.parseInt(match.group(statusGroupNumber));
1031                } catch (NumberFormatException e) {
1032                    status = -1;
1033                }
1034            }
1035            broadcastAssociationRejectionEvent(iface, status, BSSID);
1036        } else if (event == BSS_ADDED && !DBG) {
1037            // Ignore that event - it is not handled, and dont log it as it is too verbose
1038        } else if (event == BSS_REMOVED && !DBG) {
1039            // Ignore that event - it is not handled, and dont log it as it is too verbose
1040        }  else {
1041            handleEvent(event, eventData, iface);
1042        }
1043        mRecvErrors = 0;
1044        eventLogCounter++;
1045        return false;
1046    }
1047
1048    private void handleDriverEvent(String state, String iface) {
1049        if (state == null) {
1050            return;
1051        }
1052        if (state.equals("HANGED")) {
1053            sendMessage(iface, DRIVER_HUNG_EVENT);
1054        }
1055    }
1056
1057    /**
1058     * Handle all supplicant events except STATE-CHANGE
1059     * @param event the event type
1060     * @param remainder the rest of the string following the
1061     * event name and &quot;&#8195;&#8212;&#8195;&quot;
1062     */
1063    private void handleEvent(int event, String remainder, String iface) {
1064        if (mVerboseLoggingEnabled) {
1065            Log.d(TAG, "handleEvent " + Integer.toString(event) + " " + remainder);
1066        }
1067        switch (event) {
1068            case DISCONNECTED:
1069                handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder, iface);
1070                break;
1071
1072            case CONNECTED:
1073                handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder, iface);
1074                break;
1075
1076            case UNKNOWN:
1077                if (mVerboseLoggingEnabled) {
1078                    Log.w(TAG, "handleEvent unknown: " + Integer.toString(event) + " " + remainder);
1079                }
1080                break;
1081            default:
1082                break;
1083        }
1084    }
1085
1086    private void handleTargetBSSIDEvent(String eventStr, String iface) {
1087        String BSSID = null;
1088        Matcher match = mTargetBSSIDPattern.matcher(eventStr);
1089        if (match.find()) {
1090            BSSID = match.group(1);
1091        }
1092        sendMessage(iface, WifiStateMachine.CMD_TARGET_BSSID, eventLogCounter, 0, BSSID);
1093    }
1094
1095    private void handleAssociatedBSSIDEvent(String eventStr, String iface) {
1096        String BSSID = null;
1097        Matcher match = mAssociatedPattern.matcher(eventStr);
1098        if (match.find()) {
1099            BSSID = match.group(1);
1100        }
1101        broadcastAssociationSuccesfulEvent(iface, BSSID);
1102    }
1103
1104
1105    private void handleWpsFailEvent(String dataString, String iface) {
1106        final Pattern p = Pattern.compile(WPS_FAIL_PATTERN);
1107        Matcher match = p.matcher(dataString);
1108        int vendorErrorCodeInt = 0;
1109        int cfgErrInt = 0;
1110        if (match.find()) {
1111            String cfgErrStr = match.group(1);
1112            String vendorErrorCodeStr = match.group(2);
1113            if (vendorErrorCodeStr != null) {
1114                vendorErrorCodeInt = Integer.parseInt(vendorErrorCodeStr);
1115            }
1116            if (cfgErrStr != null) {
1117                cfgErrInt = Integer.parseInt(cfgErrStr);
1118            }
1119        }
1120        broadcastWpsFailEvent(iface, cfgErrInt, vendorErrorCodeInt);
1121    }
1122
1123    /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */
1124    private P2pStatus p2pError(String dataString) {
1125        P2pStatus err = P2pStatus.UNKNOWN;
1126        String[] tokens = dataString.split(" ");
1127        if (tokens.length < 2) return err;
1128        String[] nameValue = tokens[1].split("=");
1129        if (nameValue.length != 2) return err;
1130
1131        /* Handle the special case of reason=FREQ+CONFLICT */
1132        if (nameValue[1].equals("FREQ_CONFLICT")) {
1133            return P2pStatus.NO_COMMON_CHANNEL;
1134        }
1135        try {
1136            err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
1137        } catch (NumberFormatException e) {
1138            e.printStackTrace();
1139        }
1140        return err;
1141    }
1142
1143    private WifiP2pDevice getWifiP2pDevice(String dataString) {
1144        try {
1145            return new WifiP2pDevice(dataString);
1146        } catch (IllegalArgumentException e) {
1147            return null;
1148        }
1149    }
1150
1151    private WifiP2pGroup getWifiP2pGroup(String dataString) {
1152        try {
1153            return new WifiP2pGroup(dataString);
1154        } catch (IllegalArgumentException e) {
1155            return null;
1156        }
1157    }
1158
1159    /**
1160     * Handle p2p events
1161     */
1162    private void handleP2pEvents(String dataString, String iface) {
1163        if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) {
1164            WifiP2pDevice device = getWifiP2pDevice(dataString);
1165            if (device != null) sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device);
1166        } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) {
1167            WifiP2pDevice device = getWifiP2pDevice(dataString);
1168            if (device != null) sendMessage(iface, P2P_DEVICE_LOST_EVENT, device);
1169        } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) {
1170            sendMessage(iface, P2P_FIND_STOPPED_EVENT);
1171        } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) {
1172            sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, new WifiP2pConfig(dataString));
1173        } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) {
1174            sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT);
1175        } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) {
1176            sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString));
1177        } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) {
1178            sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT);
1179        } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) {
1180            sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString));
1181        } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) {
1182            WifiP2pGroup group = getWifiP2pGroup(dataString);
1183            if (group != null) sendMessage(iface, P2P_GROUP_STARTED_EVENT, group);
1184        } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) {
1185            WifiP2pGroup group = getWifiP2pGroup(dataString);
1186            if (group != null) sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group);
1187        } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) {
1188            sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, new WifiP2pGroup(dataString));
1189        } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) {
1190            sendMessage(iface, P2P_INVITATION_RESULT_EVENT, p2pError(dataString));
1191        } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) {
1192            sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, new WifiP2pProvDiscEvent(dataString));
1193        } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) {
1194            sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, new WifiP2pProvDiscEvent(dataString));
1195        } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) {
1196            sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, new WifiP2pProvDiscEvent(dataString));
1197        } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) {
1198            sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, new WifiP2pProvDiscEvent(dataString));
1199        } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) {
1200            sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT);
1201        } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) {
1202            List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString);
1203            if (list != null) {
1204                sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, list);
1205            } else {
1206                Log.e(TAG, "Null service resp " + dataString);
1207            }
1208        }
1209    }
1210
1211    /**
1212     * Handle hostap events
1213     */
1214    private void handleHostApEvents(String dataString, String iface) {
1215        String[] tokens = dataString.split(" ");
1216        /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
1217        if (tokens[0].equals(AP_STA_CONNECTED_STR)) {
1218            sendMessage(iface, AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString));
1219            /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
1220        } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) {
1221            sendMessage(iface, AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString));
1222        }
1223    }
1224
1225    private static final String ADDR_STRING = "addr=";
1226    private static final String RESULT_STRING = "result=";
1227
1228    // ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS
1229
1230    private void handleAnqpResult(String eventStr, String iface) {
1231        int addrPos = eventStr.indexOf(ADDR_STRING);
1232        int resPos = eventStr.indexOf(RESULT_STRING);
1233        if (addrPos < 0 || resPos < 0) {
1234            throw new IllegalArgumentException("Unexpected ANQP result notification");
1235        }
1236        int eoaddr = eventStr.indexOf(' ', addrPos + ADDR_STRING.length());
1237        if (eoaddr < 0) {
1238            eoaddr = eventStr.length();
1239        }
1240        int eoresult = eventStr.indexOf(' ', resPos + RESULT_STRING.length());
1241        if (eoresult < 0) {
1242            eoresult = eventStr.length();
1243        }
1244
1245        long bssid = 0;
1246        int result = 0;
1247        try {
1248            bssid = Utils.parseMac(eventStr.substring(addrPos + ADDR_STRING.length(), eoaddr));
1249            result = eventStr.substring(
1250                    resPos + RESULT_STRING.length(), eoresult).equalsIgnoreCase("success") ? 1 : 0;
1251        }
1252        catch (IllegalArgumentException iae) {
1253            Log.e(TAG, "Bad MAC address in ANQP response: " + iae.getMessage());
1254            return;
1255        }
1256        AnqpEvent anqpEvent = null;
1257        // If there are no errors fetch the ANQP elements from wpa_supplicant, otherwise return
1258        // empty ANQP elements.
1259        if (bssid != 0 && result != 0) {
1260            String bssData = mWifiNative.scanResult(Utils.macToString(bssid));
1261            anqpEvent = AnqpEvent.buildAnqpEvent(bssid, bssData);
1262        } else {
1263            anqpEvent = AnqpEvent.buildAnqpEvent(bssid, null);
1264        }
1265        broadcastAnqpDoneEvent(iface, anqpEvent);
1266    }
1267
1268    private void handleIconResult(String eventStr, String iface) {
1269        // RX-HS20-ICON c0:c5:20:27:d1:e8 <file> <size>
1270        String[] segments = eventStr.split(" ");
1271        if (segments.length != 4) {
1272            throw new IllegalArgumentException("Incorrect number of segments");
1273        }
1274
1275        try {
1276            String bssid = segments[1];
1277            String fileName = segments[2];
1278            int size = Integer.parseInt(segments[3]);
1279            byte[] iconData = null;
1280            if (!TextUtils.isEmpty(bssid) && !TextUtils.isEmpty(fileName) && size > 0) {
1281                try {
1282                    iconData = retrieveIcon(Utils.parseMac(bssid), fileName, size);
1283                } catch (IOException ioe) {
1284                    Log.e(TAG, "Failed to retrieve icon: " + ioe.toString() + ": " + fileName);
1285                }
1286            }
1287            broadcastIconDoneEvent(
1288                    iface, new IconEvent(Utils.parseMac(bssid), fileName, size, iconData));
1289        }
1290        catch (NumberFormatException nfe) {
1291            throw new IllegalArgumentException("Bad numeral");
1292        }
1293    }
1294
1295    // Retrieve the icon data from wpa_supplicant.
1296    private byte[] retrieveIcon(long bssid, String fileName, int fileSize) throws IOException {
1297        byte[] iconData = new byte[fileSize];
1298        try {
1299            int offset = 0;
1300            while (offset < fileSize) {
1301                int size = Math.min(fileSize - offset, ICON_CHUNK_SIZE);
1302
1303                String command = String.format("GET_HS20_ICON %s %s %d %d",
1304                        Utils.macToString(bssid), fileName, offset, size);
1305                Log.d(TAG, "Issuing '" + command + "'");
1306                String response = mWifiNative.doCustomSupplicantCommand(command);
1307                if (response == null) {
1308                    throw new IOException("No icon data returned");
1309                }
1310
1311                try {
1312                    byte[] fragment = Base64.decode(response, Base64.DEFAULT);
1313                    if (fragment.length == 0) {
1314                        throw new IOException("Null data for '" + command + "': " + response);
1315                    }
1316                    if (fragment.length + offset > iconData.length) {
1317                        throw new IOException("Icon chunk exceeds image size");
1318                    }
1319                    System.arraycopy(fragment, 0, iconData, offset, fragment.length);
1320                    offset += fragment.length;
1321                } catch (IllegalArgumentException iae) {
1322                    throw new IOException("Failed to parse response to '" + command
1323                            + "': " + response);
1324                }
1325            }
1326            if (offset != fileSize) {
1327                Log.w(TAG, "Partial icon data: " + offset + ", expected " + fileSize);
1328            }
1329        } finally {
1330            // Delete the icon file in supplicant.
1331            Log.d(TAG, "Deleting icon for " + fileName);
1332            String result = mWifiNative.doCustomSupplicantCommand("DEL_HS20_ICON "
1333                    + Utils.macToString(bssid) + " " + fileName);
1334            Log.d(TAG, "Result: " + result);
1335        }
1336        return iconData;
1337    }
1338
1339    private void handleWnmFrame(String eventStr, String iface) {
1340        try {
1341            WnmData wnmData = WnmData.buildWnmData(eventStr);
1342            broadcastWnmEvent(iface, wnmData);
1343        } catch (IOException | NumberFormatException e) {
1344            Log.w(TAG, "Bad WNM event: '" + eventStr + "'");
1345        }
1346    }
1347
1348    /**
1349     * Handle Supplicant Requests
1350     */
1351    private void handleRequests(String dataString, String iface) {
1352        String SSID = null;
1353        int  networkId = -2;
1354        String requestName = dataString.substring(REQUEST_PREFIX_LEN_STR);
1355        if (TextUtils.isEmpty(requestName)) {
1356            return;
1357        }
1358        if (requestName.startsWith(IDENTITY_STR)) {
1359            Matcher match = mRequestIdentityPattern.matcher(requestName);
1360            if (match.find()) {
1361                SSID = match.group(2);
1362                try {
1363                    networkId = Integer.parseInt(match.group(1));
1364                } catch (NumberFormatException e) {
1365                    networkId = -1;
1366                }
1367            } else {
1368                Log.e(TAG, "didn't find SSID " + requestName);
1369            }
1370            broadcastNetworkIdentityRequestEvent(iface, networkId, SSID);
1371        } else if (requestName.startsWith(SIM_STR)) {
1372            Matcher matchGsm = mRequestGsmAuthPattern.matcher(requestName);
1373            Matcher matchUmts = mRequestUmtsAuthPattern.matcher(requestName);
1374            if (matchGsm.find()) {
1375                String[] data = matchGsm.group(2).split(":");
1376                broadcastNetworkGsmAuthRequestEvent(iface, Integer.parseInt(matchGsm.group(1)),
1377                        matchGsm.group(4), data);
1378            } else if (matchUmts.find()) {
1379                String[] data = {matchUmts.group(2), matchUmts.group(3)};
1380                broadcastNetworkUmtsAuthRequestEvent(iface, Integer.parseInt(matchUmts.group(1)),
1381                        matchUmts.group(4), data);
1382            } else {
1383                Log.e(TAG, "couldn't parse SIM auth request - " + requestName);
1384            }
1385
1386        } else {
1387            if (mVerboseLoggingEnabled) {
1388                Log.w(TAG, "couldn't identify request type - " + dataString);
1389            }
1390        }
1391    }
1392
1393    /**
1394     * Handle the supplicant STATE-CHANGE event
1395     * @param dataString New supplicant state string in the format:
1396     * id=network-id state=new-state
1397     */
1398    private void handleSupplicantStateChange(String dataString, String iface) {
1399        WifiSsid wifiSsid = null;
1400        int index = dataString.lastIndexOf("SSID=");
1401        if (index != -1) {
1402            wifiSsid = WifiSsid.createFromAsciiEncoded(
1403                    dataString.substring(index + 5));
1404        }
1405        String[] dataTokens = dataString.split(" ");
1406
1407        String BSSID = null;
1408        int networkId = -1;
1409        int newState  = -1;
1410        for (String token : dataTokens) {
1411            String[] nameValue = token.split("=");
1412            if (nameValue.length != 2) {
1413                continue;
1414            }
1415
1416            if (nameValue[0].equals("BSSID")) {
1417                BSSID = nameValue[1];
1418                continue;
1419            }
1420
1421            int value;
1422            try {
1423                value = Integer.parseInt(nameValue[1]);
1424            } catch (NumberFormatException e) {
1425                continue;
1426            }
1427
1428            if (nameValue[0].equals("id")) {
1429                networkId = value;
1430            } else if (nameValue[0].equals("state")) {
1431                newState = value;
1432            }
1433        }
1434
1435        if (newState == -1) return;
1436
1437        SupplicantState newSupplicantState = SupplicantState.INVALID;
1438        for (SupplicantState state : SupplicantState.values()) {
1439            if (state.ordinal() == newState) {
1440                newSupplicantState = state;
1441                break;
1442            }
1443        }
1444        if (newSupplicantState == SupplicantState.INVALID) {
1445            Log.w(TAG, "Invalid supplicant state: " + newState);
1446        }
1447        broadcastSupplicantStateChangeEvent(iface, networkId, wifiSsid, BSSID, newSupplicantState);
1448    }
1449
1450    private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data,
1451            String iface) {
1452        String BSSID = null;
1453        int networkId = -1;
1454        int reason = 0;
1455        int ind = -1;
1456        int local = 0;
1457        Matcher match;
1458        if (newState == NetworkInfo.DetailedState.CONNECTED) {
1459            match = mConnectedEventPattern.matcher(data);
1460            if (!match.find()) {
1461                if (mVerboseLoggingEnabled) {
1462                    Log.d(TAG, "handleNetworkStateChange: Couldnt find BSSID in event string");
1463                }
1464            } else {
1465                BSSID = match.group(1);
1466                try {
1467                    networkId = Integer.parseInt(match.group(2));
1468                } catch (NumberFormatException e) {
1469                    networkId = -1;
1470                }
1471            }
1472            broadcastNetworkConnectionEvent(iface, networkId, BSSID);
1473        } else if (newState == NetworkInfo.DetailedState.DISCONNECTED) {
1474            match = mDisconnectedEventPattern.matcher(data);
1475            if (!match.find()) {
1476                if (mVerboseLoggingEnabled) {
1477                    Log.d(TAG, "handleNetworkStateChange: Could not parse disconnect string");
1478                }
1479            } else {
1480                BSSID = match.group(1);
1481                try {
1482                    reason = Integer.parseInt(match.group(2));
1483                } catch (NumberFormatException e) {
1484                    reason = -1;
1485                }
1486                try {
1487                    local = Integer.parseInt(match.group(3));
1488                } catch (NumberFormatException e) {
1489                    local = -1;
1490                }
1491            }
1492            if (mVerboseLoggingEnabled) {
1493                Log.d(TAG, "WifiMonitor notify network disconnect: " + BSSID
1494                        + " reason=" + Integer.toString(reason));
1495            }
1496            broadcastNetworkDisconnectionEvent(iface, local, reason, BSSID);
1497        }
1498    }
1499
1500    /**
1501     * Broadcast the WPS fail event to all the handlers registered for this event.
1502     *
1503     * @param iface Name of iface on which this occurred.
1504     * @param cfgError Configuration error code.
1505     * @param vendorErrorCode Vendor specific error indication code.
1506     */
1507    public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) {
1508        int reason = 0;
1509        switch(vendorErrorCode) {
1510            case REASON_TKIP_ONLY_PROHIBITED:
1511                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED);
1512                return;
1513            case REASON_WEP_PROHIBITED:
1514                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED);
1515                return;
1516            default:
1517                reason = vendorErrorCode;
1518                break;
1519        }
1520        switch(cfgError) {
1521            case CONFIG_AUTH_FAILURE:
1522                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE);
1523                return;
1524            case CONFIG_MULTIPLE_PBC_DETECTED:
1525                sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR);
1526                return;
1527            default:
1528                if (reason == 0) {
1529                    reason = cfgError;
1530                }
1531                break;
1532        }
1533        //For all other errors, return a generic internal error
1534        sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason);
1535    }
1536
1537   /**
1538    * Broadcast the WPS succes event to all the handlers registered for this event.
1539    *
1540    * @param iface Name of iface on which this occurred.
1541    */
1542    public void broadcastWpsSuccessEvent(String iface) {
1543        sendMessage(iface, WPS_SUCCESS_EVENT);
1544    }
1545
1546    /**
1547     * Broadcast the WPS overlap event to all the handlers registered for this event.
1548     *
1549     * @param iface Name of iface on which this occurred.
1550     */
1551    public void broadcastWpsOverlapEvent(String iface) {
1552        sendMessage(iface, WPS_OVERLAP_EVENT);
1553    }
1554
1555    /**
1556     * Broadcast the WPS timeout event to all the handlers registered for this event.
1557     *
1558     * @param iface Name of iface on which this occurred.
1559     */
1560    public void broadcastWpsTimeoutEvent(String iface) {
1561        sendMessage(iface, WPS_TIMEOUT_EVENT);
1562    }
1563
1564    /**
1565     * Broadcast the ANQP done event to all the handlers registered for this event.
1566     *
1567     * @param iface Name of iface on which this occurred.
1568     * @param anqpEvent ANQP result retrieved.
1569     */
1570    public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) {
1571        sendMessage(iface, ANQP_DONE_EVENT, anqpEvent);
1572    }
1573
1574    /**
1575     * Broadcast the Icon done event to all the handlers registered for this event.
1576     *
1577     * @param iface Name of iface on which this occurred.
1578     * @param iconEvent Instance of IconEvent containing the icon data retrieved.
1579     */
1580    public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) {
1581        sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent);
1582    }
1583
1584    /**
1585     * Broadcast the WNM event to all the handlers registered for this event.
1586     *
1587     * @param iface Name of iface on which this occurred.
1588     * @param wnmData Instance of WnmData containing the event data.
1589     */
1590    public void broadcastWnmEvent(String iface, WnmData wnmData) {
1591        sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData);
1592    }
1593
1594    /**
1595     * Broadcast the Network identity request event to all the handlers registered for this event.
1596     *
1597     * @param iface Name of iface on which this occurred.
1598     * @param networkId ID of the network in wpa_supplicant.
1599     * @param ssid SSID of the network.
1600     */
1601    public void broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid) {
1602        sendMessage(iface, SUP_REQUEST_IDENTITY, 0, networkId, ssid);
1603    }
1604
1605    /**
1606     * Broadcast the Network Gsm Sim auth request event to all the handlers registered for this
1607     * event.
1608     *
1609     * @param iface Name of iface on which this occurred.
1610     * @param networkId ID of the network in wpa_supplicant.
1611     * @param ssid SSID of the network.
1612     * @param data Accompanying event data.
1613     */
1614    public void broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid,
1615                                                    String[] data) {
1616        sendMessage(iface, SUP_REQUEST_SIM_AUTH,
1617                new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.SIM, ssid, data));
1618    }
1619
1620    /**
1621     * Broadcast the Network Umts Sim auth request event to all the handlers registered for this
1622     * event.
1623     *
1624     * @param iface Name of iface on which this occurred.
1625     * @param networkId ID of the network in wpa_supplicant.
1626     * @param ssid SSID of the network.
1627     * @param data Accompanying event data.
1628     */
1629    public void broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid,
1630                                                     String[] data) {
1631        sendMessage(iface, SUP_REQUEST_SIM_AUTH,
1632                new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.AKA, ssid, data));
1633    }
1634
1635    /**
1636     * Broadcast scan result event to all the handlers registered for this event.
1637     * @param iface Name of iface on which this occurred.
1638     */
1639    public void broadcastScanResultEvent(String iface) {
1640        sendMessage(iface, SCAN_RESULTS_EVENT);
1641    }
1642
1643    /**
1644     * Broadcast scan failed event to all the handlers registered for this event.
1645     * @param iface Name of iface on which this occurred.
1646     */
1647    public void broadcastScanFailedEvent(String iface) {
1648        sendMessage(iface, SCAN_FAILED_EVENT);
1649    }
1650
1651    /**
1652     * Broadcast the authentication failure event to all the handlers registered for this event.
1653     *
1654     * @param iface Name of iface on which this occurred.
1655     * @param reason Reason for authentication failure. This has to be one of the
1656     *               |AUTHENTICATION_FAILURE_REASON_*| reason codes.
1657     */
1658    public void broadcastAuthenticationFailureEvent(String iface, int reason) {
1659        sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, 0, reason);
1660    }
1661
1662    /**
1663     * Broadcast the association rejection event to all the handlers registered for this event.
1664     *
1665     * @param iface Name of iface on which this occurred.
1666     * @param status Status code for association rejection.
1667     * @param bssid BSSID of the access point from which we received the reject.
1668     */
1669    public void broadcastAssociationRejectionEvent(String iface, int status, String bssid) {
1670        sendMessage(iface, ASSOCIATION_REJECTION_EVENT, 0, status, bssid);
1671    }
1672
1673    /**
1674     * Broadcast the association success event to all the handlers registered for this event.
1675     *
1676     * @param iface Name of iface on which this occurred.
1677     * @param bssid BSSID of the access point from which we received the reject.
1678     */
1679    public void broadcastAssociationSuccesfulEvent(String iface, String bssid) {
1680        sendMessage(iface, WifiStateMachine.CMD_ASSOCIATED_BSSID, 0, 0, bssid);
1681    }
1682
1683    /**
1684     * Broadcast the network connection event to all the handlers registered for this event.
1685     *
1686     * @param iface Name of iface on which this occurred.
1687     * @param networkId ID of the network in wpa_supplicant.
1688     * @param bssid BSSID of the access point.
1689     */
1690    public void broadcastNetworkConnectionEvent(String iface, int networkId, String bssid) {
1691        sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, 0, bssid);
1692    }
1693
1694    /**
1695     * Broadcast the network disconnection event to all the handlers registered for this event.
1696     *
1697     * @param iface Name of iface on which this occurred.
1698     * @param local Whether the disconnect was locally triggered.
1699     * @param reason Disconnect reason code.
1700     * @param bssid BSSID of the access point.
1701     */
1702    public void broadcastNetworkDisconnectionEvent(String iface, int local, int reason,
1703                                                   String bssid) {
1704        sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, bssid);
1705    }
1706
1707    /**
1708     * Broadcast the supplicant state change event to all the handlers registered for this event.
1709     *
1710     * @param iface Name of iface on which this occurred.
1711     * @param networkId ID of the network in wpa_supplicant.
1712     * @param bssid BSSID of the access point.
1713     * @param newSupplicantState New supplicant state.
1714     */
1715    public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid,
1716                                                    String bssid,
1717                                                    SupplicantState newSupplicantState) {
1718        sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
1719                new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState));
1720    }
1721
1722    /**
1723     * Broadcast the connection to wpa_supplicant event to all the handlers registered for
1724     * this event.
1725     *
1726     * @param iface Name of iface on which this occurred.
1727     */
1728    public void broadcastSupplicantConnectionEvent(String iface) {
1729        sendMessage(iface, SUP_CONNECTION_EVENT);
1730    }
1731
1732    /**
1733     * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
1734     * this event.
1735     *
1736     * @param iface Name of iface on which this occurred.
1737     */
1738    public void broadcastSupplicantDisconnectionEvent(String iface) {
1739        sendMessage(iface, SUP_DISCONNECTION_EVENT);
1740    }
1741}
1742