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     /**
    140      * Deregister the given |handler|
    141      * @param iface
    142      * @param what
    143      * @param handler
    144      */
    145     public synchronized void deregisterHandler(String iface, int what, Handler handler) {
    146         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    147         if (ifaceHandlers == null) {
    148             return;
    149         }
    150         Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what);
    151         if (ifaceWhatHandlers == null) {
    152             return;
    153         }
    154         ifaceWhatHandlers.remove(handler);
    155     }
    156 
    157     private final Map<String, Boolean> mMonitoringMap = new HashMap<>();
    158     private boolean isMonitoring(String iface) {
    159         Boolean val = mMonitoringMap.get(iface);
    160         if (val == null) {
    161             return false;
    162         } else {
    163             return val.booleanValue();
    164         }
    165     }
    166 
    167     /**
    168      * Enable/Disable monitoring for the provided iface.
    169      *
    170      * @param iface Name of the iface.
    171      * @param enabled true to enable, false to disable.
    172      */
    173     @VisibleForTesting
    174     public void setMonitoring(String iface, boolean enabled) {
    175         mMonitoringMap.put(iface, enabled);
    176     }
    177 
    178     private void setMonitoringNone() {
    179         for (String iface : mMonitoringMap.keySet()) {
    180             setMonitoring(iface, false);
    181         }
    182     }
    183 
    184     /**
    185      * Start Monitoring for wpa_supplicant events.
    186      *
    187      * @param iface Name of iface.
    188      */
    189     public synchronized void startMonitoring(String iface) {
    190         if (mVerboseLoggingEnabled) Log.d(TAG, "startMonitoring(" + iface + ")");
    191         setMonitoring(iface, true);
    192         broadcastSupplicantConnectionEvent(iface);
    193     }
    194 
    195     /**
    196      * Stop Monitoring for wpa_supplicant events.
    197      *
    198      * @param iface Name of iface.
    199      */
    200     public synchronized void stopMonitoring(String iface) {
    201         if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")");
    202         setMonitoring(iface, true);
    203         broadcastSupplicantDisconnectionEvent(iface);
    204         setMonitoring(iface, false);
    205     }
    206 
    207     /**
    208      * Stop Monitoring for wpa_supplicant events.
    209      *
    210      * TODO: Add unit tests for these once we remove the legacy code.
    211      */
    212     public synchronized void stopAllMonitoring() {
    213         mConnected = false;
    214         setMonitoringNone();
    215     }
    216 
    217 
    218     /**
    219      * Similar functions to Handler#sendMessage that send the message to the registered handler
    220      * for the given interface and message what.
    221      * All of these should be called with the WifiMonitor class lock
    222      */
    223     private void sendMessage(String iface, int what) {
    224         sendMessage(iface, Message.obtain(null, what));
    225     }
    226 
    227     private void sendMessage(String iface, int what, Object obj) {
    228         sendMessage(iface, Message.obtain(null, what, obj));
    229     }
    230 
    231     private void sendMessage(String iface, int what, int arg1) {
    232         sendMessage(iface, Message.obtain(null, what, arg1, 0));
    233     }
    234 
    235     private void sendMessage(String iface, int what, int arg1, int arg2) {
    236         sendMessage(iface, Message.obtain(null, what, arg1, arg2));
    237     }
    238 
    239     private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
    240         sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
    241     }
    242 
    243     private void sendMessage(String iface, Message message) {
    244         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    245         if (iface != null && ifaceHandlers != null) {
    246             if (isMonitoring(iface)) {
    247                 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
    248                 if (ifaceWhatHandlers != null) {
    249                     for (Handler handler : ifaceWhatHandlers) {
    250                         if (handler != null) {
    251                             sendMessage(handler, Message.obtain(message));
    252                         }
    253                     }
    254                 }
    255             } else {
    256                 if (mVerboseLoggingEnabled) {
    257                     Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
    258                 }
    259             }
    260         } else {
    261             if (mVerboseLoggingEnabled) {
    262                 Log.d(TAG, "Sending to all monitors because there's no matching iface");
    263             }
    264             for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
    265                 if (isMonitoring(entry.getKey())) {
    266                     Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
    267                     for (Handler handler : ifaceWhatHandlers) {
    268                         if (handler != null) {
    269                             sendMessage(handler, Message.obtain(message));
    270                         }
    271                     }
    272                 }
    273             }
    274         }
    275 
    276         message.recycle();
    277     }
    278 
    279     private void sendMessage(Handler handler, Message message) {
    280         message.setTarget(handler);
    281         message.sendToTarget();
    282     }
    283 
    284     /**
    285      * Broadcast the WPS fail event to all the handlers registered for this event.
    286      *
    287      * @param iface Name of iface on which this occurred.
    288      * @param cfgError Configuration error code.
    289      * @param vendorErrorCode Vendor specific error indication code.
    290      */
    291     public void broadcastWpsFailEvent(String iface, int cfgError, int vendorErrorCode) {
    292         int reason = 0;
    293         switch(vendorErrorCode) {
    294             case REASON_TKIP_ONLY_PROHIBITED:
    295                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_TKIP_ONLY_PROHIBITED);
    296                 return;
    297             case REASON_WEP_PROHIBITED:
    298                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_WEP_PROHIBITED);
    299                 return;
    300             default:
    301                 reason = vendorErrorCode;
    302                 break;
    303         }
    304         switch(cfgError) {
    305             case CONFIG_AUTH_FAILURE:
    306                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_AUTH_FAILURE);
    307                 return;
    308             case CONFIG_MULTIPLE_PBC_DETECTED:
    309                 sendMessage(iface, WPS_FAIL_EVENT, WifiManager.WPS_OVERLAP_ERROR);
    310                 return;
    311             default:
    312                 if (reason == 0) {
    313                     reason = cfgError;
    314                 }
    315                 break;
    316         }
    317         //For all other errors, return a generic internal error
    318         sendMessage(iface, WPS_FAIL_EVENT, WifiManager.ERROR, reason);
    319     }
    320 
    321    /**
    322     * Broadcast the WPS succes event to all the handlers registered for this event.
    323     *
    324     * @param iface Name of iface on which this occurred.
    325     */
    326     public void broadcastWpsSuccessEvent(String iface) {
    327         sendMessage(iface, WPS_SUCCESS_EVENT);
    328     }
    329 
    330     /**
    331      * Broadcast the WPS overlap event to all the handlers registered for this event.
    332      *
    333      * @param iface Name of iface on which this occurred.
    334      */
    335     public void broadcastWpsOverlapEvent(String iface) {
    336         sendMessage(iface, WPS_OVERLAP_EVENT);
    337     }
    338 
    339     /**
    340      * Broadcast the WPS timeout event to all the handlers registered for this event.
    341      *
    342      * @param iface Name of iface on which this occurred.
    343      */
    344     public void broadcastWpsTimeoutEvent(String iface) {
    345         sendMessage(iface, WPS_TIMEOUT_EVENT);
    346     }
    347 
    348     /**
    349      * Broadcast the ANQP done event to all the handlers registered for this event.
    350      *
    351      * @param iface Name of iface on which this occurred.
    352      * @param anqpEvent ANQP result retrieved.
    353      */
    354     public void broadcastAnqpDoneEvent(String iface, AnqpEvent anqpEvent) {
    355         sendMessage(iface, ANQP_DONE_EVENT, anqpEvent);
    356     }
    357 
    358     /**
    359      * Broadcast the Icon done event to all the handlers registered for this event.
    360      *
    361      * @param iface Name of iface on which this occurred.
    362      * @param iconEvent Instance of IconEvent containing the icon data retrieved.
    363      */
    364     public void broadcastIconDoneEvent(String iface, IconEvent iconEvent) {
    365         sendMessage(iface, RX_HS20_ANQP_ICON_EVENT, iconEvent);
    366     }
    367 
    368     /**
    369      * Broadcast the WNM event to all the handlers registered for this event.
    370      *
    371      * @param iface Name of iface on which this occurred.
    372      * @param wnmData Instance of WnmData containing the event data.
    373      */
    374     public void broadcastWnmEvent(String iface, WnmData wnmData) {
    375         sendMessage(iface, HS20_REMEDIATION_EVENT, wnmData);
    376     }
    377 
    378     /**
    379      * Broadcast the Network identity request event to all the handlers registered for this event.
    380      *
    381      * @param iface Name of iface on which this occurred.
    382      * @param networkId ID of the network in wpa_supplicant.
    383      * @param ssid SSID of the network.
    384      */
    385     public void broadcastNetworkIdentityRequestEvent(String iface, int networkId, String ssid) {
    386         sendMessage(iface, SUP_REQUEST_IDENTITY, 0, networkId, ssid);
    387     }
    388 
    389     /**
    390      * Broadcast the Network Gsm Sim auth request event to all the handlers registered for this
    391      * event.
    392      *
    393      * @param iface Name of iface on which this occurred.
    394      * @param networkId ID of the network in wpa_supplicant.
    395      * @param ssid SSID of the network.
    396      * @param data Accompanying event data.
    397      */
    398     public void broadcastNetworkGsmAuthRequestEvent(String iface, int networkId, String ssid,
    399                                                     String[] data) {
    400         sendMessage(iface, SUP_REQUEST_SIM_AUTH,
    401                 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.SIM, ssid, data));
    402     }
    403 
    404     /**
    405      * Broadcast the Network Umts Sim auth request event to all the handlers registered for this
    406      * event.
    407      *
    408      * @param iface Name of iface on which this occurred.
    409      * @param networkId ID of the network in wpa_supplicant.
    410      * @param ssid SSID of the network.
    411      * @param data Accompanying event data.
    412      */
    413     public void broadcastNetworkUmtsAuthRequestEvent(String iface, int networkId, String ssid,
    414                                                      String[] data) {
    415         sendMessage(iface, SUP_REQUEST_SIM_AUTH,
    416                 new SimAuthRequestData(networkId, WifiEnterpriseConfig.Eap.AKA, ssid, data));
    417     }
    418 
    419     /**
    420      * Broadcast scan result event to all the handlers registered for this event.
    421      * @param iface Name of iface on which this occurred.
    422      */
    423     public void broadcastScanResultEvent(String iface) {
    424         sendMessage(iface, SCAN_RESULTS_EVENT);
    425     }
    426 
    427     /**
    428      * Broadcast pno scan result event to all the handlers registered for this event.
    429      * @param iface Name of iface on which this occurred.
    430      */
    431     public void broadcastPnoScanResultEvent(String iface) {
    432         sendMessage(iface, PNO_SCAN_RESULTS_EVENT);
    433     }
    434 
    435     /**
    436      * Broadcast scan failed event to all the handlers registered for this event.
    437      * @param iface Name of iface on which this occurred.
    438      */
    439     public void broadcastScanFailedEvent(String iface) {
    440         sendMessage(iface, SCAN_FAILED_EVENT);
    441     }
    442 
    443     /**
    444      * Broadcast the authentication failure event to all the handlers registered for this event.
    445      *
    446      * @param iface Name of iface on which this occurred.
    447      * @param reason Reason for authentication failure. This has to be one of the
    448      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_NONE},
    449      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_TIMEOUT},
    450      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_WRONG_PSWD},
    451      *               {@link android.net.wifi.WifiManager#ERROR_AUTH_FAILURE_EAP_FAILURE}
    452      * @param errorCode Error code associated with the authentication failure event.
    453      *               A value of -1 is used when no error code is reported.
    454      */
    455     public void broadcastAuthenticationFailureEvent(String iface, int reason, int errorCode) {
    456         sendMessage(iface, AUTHENTICATION_FAILURE_EVENT, reason, errorCode);
    457     }
    458 
    459     /**
    460      * Broadcast the association rejection event to all the handlers registered for this event.
    461      *
    462      * @param iface Name of iface on which this occurred.
    463      * @param status Status code for association rejection.
    464      * @param timedOut Indicates if the association timed out.
    465      * @param bssid BSSID of the access point from which we received the reject.
    466      */
    467     public void broadcastAssociationRejectionEvent(String iface, int status, boolean timedOut,
    468                                                    String bssid) {
    469         sendMessage(iface, ASSOCIATION_REJECTION_EVENT, timedOut ? 1 : 0, status, bssid);
    470     }
    471 
    472     /**
    473      * Broadcast the association success event to all the handlers registered for this event.
    474      *
    475      * @param iface Name of iface on which this occurred.
    476      * @param bssid BSSID of the access point.
    477      */
    478     public void broadcastAssociatedBssidEvent(String iface, String bssid) {
    479         sendMessage(iface, WifiStateMachine.CMD_ASSOCIATED_BSSID, 0, 0, bssid);
    480     }
    481 
    482     /**
    483      * Broadcast the start of association event to all the handlers registered for this event.
    484      *
    485      * @param iface Name of iface on which this occurred.
    486      * @param bssid BSSID of the access point.
    487      */
    488     public void broadcastTargetBssidEvent(String iface, String bssid) {
    489         sendMessage(iface, WifiStateMachine.CMD_TARGET_BSSID, 0, 0, bssid);
    490     }
    491 
    492     /**
    493      * Broadcast the network connection event to all the handlers registered for this event.
    494      *
    495      * @param iface Name of iface on which this occurred.
    496      * @param networkId ID of the network in wpa_supplicant.
    497      * @param bssid BSSID of the access point.
    498      */
    499     public void broadcastNetworkConnectionEvent(String iface, int networkId, String bssid) {
    500         sendMessage(iface, NETWORK_CONNECTION_EVENT, networkId, 0, bssid);
    501     }
    502 
    503     /**
    504      * Broadcast the network disconnection event to all the handlers registered for this event.
    505      *
    506      * @param iface Name of iface on which this occurred.
    507      * @param local Whether the disconnect was locally triggered.
    508      * @param reason Disconnect reason code.
    509      * @param bssid BSSID of the access point.
    510      */
    511     public void broadcastNetworkDisconnectionEvent(String iface, int local, int reason,
    512                                                    String bssid) {
    513         sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, bssid);
    514     }
    515 
    516     /**
    517      * Broadcast the supplicant state change event to all the handlers registered for this event.
    518      *
    519      * @param iface Name of iface on which this occurred.
    520      * @param networkId ID of the network in wpa_supplicant.
    521      * @param bssid BSSID of the access point.
    522      * @param newSupplicantState New supplicant state.
    523      */
    524     public void broadcastSupplicantStateChangeEvent(String iface, int networkId, WifiSsid wifiSsid,
    525                                                     String bssid,
    526                                                     SupplicantState newSupplicantState) {
    527         sendMessage(iface, SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
    528                 new StateChangeResult(networkId, wifiSsid, bssid, newSupplicantState));
    529     }
    530 
    531     /**
    532      * Broadcast the connection to wpa_supplicant event to all the handlers registered for
    533      * this event.
    534      *
    535      * @param iface Name of iface on which this occurred.
    536      */
    537     public void broadcastSupplicantConnectionEvent(String iface) {
    538         sendMessage(iface, SUP_CONNECTION_EVENT);
    539     }
    540 
    541     /**
    542      * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
    543      * this event.
    544      *
    545      * @param iface Name of iface on which this occurred.
    546      */
    547     public void broadcastSupplicantDisconnectionEvent(String iface) {
    548         sendMessage(iface, SUP_DISCONNECTION_EVENT);
    549     }
    550 }
    551