• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.net.wifi;
18 
19 import android.net.NetworkInfo;
20 import android.net.wifi.p2p.WifiP2pConfig;
21 import android.net.wifi.p2p.WifiP2pDevice;
22 import android.net.wifi.p2p.WifiP2pGroup;
23 import android.net.wifi.p2p.WifiP2pProvDiscEvent;
24 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
25 import android.net.wifi.StateChangeResult;
26 import android.os.Message;
27 import android.util.Log;
28 
29 
30 import com.android.internal.util.Protocol;
31 import com.android.internal.util.StateMachine;
32 
33 import java.util.List;
34 import java.util.regex.Pattern;
35 import java.util.regex.Matcher;
36 
37 /**
38  * Listens for events from the wpa_supplicant server, and passes them on
39  * to the {@link StateMachine} for handling. Runs in its own thread.
40  *
41  * @hide
42  */
43 public class WifiMonitor {
44 
45     private static final String TAG = "WifiMonitor";
46 
47     /** Events we receive from the supplicant daemon */
48 
49     private static final int CONNECTED    = 1;
50     private static final int DISCONNECTED = 2;
51     private static final int STATE_CHANGE = 3;
52     private static final int SCAN_RESULTS = 4;
53     private static final int LINK_SPEED   = 5;
54     private static final int TERMINATING  = 6;
55     private static final int DRIVER_STATE = 7;
56     private static final int EAP_FAILURE  = 8;
57     private static final int UNKNOWN      = 9;
58 
59     /** All events coming from the supplicant start with this prefix */
60     private static final String EVENT_PREFIX_STR = "CTRL-EVENT-";
61     private static final int EVENT_PREFIX_LEN_STR = EVENT_PREFIX_STR.length();
62 
63     /** All WPA events coming from the supplicant start with this prefix */
64     private static final String WPA_EVENT_PREFIX_STR = "WPA:";
65     private static final String PASSWORD_MAY_BE_INCORRECT_STR =
66        "pre-shared key may be incorrect";
67 
68     /* WPS events */
69     private static final String WPS_SUCCESS_STR = "WPS-SUCCESS";
70 
71     /* Format: WPS-FAIL msg=%d [config_error=%d] [reason=%d (%s)] */
72     private static final String WPS_FAIL_STR    = "WPS-FAIL";
73     private static final String WPS_FAIL_PATTERN =
74             "WPS-FAIL msg=\\d+(?: config_error=(\\d+))?(?: reason=(\\d+))?";
75 
76     /* config error code values for config_error=%d */
77     private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12;
78     private static final int CONFIG_AUTH_FAILURE = 18;
79 
80     /* reason code values for reason=%d */
81     private static final int REASON_TKIP_ONLY_PROHIBITED = 1;
82     private static final int REASON_WEP_PROHIBITED = 2;
83 
84     private static final String WPS_OVERLAP_STR = "WPS-OVERLAP-DETECTED";
85     private static final String WPS_TIMEOUT_STR = "WPS-TIMEOUT";
86 
87     /**
88      * Names of events from wpa_supplicant (minus the prefix). In the
89      * format descriptions, * &quot;<code>x</code>&quot;
90      * designates a dynamic value that needs to be parsed out from the event
91      * string
92      */
93     /**
94      * <pre>
95      * CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed
96      * </pre>
97      * <code>xx:xx:xx:xx:xx:xx</code> is the BSSID of the associated access point
98      */
99     private static final String CONNECTED_STR =    "CONNECTED";
100     /**
101      * <pre>
102      * CTRL-EVENT-DISCONNECTED - Disconnect event - remove keys
103      * </pre>
104      */
105     private static final String DISCONNECTED_STR = "DISCONNECTED";
106     /**
107      * <pre>
108      * CTRL-EVENT-STATE-CHANGE x
109      * </pre>
110      * <code>x</code> is the numerical value of the new state.
111      */
112     private static final String STATE_CHANGE_STR =  "STATE-CHANGE";
113     /**
114      * <pre>
115      * CTRL-EVENT-SCAN-RESULTS ready
116      * </pre>
117      */
118     private static final String SCAN_RESULTS_STR =  "SCAN-RESULTS";
119 
120     /**
121      * <pre>
122      * CTRL-EVENT-LINK-SPEED x Mb/s
123      * </pre>
124      * {@code x} is the link speed in Mb/sec.
125      */
126     private static final String LINK_SPEED_STR = "LINK-SPEED";
127     /**
128      * <pre>
129      * CTRL-EVENT-TERMINATING - signal x
130      * </pre>
131      * <code>x</code> is the signal that caused termination.
132      */
133     private static final String TERMINATING_STR =  "TERMINATING";
134     /**
135      * <pre>
136      * CTRL-EVENT-DRIVER-STATE state
137      * </pre>
138      * <code>state</code> can be HANGED
139      */
140     private static final String DRIVER_STATE_STR = "DRIVER-STATE";
141     /**
142      * <pre>
143      * CTRL-EVENT-EAP-FAILURE EAP authentication failed
144      * </pre>
145      */
146     private static final String EAP_FAILURE_STR = "EAP-FAILURE";
147 
148     /**
149      * This indicates an authentication failure on EAP FAILURE event
150      */
151     private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed";
152 
153     /**
154      * Regex pattern for extracting an Ethernet-style MAC address from a string.
155      * Matches a strings like the following:<pre>
156      * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]</pre>
157      */
158     private static Pattern mConnectedEventPattern =
159         Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) ");
160 
161     /** P2P events */
162     private static final String P2P_EVENT_PREFIX_STR = "P2P";
163 
164     /* P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 pri_dev_type=1-0050F204-1
165        name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */
166     private static final String P2P_DEVICE_FOUND_STR = "P2P-DEVICE-FOUND";
167 
168     /* P2P-DEVICE-LOST p2p_dev_addr=42:fc:89:e1:e2:27 */
169     private static final String P2P_DEVICE_LOST_STR = "P2P-DEVICE-LOST";
170 
171     /* P2P-FIND-STOPPED */
172     private static final String P2P_FIND_STOPPED_STR = "P2P-FIND-STOPPED";
173 
174     /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */
175     private static final String P2P_GO_NEG_REQUEST_STR = "P2P-GO-NEG-REQUEST";
176 
177     private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS";
178 
179     private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE";
180 
181     private static final String P2P_GROUP_FORMATION_SUCCESS_STR =
182             "P2P-GROUP-FORMATION-SUCCESS";
183 
184     private static final String P2P_GROUP_FORMATION_FAILURE_STR =
185             "P2P-GROUP-FORMATION-FAILURE";
186 
187     /* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
188        [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"]
189        go_dev_addr=fa:7b:7a:42:02:13 */
190     private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED";
191 
192     /* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */
193     private static final String P2P_GROUP_REMOVED_STR = "P2P-GROUP-REMOVED";
194 
195     /* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13
196         bssid=fa:7b:7a:42:82:13 unknown-network */
197     private static final String P2P_INVITATION_RECEIVED_STR = "P2P-INVITATION-RECEIVED";
198 
199     /* P2P-INVITATION-RESULT status=1 */
200     private static final String P2P_INVITATION_RESULT_STR = "P2P-INVITATION-RESULT";
201 
202     /* P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27
203        pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27
204        group_capab=0x0 */
205     private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ";
206 
207     /* P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 */
208     private static final String P2P_PROV_DISC_PBC_RSP_STR = "P2P-PROV-DISC-PBC-RESP";
209 
210     /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27
211        pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27
212        group_capab=0x0 */
213     private static final String P2P_PROV_DISC_ENTER_PIN_STR = "P2P-PROV-DISC-ENTER-PIN";
214     /* P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27
215        pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27
216        group_capab=0x0 */
217     private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN";
218 
219     /*
220      * Protocol format is as follows.<br>
221      * See the Table.62 in the WiFi Direct specification for the detail.
222      * ______________________________________________________________
223      * |           Length(2byte)     | Type(1byte) | TransId(1byte)}|
224      * ______________________________________________________________
225      * | status(1byte)  |            vendor specific(variable)      |
226      *
227      * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300000101
228      * length=3, service type=0(ALL Service), transaction id=1,
229      * status=1(service protocol type not available)<br>
230      *
231      * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300020201
232      * length=3, service type=2(UPnP), transaction id=2,
233      * status=1(service protocol type not available)
234      *
235      * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 990002030010757569643a3131323
236      * 2646534652d383537342d353961622d393332322d3333333435363738393034343a3
237      * a75726e3a736368656d61732d75706e702d6f72673a736572766963653a436f6e746
238      * 56e744469726563746f72793a322c757569643a36383539646564652d383537342d3
239      * 53961622d393333322d3132333435363738393031323a3a75706e703a726f6f74646
240      * 576696365
241      * length=153,type=2(UPnP),transaction id=3,status=0
242      *
243      * UPnP Protocol format is as follows.
244      * ______________________________________________________
245      * |  Version (1)  |          USN (Variable)            |
246      *
247      * version=0x10(UPnP1.0) data=usn:uuid:1122de4e-8574-59ab-9322-33345678
248      * 9044::urn:schemas-upnp-org:service:ContentDirectory:2,usn:uuid:6859d
249      * ede-8574-59ab-9332-123456789012::upnp:rootdevice
250      *
251      * P2P-SERV-DISC-RESP 58:17:0c:bc:dd:ca 21 1900010200045f6970
252      * 70c00c000c01094d795072696e746572c027
253      * length=25, type=1(Bonjour),transaction id=2,status=0
254      *
255      * Bonjour Protocol format is as follows.
256      * __________________________________________________________
257      * |DNS Name(Variable)|DNS Type(1)|Version(1)|RDATA(Variable)|
258      *
259      * DNS Name=_ipp._tcp.local.,DNS type=12(PTR), Version=1,
260      * RDATA=MyPrinter._ipp._tcp.local.
261      *
262      */
263     private static final String P2P_SERV_DISC_RESP_STR = "P2P-SERV-DISC-RESP";
264 
265     private static final String HOST_AP_EVENT_PREFIX_STR = "AP";
266     /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */
267     private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED";
268     /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
269     private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
270 
271     private final StateMachine mStateMachine;
272     private final WifiNative mWifiNative;
273 
274     /* Supplicant events reported to a state machine */
275     private static final int BASE = Protocol.BASE_WIFI_MONITOR;
276 
277     /* Connection to supplicant established */
278     public static final int SUP_CONNECTION_EVENT                 = BASE + 1;
279     /* Connection to supplicant lost */
280     public static final int SUP_DISCONNECTION_EVENT              = BASE + 2;
281    /* Network connection completed */
282     public static final int NETWORK_CONNECTION_EVENT             = BASE + 3;
283     /* Network disconnection completed */
284     public static final int NETWORK_DISCONNECTION_EVENT          = BASE + 4;
285     /* Scan results are available */
286     public static final int SCAN_RESULTS_EVENT                   = BASE + 5;
287     /* Supplicate state changed */
288     public static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 6;
289     /* Password failure and EAP authentication failure */
290     public static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 7;
291     /* WPS success detected */
292     public static final int WPS_SUCCESS_EVENT                    = BASE + 8;
293     /* WPS failure detected */
294     public static final int WPS_FAIL_EVENT                       = BASE + 9;
295      /* WPS overlap detected */
296     public static final int WPS_OVERLAP_EVENT                    = BASE + 10;
297      /* WPS timeout detected */
298     public static final int WPS_TIMEOUT_EVENT                    = BASE + 11;
299     /* Driver was hung */
300     public static final int DRIVER_HUNG_EVENT                    = BASE + 12;
301 
302     /* P2P events */
303     public static final int P2P_DEVICE_FOUND_EVENT               = BASE + 21;
304     public static final int P2P_DEVICE_LOST_EVENT                = BASE + 22;
305     public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT     = BASE + 23;
306     public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT     = BASE + 25;
307     public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT     = BASE + 26;
308     public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT    = BASE + 27;
309     public static final int P2P_GROUP_FORMATION_FAILURE_EVENT    = BASE + 28;
310     public static final int P2P_GROUP_STARTED_EVENT              = BASE + 29;
311     public static final int P2P_GROUP_REMOVED_EVENT              = BASE + 30;
312     public static final int P2P_INVITATION_RECEIVED_EVENT        = BASE + 31;
313     public static final int P2P_INVITATION_RESULT_EVENT          = BASE + 32;
314     public static final int P2P_PROV_DISC_PBC_REQ_EVENT          = BASE + 33;
315     public static final int P2P_PROV_DISC_PBC_RSP_EVENT          = BASE + 34;
316     public static final int P2P_PROV_DISC_ENTER_PIN_EVENT        = BASE + 35;
317     public static final int P2P_PROV_DISC_SHOW_PIN_EVENT         = BASE + 36;
318     public static final int P2P_FIND_STOPPED_EVENT               = BASE + 37;
319     public static final int P2P_SERV_DISC_RESP_EVENT             = BASE + 38;
320 
321     /* hostap events */
322     public static final int AP_STA_DISCONNECTED_EVENT            = BASE + 41;
323     public static final int AP_STA_CONNECTED_EVENT               = BASE + 42;
324 
325     /**
326      * This indicates the supplicant connection for the monitor is closed
327      */
328     private static final String MONITOR_SOCKET_CLOSED_STR = "connection closed";
329 
330     /**
331      * This indicates a read error on the monitor socket conenction
332      */
333     private static final String WPA_RECV_ERROR_STR = "recv error";
334 
335     /**
336      * Tracks consecutive receive errors
337      */
338     private int mRecvErrors = 0;
339 
340     /**
341      * Max errors before we close supplicant connection
342      */
343     private static final int MAX_RECV_ERRORS    = 10;
344 
WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative)345     public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
346         mStateMachine = wifiStateMachine;
347         mWifiNative = wifiNative;
348     }
349 
startMonitoring()350     public void startMonitoring() {
351         new MonitorThread().start();
352     }
353 
354     class MonitorThread extends Thread {
MonitorThread()355         public MonitorThread() {
356             super("WifiMonitor");
357         }
358 
run()359         public void run() {
360 
361             if (connectToSupplicant()) {
362                 // Send a message indicating that it is now possible to send commands
363                 // to the supplicant
364                 mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
365             } else {
366                 mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
367                 return;
368             }
369 
370             //noinspection InfiniteLoopStatement
371             for (;;) {
372                 String eventStr = mWifiNative.waitForEvent();
373 
374                 // Skip logging the common but mostly uninteresting scan-results event
375                 if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
376                     Log.d(TAG, "Event [" + eventStr + "]");
377                 }
378                 if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
379                     if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
380                             0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
381                         mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
382                     } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
383                         mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
384                     } else if (eventStr.startsWith(WPS_FAIL_STR)) {
385                         handleWpsFailEvent(eventStr);
386                     } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
387                         mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
388                     } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
389                         mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
390                     } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
391                         handleP2pEvents(eventStr);
392                     } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
393                         handleHostApEvents(eventStr);
394                     }
395                     continue;
396                 }
397 
398                 String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
399                 int nameEnd = eventName.indexOf(' ');
400                 if (nameEnd != -1)
401                     eventName = eventName.substring(0, nameEnd);
402                 if (eventName.length() == 0) {
403                     if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name");
404                     continue;
405                 }
406                 /*
407                  * Map event name into event enum
408                  */
409                 int event;
410                 if (eventName.equals(CONNECTED_STR))
411                     event = CONNECTED;
412                 else if (eventName.equals(DISCONNECTED_STR))
413                     event = DISCONNECTED;
414                 else if (eventName.equals(STATE_CHANGE_STR))
415                     event = STATE_CHANGE;
416                 else if (eventName.equals(SCAN_RESULTS_STR))
417                     event = SCAN_RESULTS;
418                 else if (eventName.equals(LINK_SPEED_STR))
419                     event = LINK_SPEED;
420                 else if (eventName.equals(TERMINATING_STR))
421                     event = TERMINATING;
422                 else if (eventName.equals(DRIVER_STATE_STR))
423                     event = DRIVER_STATE;
424                 else if (eventName.equals(EAP_FAILURE_STR))
425                     event = EAP_FAILURE;
426                 else
427                     event = UNKNOWN;
428 
429                 String eventData = eventStr;
430                 if (event == DRIVER_STATE || event == LINK_SPEED)
431                     eventData = eventData.split(" ")[1];
432                 else if (event == STATE_CHANGE || event == EAP_FAILURE) {
433                     int ind = eventStr.indexOf(" ");
434                     if (ind != -1) {
435                         eventData = eventStr.substring(ind + 1);
436                     }
437                 } else {
438                     int ind = eventStr.indexOf(" - ");
439                     if (ind != -1) {
440                         eventData = eventStr.substring(ind + 3);
441                     }
442                 }
443 
444                 if (event == STATE_CHANGE) {
445                     handleSupplicantStateChange(eventData);
446                 } else if (event == DRIVER_STATE) {
447                     handleDriverEvent(eventData);
448                 } else if (event == TERMINATING) {
449                     /**
450                      * Close the supplicant connection if we see
451                      * too many recv errors
452                      */
453                     if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
454                         if (++mRecvErrors > MAX_RECV_ERRORS) {
455                             if (false) {
456                                 Log.d(TAG, "too many recv errors, closing connection");
457                             }
458                         } else {
459                             continue;
460                         }
461                     }
462 
463                     // notify and exit
464                     mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
465                     break;
466                 } else if (event == EAP_FAILURE) {
467                     if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
468                         mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
469                     }
470                 } else {
471                     handleEvent(event, eventData);
472                 }
473                 mRecvErrors = 0;
474             }
475         }
476 
connectToSupplicant()477         private boolean connectToSupplicant() {
478             int connectTries = 0;
479 
480             while (true) {
481                 if (mWifiNative.connectToSupplicant()) {
482                     return true;
483                 }
484                 if (connectTries++ < 5) {
485                     nap(1);
486                 } else {
487                     break;
488                 }
489             }
490             return false;
491         }
492 
handleDriverEvent(String state)493         private void handleDriverEvent(String state) {
494             if (state == null) {
495                 return;
496             }
497             if (state.equals("HANGED")) {
498                 mStateMachine.sendMessage(DRIVER_HUNG_EVENT);
499             }
500         }
501 
502         /**
503          * Handle all supplicant events except STATE-CHANGE
504          * @param event the event type
505          * @param remainder the rest of the string following the
506          * event name and &quot;&#8195;&#8212;&#8195;&quot;
507          */
handleEvent(int event, String remainder)508         void handleEvent(int event, String remainder) {
509             switch (event) {
510                 case DISCONNECTED:
511                     handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
512                     break;
513 
514                 case CONNECTED:
515                     handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
516                     break;
517 
518                 case SCAN_RESULTS:
519                     mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
520                     break;
521 
522                 case UNKNOWN:
523                     break;
524             }
525         }
526 
handleWpsFailEvent(String dataString)527         private void handleWpsFailEvent(String dataString) {
528             final Pattern p = Pattern.compile(WPS_FAIL_PATTERN);
529             Matcher match = p.matcher(dataString);
530             if (match.find()) {
531                 String cfgErr = match.group(1);
532                 String reason = match.group(2);
533 
534                 if (reason != null) {
535                     switch(Integer.parseInt(reason)) {
536                         case REASON_TKIP_ONLY_PROHIBITED:
537                             mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT,
538                                     WifiManager.WPS_TKIP_ONLY_PROHIBITED, 0));
539                             return;
540                         case REASON_WEP_PROHIBITED:
541                             mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT,
542                                     WifiManager.WPS_WEP_PROHIBITED, 0));
543                             return;
544                     }
545                 }
546                 if (cfgErr != null) {
547                     switch(Integer.parseInt(cfgErr)) {
548                         case CONFIG_AUTH_FAILURE:
549                             mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT,
550                                     WifiManager.WPS_AUTH_FAILURE, 0));
551                             return;
552                         case CONFIG_MULTIPLE_PBC_DETECTED:
553                             mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT,
554                                     WifiManager.WPS_OVERLAP_ERROR, 0));
555                             return;
556                     }
557                 }
558             }
559             //For all other errors, return a generic internal error
560             mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT,
561                     WifiManager.ERROR, 0));
562         }
563 
564         /**
565          * Handle p2p events
566          */
handleP2pEvents(String dataString)567         private void handleP2pEvents(String dataString) {
568             if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) {
569                 mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString));
570             } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) {
571                 mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString));
572             } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) {
573                 mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT);
574             } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) {
575                 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT,
576                         new WifiP2pConfig(dataString));
577             } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) {
578                 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT);
579             } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) {
580                 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT);
581             } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) {
582                 mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT);
583             } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) {
584                 mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT);
585             } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) {
586                 mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString));
587             } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) {
588                 mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString));
589             } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) {
590                 mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT,
591                         new WifiP2pGroup(dataString));
592             } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) {
593                 String[] tokens = dataString.split(" ");
594                 if (tokens.length != 2) return;
595                 String[] nameValue = tokens[1].split("=");
596                 if (nameValue.length != 2) return;
597                 mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, nameValue[1]);
598             } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) {
599                 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT,
600                         new WifiP2pProvDiscEvent(dataString));
601             } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) {
602                 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT,
603                         new WifiP2pProvDiscEvent(dataString));
604             } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) {
605                 mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT,
606                         new WifiP2pProvDiscEvent(dataString));
607             } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) {
608                 mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT,
609                         new WifiP2pProvDiscEvent(dataString));
610             } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) {
611                 List<WifiP2pServiceResponse> list = WifiP2pServiceResponse.newInstance(dataString);
612                 if (list != null) {
613                     mStateMachine.sendMessage(P2P_SERV_DISC_RESP_EVENT, list);
614                 } else {
615                     Log.e(TAG, "Null service resp " + dataString);
616                 }
617             }
618         }
619 
620         /**
621          * Handle hostap events
622          */
handleHostApEvents(String dataString)623         private void handleHostApEvents(String dataString) {
624             String[] tokens = dataString.split(" ");
625             /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
626             if (tokens[0].equals(AP_STA_CONNECTED_STR)) {
627                 mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString));
628             /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
629             } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) {
630                 mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString));
631             }
632         }
633 
634         /**
635          * Handle the supplicant STATE-CHANGE event
636          * @param dataString New supplicant state string in the format:
637          * id=network-id state=new-state
638          */
handleSupplicantStateChange(String dataString)639         private void handleSupplicantStateChange(String dataString) {
640             String SSID = null;
641             int index = dataString.lastIndexOf("SSID=");
642             if (index != -1) SSID = dataString.substring(index + 5);
643             String[] dataTokens = dataString.split(" ");
644 
645             String BSSID = null;
646             int networkId = -1;
647             int newState  = -1;
648             for (String token : dataTokens) {
649                 String[] nameValue = token.split("=");
650                 if (nameValue.length != 2) {
651                     continue;
652                 }
653 
654                 if (nameValue[0].equals("BSSID")) {
655                     BSSID = nameValue[1];
656                     continue;
657                 }
658 
659                 int value;
660                 try {
661                     value = Integer.parseInt(nameValue[1]);
662                 } catch (NumberFormatException e) {
663                     continue;
664                 }
665 
666                 if (nameValue[0].equals("id")) {
667                     networkId = value;
668                 } else if (nameValue[0].equals("state")) {
669                     newState = value;
670                 }
671             }
672 
673             if (newState == -1) return;
674 
675             SupplicantState newSupplicantState = SupplicantState.INVALID;
676             for (SupplicantState state : SupplicantState.values()) {
677                 if (state.ordinal() == newState) {
678                     newSupplicantState = state;
679                     break;
680                 }
681             }
682             if (newSupplicantState == SupplicantState.INVALID) {
683                 Log.w(TAG, "Invalid supplicant state: " + newState);
684             }
685             notifySupplicantStateChange(networkId, SSID, BSSID, newSupplicantState);
686         }
687     }
688 
handleNetworkStateChange(NetworkInfo.DetailedState newState, String data)689     private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
690         String BSSID = null;
691         int networkId = -1;
692         if (newState == NetworkInfo.DetailedState.CONNECTED) {
693             Matcher match = mConnectedEventPattern.matcher(data);
694             if (!match.find()) {
695                 if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
696             } else {
697                 BSSID = match.group(1);
698                 try {
699                     networkId = Integer.parseInt(match.group(2));
700                 } catch (NumberFormatException e) {
701                     networkId = -1;
702                 }
703             }
704         }
705         notifyNetworkStateChange(newState, BSSID, networkId);
706     }
707 
708     /**
709      * Send the state machine a notification that the state of Wifi connectivity
710      * has changed.
711      * @param networkId the configured network on which the state change occurred
712      * @param newState the new network state
713      * @param BSSID when the new state is {@link DetailedState#CONNECTED
714      * NetworkInfo.DetailedState.CONNECTED},
715      * this is the MAC address of the access point. Otherwise, it
716      * is {@code null}.
717      */
notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId)718     void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
719         if (newState == NetworkInfo.DetailedState.CONNECTED) {
720             Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
721                     netId, 0, BSSID);
722             mStateMachine.sendMessage(m);
723         } else {
724             Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
725                     netId, 0, BSSID);
726             mStateMachine.sendMessage(m);
727         }
728     }
729 
730     /**
731      * Send the state machine a notification that the state of the supplicant
732      * has changed.
733      * @param networkId the configured network on which the state change occurred
734      * @param SSID network name
735      * @param BSSID network address
736      * @param newState the new {@code SupplicantState}
737      */
notifySupplicantStateChange(int networkId, String SSID, String BSSID, SupplicantState newState)738     void notifySupplicantStateChange(int networkId, String SSID, String BSSID, SupplicantState newState) {
739         mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
740                 new StateChangeResult(networkId, SSID, BSSID, newState)));
741     }
742 
743     /**
744      * Sleep for a period of time.
745      * @param secs the number of seconds to sleep
746      */
nap(int secs)747     private static void nap(int secs) {
748         try {
749             Thread.sleep(secs * 1000);
750         } catch (InterruptedException ignore) {
751         }
752     }
753 }
754