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.wifi.SupplicantState;
     20 import android.net.wifi.WifiEnterpriseConfig;
     21 import android.net.wifi.WifiManager;
     22 import android.net.wifi.WifiSsid;
     23 import android.os.Handler;
     24 import android.os.Message;
     25 import android.util.ArraySet;
     26 import android.util.Log;
     27 import android.util.SparseArray;
     28 
     29 import com.android.internal.annotations.VisibleForTesting;
     30 import com.android.internal.util.Protocol;
     31 import com.android.internal.util.StateMachine;
     32 import com.android.server.wifi.hotspot2.AnqpEvent;
     33 import com.android.server.wifi.hotspot2.IconEvent;
     34 import com.android.server.wifi.hotspot2.WnmData;
     35 import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
     36 
     37 import java.util.HashMap;
     38 import java.util.Map;
     39 import java.util.Set;
     40 
     41 /**
     42  * Listens for events from the wpa_supplicant server, and passes them on
     43  * to the {@link StateMachine} for handling.
     44  *
     45  * @hide
     46  */
     47 public class WifiMonitor {
     48     private static final String TAG = "WifiMonitor";
     49 
     50     /* Supplicant events reported to a state machine */
     51     private static final int BASE = Protocol.BASE_WIFI_MONITOR;
     52 
     53     /* Connection to supplicant established */
     54     public static final int SUP_CONNECTION_EVENT                 = BASE + 1;
     55     /* Connection to supplicant lost */
     56     public static final int SUP_DISCONNECTION_EVENT              = BASE + 2;
     57    /* Network connection completed */
     58     public static final int NETWORK_CONNECTION_EVENT             = BASE + 3;
     59     /* Network disconnection completed */
     60     public static final int NETWORK_DISCONNECTION_EVENT          = BASE + 4;
     61     /* Scan results are available */
     62     public static final int SCAN_RESULTS_EVENT                   = BASE + 5;
     63     /* Supplicate state changed */
     64     public static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 6;
     65     /* Password failure and EAP authentication failure */
     66     public static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 7;
     67     /* WPS success detected */
     68     public static final int WPS_SUCCESS_EVENT                    = BASE + 8;
     69     /* WPS failure detected */
     70     public static final int WPS_FAIL_EVENT                       = BASE + 9;
     71      /* WPS overlap detected */
     72     public static final int WPS_OVERLAP_EVENT                    = BASE + 10;
     73      /* WPS timeout detected */
     74     public static final int WPS_TIMEOUT_EVENT                    = BASE + 11;
     75 
     76     /* Request Identity */
     77     public static final int SUP_REQUEST_IDENTITY                 = BASE + 15;
     78 
     79     /* Request SIM Auth */
     80     public static final int SUP_REQUEST_SIM_AUTH                 = BASE + 16;
     81 
     82     public static final int SCAN_FAILED_EVENT                    = BASE + 17;
     83     /* Pno scan results are available */
     84     public static final int PNO_SCAN_RESULTS_EVENT               = BASE + 18;
     85 
     86 
     87     /* Indicates assoc reject event */
     88     public static final int ASSOCIATION_REJECTION_EVENT          = BASE + 43;
     89     public static final int ANQP_DONE_EVENT                      = BASE + 44;
     90 
     91     /* hotspot 2.0 ANQP events */
     92     public static final int GAS_QUERY_START_EVENT                = BASE + 51;
     93     public static final int GAS_QUERY_DONE_EVENT                 = BASE + 52;
     94     public static final int RX_HS20_ANQP_ICON_EVENT              = BASE + 53;
     95 
     96     /* hotspot 2.0 events */
     97     public static final int HS20_REMEDIATION_EVENT               = BASE + 61;
     98 
     99     /* WPS config errrors */
    100     private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12;
    101     private static final int CONFIG_AUTH_FAILURE = 18;
    102 
    103     /* WPS error indications */
    104     private static final int REASON_TKIP_ONLY_PROHIBITED = 1;
    105     private static final int REASON_WEP_PROHIBITED = 2;
    106 
    107     private final WifiInjector mWifiInjector;
    108     private boolean mVerboseLoggingEnabled = false;
    109     private boolean mConnected = false;
    110 
    111     public WifiMonitor(WifiInjector wifiInjector) {
    112         mWifiInjector = wifiInjector;
    113     }
    114 
    115     void enableVerboseLogging(int verbose) {
    116         if (verbose > 0) {
    117             mVerboseLoggingEnabled = true;
    118         } else {
    119             mVerboseLoggingEnabled = false;
    120         }
    121     }
    122 
    123     // TODO(b/27569474) remove support for multiple handlers for the same event
    124     private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>();
    125     public synchronized void registerHandler(String iface, int what, Handler handler) {
    126         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    127         if (ifaceHandlers == null) {
    128             ifaceHandlers = new SparseArray<>();
    129             mHandlerMap.put(iface, ifaceHandlers);
    130         }
    131         Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what);
    132         if (ifaceWhatHandlers == null) {
    133             ifaceWhatHandlers = new ArraySet<>();
    134             ifaceHandlers.put(what, ifaceWhatHandlers);
    135         }
    136         ifaceWhatHandlers.add(handler);
    137     }
    138 
    139     private final Map<String, Boolean> mMonitoringMap = new HashMap<>();
    140     private boolean isMonitoring(String iface) {
    141         Boolean val = mMonitoringMap.get(iface);
    142         if (val == null) {
    143             return false;
    144         } else {
    145             return val.booleanValue();
    146         }
    147     }
    148 
    149     /**
    150      * Enable/Disable monitoring for the provided iface.
    151      *
    152      * @param iface Name of the iface.
    153      * @param enabled true to enable, false to disable.
    154      */
    155     @VisibleForTesting
    156     public void setMonitoring(String iface, boolean enabled) {
    157         mMonitoringMap.put(iface, enabled);
    158     }
    159 
    160     private void setMonitoringNone() {
    161         for (String iface : mMonitoringMap.keySet()) {
    162             setMonitoring(iface, false);
    163         }
    164     }
    165 
    166     /**
    167      * Wait for wpa_supplicant's control interface to be ready.
    168      *
    169      * TODO: Add unit tests for these once we remove the legacy code.
    170      */
    171     private boolean ensureConnectedLocked() {
    172         if (mConnected) {
    173             return true;
    174         }
    175         if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant");
    176         int connectTries = 0;
    177         while (true) {
    178             mConnected = mWifiInjector.getWifiNative().connectToSupplicant();
    179             if (mConnected) {
    180                 return true;
    181             }
    182             if (connectTries++ < 50) {
    183                 try {
    184                     Thread.sleep(100);
    185                 } catch (InterruptedException ignore) {
    186                 }
    187             } else {
    188                 return false;
    189             }
    190         }
    191     }
    192 
    193     /**
    194      * Start Monitoring for wpa_supplicant events.
    195      *
    196      * @param iface Name of iface.
    197      * TODO: Add unit tests for these once we remove the legacy code.
    198      */
    199     public synchronized void startMonitoring(String iface, boolean isStaIface) {
    200         if (ensureConnectedLocked()) {
    201             setMonitoring(iface, true);
    202             broadcastSupplicantConnectionEvent(iface);
    203         } else {
    204             boolean originalMonitoring = isMonitoring(iface);
    205             setMonitoring(iface, true);
    206             broadcastSupplicantDisconnectionEvent(iface);
    207             setMonitoring(iface, originalMonitoring);
    208             Log.e(TAG, "startMonitoring(" + iface + ") failed!");
    209         }
    210     }
    211 
    212     /**
    213      * Stop Monitoring for wpa_supplicant events.
    214      *
    215      * @param iface Name of iface.
    216      * TODO: Add unit tests for these once we remove the legacy code.
    217      */
    218     public synchronized void stopMonitoring(String iface) {
    219         if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")");
    220         setMonitoring(iface, true);
    221         broadcastSupplicantDisconnectionEvent(iface);
    222         setMonitoring(iface, false);
    223     }
    224 
    225     /**
    226      * Stop Monitoring for wpa_supplicant events.
    227      *
    228      * TODO: Add unit tests for these once we remove the legacy code.
    229      */
    230     public synchronized void stopAllMonitoring() {
    231         mConnected = false;
    232         setMonitoringNone();
    233     }
    234 
    235 
    236     /**
    237      * Similar functions to Handler#sendMessage that send the message to the registered handler
    238      * for the given interface and message what.
    239      * All of these should be called with the WifiMonitor class lock
    240      */
    241     private void sendMessage(String iface, int what) {
    242         sendMessage(iface, Message.obtain(null, what));
    243     }
    244 
    245     private void sendMessage(String iface, int what, Object obj) {
    246         sendMessage(iface, Message.obtain(null, what, obj));
    247     }
    248 
    249     private void sendMessage(String iface, int what, int arg1) {
    250         sendMessage(iface, Message.obtain(null, what, arg1, 0));
    251     }
    252 
    253     private void sendMessage(String iface, int what, int arg1, int arg2) {
    254         sendMessage(iface, Message.obtain(null, what, arg1, arg2));
    255     }
    256 
    257     private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
    258         sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
    259     }
    260 
    261     private void sendMessage(String iface, Message message) {
    262         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    263         if (iface != null && ifaceHandlers != null) {
    264             if (isMonitoring(iface)) {
    265                 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
    266                 if (ifaceWhatHandlers != null) {
    267                     for (Handler handler : ifaceWhatHandlers) {
    268                         if (handler != null) {
    269                             sendMessage(handler, Message.obtain(message));
    270                         }
    271                     }
    272                 }
    273             } else {
    274                 if (mVerboseLoggingEnabled) {
    275                     Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
    276                 }
    277             }
    278         } else {
    279             if (mVerboseLoggingEnabled) {
    280                 Log.d(TAG, "Sending to all monitors because there's no matching iface");
    281             }
    282             for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
    283                 if (isMonitoring(entry.getKey())) {
    284                     Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
    285                     for (Handler handler : ifaceWhatHandlers) {
    286                         if (handler != null) {
    287                             sendMessage(handler, Message.obtain(message));
    288                         }
    289                     }
    290                 }
    291             }
    292         }
    293 
    294         message.recycle();
    295     }
    296 
    297     private void sendMessage(Handler handler, Message message) {
    298         message.setTarget(handler);
    299         message.sendToTarget();
    300     }
    301 
    302     /**
    303      * Broadcast the WPS fail event to all the handlers registered for this event.
    304      *
    305      * @param iface Name of iface on which this occurred.
    306      * @param cfgError Configuration error code.
    307      * @param vendorErrorCode Vendor specific error indication code.
    308      */
    309     public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) {
    310         int reason = 0;
    311         switch(vendorErrorCode) {
    312             case REASON_TKIP_ONLY_PROHIBITED:
    313                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED);
    314                 return;
    315             case REASON_WEP_PROHIBITED:
    316                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED);
    317                 return;
    318             default:
    319                 reason = vendorErrorCode;
    320                 break;
    321         }
    322         switch(cfgError) {
    323             case CONFIG_AUTH_FAILURE:
    324                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE);
    325                 return;
    326             case CONFIG_MULTIPLE_PBC_DETECTED:
    327                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR);
    328                 return;
    329             default:
    330                 if (reason == 0) {
    331                     reason = cfgError;
    332                 }
    333                 break;
    334         }
    335         //For all other errors, return a generic internal error
    336         sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason);
    337     }
    338 
    339    /**
    340     * Broadcast the WPS succes event to all the handlers registered for this event.
    341     *
    342     * @param iface Name of iface on which this occurred.
    343     */
    344     public void broadcastWpsSuccessEvent(String iface) {
    345         sendMessage(iface, WPS_SUCCESS_EVENT);
    346     }
    347 
    348     /**
    349      * Broadcast the WPS overlap event to all the handlers registered for this event.
    350      *
    351      * @param iface Name of iface on which this occurred.
    352      */
    353     public void broadcastWpsOverlapEvent(String iface) {
    354         sendMessage(iface, WPS_OVERLAP_EVENT);
    355     }
    356 
    357     /**
    358      * Broadcast the WPS timeout event to all the handlers registered for this event.
    359      *
    360      * @param iface Name of iface on which this occurred.
    361      */
    362     public void broadcastWpsTimeoutEvent(String iface) {
    363         sendMessage(iface, WPS_TIMEOUT_EVENT);
    364     }
    365 
    366     /**
    367      * Broadcast the ANQP done event to all the handlers registered for this event.
    368      *
    369      * @param iface Name of iface on which this occurred.
    370      * @param anqpEvent ANQP result retrieved.
    371      */
    372     public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) {
    373         sendMessage(iface, ANQP_DONE_EVENT, anqpEvent);
    374     }
    375 
    376     /**
    377      * Broadcast the Icon done event to all the handlers registered for this event.
    378      *
    379      * @param iface Name of iface on which this occurred.
    380      * @param iconEvent Instance of IconEvent containing the icon data retrieved.
    381      */
    382     public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) {
    383         sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent);
    384     }
    385 
    386     /**
    387      * Broadcast the WNM event to all the handlers registered for this event.
    388      *
    389      * @param iface Name of iface on which this occurred.
    390      * @param wnmData Instance of WnmData containing the event data.
    391      */
    392     public void broadcastWnmEvent(String iface, WnmData wnmData) {
    393         sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData);
    394     }
    395 
    396     /**
    397      * Broadcast the Network identity request event to all the handlers registered for this event.
    398      *
    399      * @param iface Name of iface on which this occurred.
    400      * @param networkId ID of the network in wpa_supplicant.
    401      * @param ssid SSID of the network.
    402      */
    403     public void broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid) {
    404         sendMessage(iface, SUP_REQUEST_IDENTITY, 0, networkId, ssid);
    405     }
    406 
    407     /**
    408      * Broadcast the Network Gsm Sim auth request event to all the handlers registered for this
    409      * event.
    410      *
    411      * @param iface Name of iface on which this occurred.
    412      * @param networkId ID of the network in wpa_supplicant.
    413      * @param ssid SSID of the network.
    414      * @param data Accompanying event data.
    415      */
    416     public void broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid,
    417                                                     String[] data) {
    418         sendMessage(iface, SUP_REQUEST_SIM_AUTH,
    419                 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.SIM, ssid, data));
    420     }
    421 
    422     /**
    423      * Broadcast the Network Umts Sim auth request event to all the handlers registered for this
    424      * event.
    425      *
    426      * @param iface Name of iface on which this occurred.
    427      * @param networkId ID of the network in wpa_supplicant.
    428      * @param ssid SSID of the network.
    429      * @param data Accompanying event data.
    430      */
    431     public void broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid,
    432                                                      String[] data) {
    433         sendMessage(iface, SUP_REQUEST_SIM_AUTH,
    434                 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.AKA, ssid, data));
    435     }
    436 
    437     /**
    438      * Broadcast scan result event to all the handlers registered for this event.
    439      * @param iface Name of iface on which this occurred.
    440      */
    441     public void broadcastScanResultEvent(String iface) {
    442         sendMessage(iface, SCAN_RESULTS_EVENT);
    443     }
    444 
    445     /**
    446      * Broadcast pno scan result event to all the handlers registered for this event.
    447      * @param iface Name of iface on which this occurred.
    448      */
    449     public void broadcastPnoScanResultEvent(String iface) {
    450         sendMessage(iface, PNO_SCAN_RESULTS_EVENT);
    451     }
    452 
    453     /**
    454      * Broadcast scan failed event to all the handlers registered for this event.
    455      * @param iface Name of iface on which this occurred.
    456      */
    457     public void broadcastScanFailedEvent(String iface) {
    458         sendMessage(iface, SCAN_FAILED_EVENT);
    459     }
    460 
    461     /**
    462      * Broadcast the authentication failure event to all the handlers registered for this event.
    463      *
    464      * @param iface Name of iface on which this occurred.
    465      * @param reason Reason for authentication failure. This has to be one of the
    466      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_NONE},
    467      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_TIMEOUT},
    468      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_WRONG_PSWD},
    469      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_EAP_FAILURE}
    470      */
    471     public void broadcastAuthenticationFailureEvent(String iface, int reason) {
    472         sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, 0, reason);
    473     }
    474 
    475     /**
    476      * Broadcast the association rejection event to all the handlers registered for this event.
    477      *
    478      * @param iface Name of iface on which this occurred.
    479      * @param status Status code for association rejection.
    480      * @param timedOut Indicates if the association timed out.
    481      * @param bssid BSSID of the access point from which we received the reject.
    482      */
    483     public void broadcastAssociationRejectionEvent(String iface, int status, boolean timedOut,
    484                                                    String bssid) {
    485         sendMessage(iface, ASSOCIATION_REJECTION_EVENT, timedOut ? 1 : 0, status, bssid);
    486     }
    487 
    488     /**
    489      * Broadcast the association success event to all the handlers registered for this event.
    490      *
    491      * @param iface Name of iface on which this occurred.
    492      * @param bssid BSSID of the access point.
    493      */
    494     public void broadcastAssociatedBssidEvent(String iface, String bssid) {
    495         sendMessage(iface, WifiStateMachine.CMD_ASSOCIATED_BSSID, 0, 0, bssid);
    496     }
    497 
    498     /**
    499      * Broadcast the start of association event to all the handlers registered for this event.
    500      *
    501      * @param iface Name of iface on which this occurred.
    502      * @param bssid BSSID of the access point.
    503      */
    504     public void broadcastTargetBssidEvent(String iface, String bssid) {
    505         sendMessage(iface, WifiStateMachine.CMD_TARGET_BSSID, 0, 0, bssid);
    506     }
    507 
    508     /**
    509      * Broadcast the network connection event to all the handlers registered for this event.
    510      *
    511      * @param iface Name of iface on which this occurred.
    512      * @param networkId ID of the network in wpa_supplicant.
    513      * @param bssid BSSID of the access point.
    514      */
    515     public void broadcastNetworkConnectionEvent(String iface, int networkId, String bssid) {
    516         sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, 0, bssid);
    517     }
    518 
    519     /**
    520      * Broadcast the network disconnection event to all the handlers registered for this event.
    521      *
    522      * @param iface Name of iface on which this occurred.
    523      * @param local Whether the disconnect was locally triggered.
    524      * @param reason Disconnect reason code.
    525      * @param bssid BSSID of the access point.
    526      */
    527     public void broadcastNetworkDisconnectionEvent(String iface, int local, int reason,
    528                                                    String bssid) {
    529         sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, bssid);
    530     }
    531 
    532     /**
    533      * Broadcast the supplicant state change event to all the handlers registered for this event.
    534      *
    535      * @param iface Name of iface on which this occurred.
    536      * @param networkId ID of the network in wpa_supplicant.
    537      * @param bssid BSSID of the access point.
    538      * @param newSupplicantState New supplicant state.
    539      */
    540     public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid,
    541                                                     String bssid,
    542                                                     SupplicantState newSupplicantState) {
    543         sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
    544                 new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState));
    545     }
    546 
    547     /**
    548      * Broadcast the connection to wpa_supplicant event to all the handlers registered for
    549      * this event.
    550      *
    551      * @param iface Name of iface on which this occurred.
    552      */
    553     public void broadcastSupplicantConnectionEvent(String iface) {
    554         sendMessage(iface, SUP_CONNECTION_EVENT);
    555     }
    556 
    557     /**
    558      * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
    559      * this event.
    560      *
    561      * @param iface Name of iface on which this occurred.
    562      */
    563     public void broadcastSupplicantDisconnectionEvent(String iface) {
    564         sendMessage(iface, SUP_DISCONNECTION_EVENT);
    565     }
    566 }
    567