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 android.content.Context;
20 import android.net.wifi.WifiConfiguration;
21 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
22 import android.net.wifi.WifiConfiguration.KeyMgmt;
23 import android.net.wifi.WifiInfo;
24 import android.net.wifi.WifiManager;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import com.android.settingslib.wifi.AccessPoint;
29 import com.android.tv.settings.R;
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 
setConfigSsid(WifiConfiguration config, String ssid)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 = AccessPoint.convertToQuotedString(ssid);
68         } else {
69             config.SSID = ssid;
70         }
71     }
72 
setConfigKeyManagementBySecurity( WifiConfiguration config, WifiSecurity security)73     public static void setConfigKeyManagementBySecurity(
74             WifiConfiguration config, WifiSecurity security) {
75         config.allowedKeyManagement.clear();
76         config.allowedAuthAlgorithms.clear();
77         switch (security) {
78             case NONE:
79                 config.allowedKeyManagement.set(KeyMgmt.NONE);
80                 break;
81             case WEP:
82                 config.allowedKeyManagement.set(KeyMgmt.NONE);
83                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
84                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
85                 break;
86             case PSK:
87                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
88                 break;
89             case EAP:
90                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
91                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
92                 break;
93         }
94     }
95 
96     /**
97      * validate syntax of hostname and port entries
98      * @return 0 on success, string resource ID on failure
99      */
validate(String hostname, String port, String exclList)100     public static int validate(String hostname, String port, String exclList) {
101         Matcher match = HOSTNAME_PATTERN.matcher(hostname);
102         String exclListArray[] = exclList.split(",");
103 
104         if (!match.matches()) return R.string.proxy_error_invalid_host;
105 
106         for (String excl : exclListArray) {
107             Matcher m = EXCLUSION_PATTERN.matcher(excl);
108             if (!m.matches()) return R.string.proxy_error_invalid_exclusion_list;
109         }
110 
111         if (hostname.length() > 0 && port.length() == 0) {
112             return R.string.proxy_error_empty_port;
113         }
114 
115         if (port.length() > 0) {
116             if (hostname.length() == 0) {
117                 return R.string.proxy_error_empty_host_set_port;
118             }
119             int portVal = -1;
120             try {
121                 portVal = Integer.parseInt(port);
122             } catch (NumberFormatException ex) {
123                 return R.string.proxy_error_invalid_port;
124             }
125             if (portVal <= 0 || portVal > 0xFFFF) {
126                 return R.string.proxy_error_invalid_port;
127             }
128         }
129         return 0;
130     }
131 
getWifiConfiguration(WifiManager wifiManager, int networkId)132     public static WifiConfiguration getWifiConfiguration(WifiManager wifiManager, int networkId) {
133         List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
134         if (configuredNetworks != null) {
135             for (WifiConfiguration configuredNetwork : configuredNetworks) {
136                 if (configuredNetwork.networkId == networkId) {
137                     return configuredNetwork;
138                 }
139             }
140         }
141         return null;
142     }
143 
144     /**
145      * Did this config come out of the supplicant?  NOT "Is the config currently in the supplicant?"
146      */
isNetworkSaved(WifiConfiguration config)147     public static boolean isNetworkSaved(WifiConfiguration config) {
148         return config != null && config.networkId > -1;
149     }
150 
151     /**
152      * Return the configured network that matches the ssid/security pair, or create one.
153      */
getConfiguration(Context context, String ssid, WifiSecurity security)154     public static WifiConfiguration getConfiguration(Context context, String ssid,
155             WifiSecurity security) {
156         WifiConfiguration config = getFromConfiguredNetworks(context, ssid, security);
157 
158         if (config == null) {
159             // No configured network found; populate a new one with the provided ssid / security.
160             config = new WifiConfiguration();
161             setConfigSsid(config, ssid);
162             setConfigKeyManagementBySecurity(config, security);
163         }
164         return config;
165     }
166 
167     /**
168      * Save a wifi configuration.
169      */
saveConfiguration(Context context, WifiConfiguration config)170     public static boolean saveConfiguration(Context context, WifiConfiguration config) {
171         if (config == null) {
172             return false;
173         }
174 
175         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
176         int networkId = wifiMan.addNetwork(config);
177         if (networkId == -1) {
178           if (DEBUG) Log.e(TAG, "failed to add network: " + config.toString());
179           return false;
180         }
181 
182         if (!wifiMan.enableNetwork(networkId, false)) {
183           if (DEBUG) Log.e(TAG, "enable network failed: " + networkId + "; " + config.toString());
184           return false;
185         }
186 
187         if (!wifiMan.saveConfiguration()) {
188           if (DEBUG) Log.e(TAG, "failed to save: " + config.toString());
189           return false;
190         }
191 
192         if (DEBUG) Log.d(TAG, "saved network: " + config.toString());
193         return true;
194     }
195 
196     /**
197      * Forget a wifi configuration.
198      */
forgetConfiguration(Context context, WifiConfiguration config)199     public static void forgetConfiguration(Context context, WifiConfiguration config) {
200         if (config == null) {
201             return;
202         }
203 
204         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
205         List<WifiConfiguration> configuredNetworks = wifiMan.getConfiguredNetworks();
206         if (configuredNetworks == null) {
207             if (DEBUG) Log.e(TAG, "failed to get configured networks");
208             return;
209         }
210 
211         for (WifiConfiguration wc : configuredNetworks) {
212             if (wc != null && wc.SSID != null && TextUtils.equals(wc.SSID, config.SSID)) {
213                 wifiMan.forget(wc.networkId, null);
214                 if (DEBUG) Log.d(TAG, "forgot network config: " + wc.toString());
215                 break;
216             }
217         }
218     }
219 
220     /**
221      * Forget the current wifi connection.
222      */
forgetWifiNetwork(Context context)223     public static void forgetWifiNetwork(Context context) {
224         WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
225         WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
226         if (wifiInfo != null) {
227             int networkId = wifiInfo.getNetworkId();
228             if (networkId != -1) {
229                 mWifiManager.forget(networkId, null);
230             }
231         }
232     }
233 
234     /**
235      * @return A matching WifiConfiguration from the list of configured
236      * networks, or null if no matching network is found.
237      */
getFromConfiguredNetworks(Context context, String ssid, WifiSecurity security)238     private static WifiConfiguration getFromConfiguredNetworks(Context context, String ssid,
239             WifiSecurity security) {
240         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
241         List<WifiConfiguration> configuredNetworks = wifiMan.getConfiguredNetworks();
242         if (configuredNetworks != null) {
243             for (WifiConfiguration configuredNetwork : configuredNetworks) {
244                 if (configuredNetwork == null || configuredNetwork.SSID == null) {
245                     continue;  // Does this ever really happen?
246                 }
247 
248                 // If the SSID and the security match, that's our network.
249                 String configuredSsid = WifiInfo.removeDoubleQuotes(configuredNetwork.SSID);
250                 if (TextUtils.equals(configuredSsid, ssid)) {
251                     WifiSecurity configuredSecurity = WifiSecurity.getSecurity(configuredNetwork);
252                     if (configuredSecurity.equals(security)) {
253                         return configuredNetwork;
254                     }
255                 }
256             }
257         }
258 
259         return null;
260     }
261 
WifiConfigHelper()262     private WifiConfigHelper() {
263     }
264 }
265