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