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