Home | History | Annotate | Download | only in connectivity
      1 /*
      2  * Copyright (C) 2014 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.tv.settings.connectivity;
     18 
     19 import com.android.tv.settings.R;
     20 
     21 import android.content.Context;
     22 import android.net.wifi.ScanResult;
     23 import android.net.wifi.WifiConfiguration;
     24 import android.net.wifi.WifiInfo;
     25 import android.net.wifi.WifiManager;
     26 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
     27 import android.net.wifi.WifiConfiguration.KeyMgmt;
     28 import android.text.TextUtils;
     29 import android.util.Log;
     30 
     31 import java.util.List;
     32 import java.util.regex.Matcher;
     33 import java.util.regex.Pattern;
     34 
     35 /**
     36  * Helper class that deals with Wi-fi configuration
     37  */
     38 public final class WifiConfigHelper {
     39 
     40     private static final String TAG = "WifiConfigHelper";
     41     private static final boolean DEBUG = false;
     42 
     43     /**
     44      * If there are exactly 12 hex digits, this looks like a BSSID
     45      */
     46     private static final String REGEX_HEX_BSSID = "[a-fA-F0-9]{12}";
     47 
     48     // Allows underscore char to supports proxies that do not
     49     // follow the spec
     50     private static final String HC = "a-zA-Z0-9\\_";
     51 
     52     // Matches blank input, ips, and domain names
     53     private static final String HOSTNAME_REGEXP =
     54             "^$|^[" + HC + "]+(\\-[" + HC + "]+)*(\\.[" + HC + "]+(\\-[" + HC + "]+)*)*$";
     55     private static final Pattern HOSTNAME_PATTERN;
     56     private static final String EXCLUSION_REGEXP =
     57             "$|^(\\*)?\\.?[" + HC + "]+(\\-[" + HC + "]+)*(\\.[" + HC + "]+(\\-[" + HC + "]+)*)*$";
     58     private static final Pattern EXCLUSION_PATTERN;
     59     static {
     60         HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
     61         EXCLUSION_PATTERN = Pattern.compile(EXCLUSION_REGEXP);
     62     }
     63 
     64     public static void setConfigSsid(WifiConfiguration config, String ssid) {
     65         // if this looks like a BSSID, don't quote it
     66         if (!Pattern.matches(REGEX_HEX_BSSID, ssid)) {
     67             config.SSID = enquoteSsid(ssid);
     68         } else {
     69             config.SSID = ssid;
     70         }
     71     }
     72 
     73     public static void setConfigSsid(WifiConfiguration config, ScanResult scanResult) {
     74         // just enquote the SSID, if taken from a scan result, we assume that
     75         // there is no possibility this is a BSSID in disguise.
     76         config.SSID = enquoteSsid(scanResult.SSID);
     77     }
     78 
     79     public static void setConfigKeyManagementBySecurity(
     80             WifiConfiguration config, WifiSecurity security) {
     81         config.allowedKeyManagement.clear();
     82         config.allowedAuthAlgorithms.clear();
     83         switch (security) {
     84             case NONE:
     85                 config.allowedKeyManagement.set(KeyMgmt.NONE);
     86                 break;
     87             case WEP:
     88                 config.allowedKeyManagement.set(KeyMgmt.NONE);
     89                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
     90                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
     91                 break;
     92             case PSK:
     93                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
     94                 break;
     95             case EAP:
     96                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
     97                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
     98                 break;
     99         }
    100     }
    101 
    102     public static boolean areSameNetwork(WifiManager wifiManager, ScanResult scanResult,
    103             WifiInfo wifiInfo) {
    104         if (scanResult == null || wifiInfo == null) {
    105             return false;
    106         }
    107         if (scanResult.SSID == null || wifiInfo.getSSID() == null) {
    108             return false;
    109         }
    110         if (scanResult.BSSID == null || wifiInfo.getBSSID() == null) {
    111             return false;
    112         }
    113         String wifiInfoSSID = WifiInfo.removeDoubleQuotes(wifiInfo.getSSID());
    114         String wifiInfoBSSID = wifiInfo.getBSSID();
    115         WifiSecurity scanResultSecurity = WifiSecurity.getSecurity(scanResult);
    116         WifiSecurity wifiInfoSecurity = getCurrentConnectionSecurity(wifiManager, wifiInfo);
    117 
    118         return (TextUtils.equals(scanResult.SSID, wifiInfoSSID) &&
    119                 TextUtils.equals(scanResult.BSSID, wifiInfoBSSID) &&
    120                 scanResultSecurity.equals(wifiInfoSecurity));
    121     }
    122 
    123     public static WifiSecurity getCurrentConnectionSecurity(WifiManager wifiManager,
    124             WifiInfo currentWifiInfo) {
    125         if (currentWifiInfo != null) {
    126             WifiConfiguration wifiConfiguration = getWifiConfiguration(wifiManager,
    127                     currentWifiInfo.getNetworkId());
    128             if (wifiConfiguration != null) {
    129                 return WifiSecurity.getSecurity(wifiConfiguration);
    130             }
    131         }
    132         return WifiSecurity.NONE;
    133     }
    134 
    135     /**
    136      * validate syntax of hostname and port entries
    137      * @return 0 on success, string resource ID on failure
    138      */
    139     public static int validate(String hostname, String port, String exclList) {
    140         Matcher match = HOSTNAME_PATTERN.matcher(hostname);
    141         String exclListArray[] = exclList.split(",");
    142 
    143         if (!match.matches()) return R.string.proxy_error_invalid_host;
    144 
    145         for (String excl : exclListArray) {
    146             Matcher m = EXCLUSION_PATTERN.matcher(excl);
    147             if (!m.matches()) return R.string.proxy_error_invalid_exclusion_list;
    148         }
    149 
    150         if (hostname.length() > 0 && port.length() == 0) {
    151             return R.string.proxy_error_empty_port;
    152         }
    153 
    154         if (port.length() > 0) {
    155             if (hostname.length() == 0) {
    156                 return R.string.proxy_error_empty_host_set_port;
    157             }
    158             int portVal = -1;
    159             try {
    160                 portVal = Integer.parseInt(port);
    161             } catch (NumberFormatException ex) {
    162                 return R.string.proxy_error_invalid_port;
    163             }
    164             if (portVal <= 0 || portVal > 0xFFFF) {
    165                 return R.string.proxy_error_invalid_port;
    166             }
    167         }
    168         return 0;
    169     }
    170 
    171     public static WifiConfiguration getWifiConfiguration(WifiManager wifiManager, int networkId) {
    172         List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
    173         if (configuredNetworks != null) {
    174             for (WifiConfiguration configuredNetwork : configuredNetworks) {
    175                 if (configuredNetwork.networkId == networkId) {
    176                     return configuredNetwork;
    177                 }
    178             }
    179         }
    180         return null;
    181     }
    182 
    183     /**
    184      * Did this config come out of the supplicant?  NOT "Is the config currently in the supplicant?"
    185      */
    186     public static boolean isNetworkSaved(WifiConfiguration config) {
    187         return config != null && config.networkId > -1;
    188     }
    189 
    190     /**
    191      * Return the configured network that matches the ScanResult, or create one.
    192      */
    193     public static WifiConfiguration getConfigurationForNetwork(Context context,
    194             ScanResult network) {
    195         WifiConfiguration config = getFromConfiguredNetworks(context, network.SSID,
    196                 WifiSecurity.getSecurity(network));
    197         if (config == null) {
    198             config = new WifiConfiguration();
    199             setConfigSsid(config, network);
    200             setConfigKeyManagementBySecurity(config, WifiSecurity.getSecurity(network));
    201         }
    202         return config;
    203     }
    204 
    205     /**
    206      * Return the configured network that matches the ssid/security pair, or create one.
    207      */
    208     public static WifiConfiguration getConfiguration(Context context, String ssid,
    209             WifiSecurity security) {
    210         WifiConfiguration config = getFromConfiguredNetworks(context, ssid, security);
    211 
    212         if (config == null) {
    213             // No configured network found; populate a new one with the provided ssid / security.
    214             config = new WifiConfiguration();
    215             setConfigSsid(config, ssid);
    216             setConfigKeyManagementBySecurity(config, security);
    217         }
    218         return config;
    219     }
    220 
    221     /**
    222      * Save a wifi configuration.
    223      */
    224     public static boolean saveConfiguration(Context context, WifiConfiguration config) {
    225         if (config == null) {
    226             return false;
    227         }
    228 
    229         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    230         int networkId = wifiMan.addNetwork(config);
    231         if (networkId == -1) {
    232           if (DEBUG) Log.e(TAG, "failed to add network: " + config.toString());
    233           return false;
    234         }
    235 
    236         if (!wifiMan.enableNetwork(networkId, false)) {
    237           if (DEBUG) Log.e(TAG, "enable network failed: " + networkId + "; " + config.toString());
    238           return false;
    239         }
    240 
    241         if (!wifiMan.saveConfiguration()) {
    242           if (DEBUG) Log.e(TAG, "failed to save: " + config.toString());
    243           return false;
    244         }
    245 
    246         if (DEBUG) Log.d(TAG, "saved network: " + config.toString());
    247         return true;
    248     }
    249 
    250     /**
    251      * Forget a wifi configuration.
    252      */
    253     public static void forgetConfiguration(Context context, WifiConfiguration config) {
    254         if (config == null) {
    255             return;
    256         }
    257 
    258         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    259         List<WifiConfiguration> configuredNetworks = wifiMan.getConfiguredNetworks();
    260         if (configuredNetworks == null) {
    261             if (DEBUG) Log.e(TAG, "failed to get configured networks");
    262             return;
    263         }
    264 
    265         for (WifiConfiguration wc : configuredNetworks) {
    266             if (wc != null && wc.SSID != null && TextUtils.equals(wc.SSID, config.SSID)) {
    267                 wifiMan.forget(wc.networkId, null);
    268                 if (DEBUG) Log.d(TAG, "forgot network config: " + wc.toString());
    269                 break;
    270             }
    271         }
    272     }
    273 
    274     /**
    275      * Forget the current wifi connection.
    276      */
    277     public static void forgetWifiNetwork(Context context) {
    278         WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    279         WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
    280         if (wifiInfo != null) {
    281             int networkId = wifiInfo.getNetworkId();
    282             if (networkId != -1) {
    283                 mWifiManager.forget(networkId, null);
    284             }
    285         }
    286     }
    287 
    288     private static String enquoteSsid(String ssid) {
    289         return "\"".concat(ssid.replace("\"", "\\\"")).concat("\"");
    290     }
    291 
    292     /**
    293      * @return A matching WifiConfiguration from the list of configured
    294      * networks, or null if no matching network is found.
    295      */
    296     private static WifiConfiguration getFromConfiguredNetworks(Context context, String ssid,
    297             WifiSecurity security) {
    298         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    299         List<WifiConfiguration> configuredNetworks = wifiMan.getConfiguredNetworks();
    300         if (configuredNetworks != null) {
    301             for (WifiConfiguration configuredNetwork : configuredNetworks) {
    302                 if (configuredNetwork == null || configuredNetwork.SSID == null) {
    303                     continue;  // Does this ever really happen?
    304                 }
    305 
    306                 // If the SSID and the security match, that's our network.
    307                 String configuredSsid = WifiInfo.removeDoubleQuotes(configuredNetwork.SSID);
    308                 if (TextUtils.equals(configuredSsid, ssid)) {
    309                     WifiSecurity configuredSecurity = WifiSecurity.getSecurity(configuredNetwork);
    310                     if (configuredSecurity.equals(security)) {
    311                         return configuredNetwork;
    312                     }
    313                 }
    314             }
    315         }
    316 
    317         return null;
    318     }
    319 
    320     private WifiConfigHelper() {
    321     }
    322 }
    323