• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.hotspot2;
2 
3 import android.content.Context;
4 import android.content.Intent;
5 import android.net.CaptivePortal;
6 import android.net.ConnectivityManager;
7 import android.net.ICaptivePortal;
8 import android.net.Network;
9 import android.net.wifi.WifiConfiguration;
10 import android.net.wifi.WifiEnterpriseConfig;
11 import android.net.wifi.WifiInfo;
12 import android.net.wifi.WifiManager;
13 import android.util.Log;
14 
15 import com.android.configparse.ConfigBuilder;
16 import com.android.hotspot2.omadm.MOManager;
17 import com.android.hotspot2.omadm.MOTree;
18 import com.android.hotspot2.omadm.OMAConstants;
19 import com.android.hotspot2.omadm.OMAException;
20 import com.android.hotspot2.omadm.OMAParser;
21 import com.android.hotspot2.osu.OSUCertType;
22 import com.android.hotspot2.osu.OSUInfo;
23 import com.android.hotspot2.osu.OSUManager;
24 import com.android.hotspot2.osu.commands.MOData;
25 import com.android.hotspot2.pps.HomeSP;
26 
27 import org.xml.sax.SAXException;
28 
29 import java.io.IOException;
30 import java.net.URL;
31 import java.security.GeneralSecurityException;
32 import java.security.PrivateKey;
33 import java.security.cert.X509Certificate;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 
40 public class WifiNetworkAdapter {
41     private final Context mContext;
42     private final OSUManager mOSUManager;
43     private final Map<String, PasspointConfig> mPasspointConfigs = new HashMap<>();
44 
45     private static class PasspointConfig {
46         private final WifiConfiguration mWifiConfiguration;
47         private final MOTree mMOTree;
48         private final HomeSP mHomeSP;
49 
PasspointConfig(WifiConfiguration config)50         private PasspointConfig(WifiConfiguration config) throws IOException, SAXException {
51             mWifiConfiguration = config;
52             OMAParser omaParser = new OMAParser();
53             mMOTree = omaParser.parse(config.getMoTree(), OMAConstants.PPS_URN);
54             List<HomeSP> spList = MOManager.buildSPs(mMOTree);
55             if (spList.size() != 1) {
56                 throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
57             }
58             mHomeSP = spList.iterator().next();
59         }
60 
getWifiConfiguration()61         public WifiConfiguration getWifiConfiguration() {
62             return mWifiConfiguration;
63         }
64 
getHomeSP()65         public HomeSP getHomeSP() {
66             return mHomeSP;
67         }
68 
getmMOTree()69         public MOTree getmMOTree() {
70             return mMOTree;
71         }
72     }
73 
WifiNetworkAdapter(Context context, OSUManager osuManager)74     public WifiNetworkAdapter(Context context, OSUManager osuManager) {
75         mOSUManager = osuManager;
76         mContext = context;
77     }
78 
initialize()79     public void initialize() {
80         loadAllSps();
81     }
82 
networkConfigChange(WifiConfiguration configuration)83     public void networkConfigChange(WifiConfiguration configuration) {
84         loadAllSps();
85     }
86 
loadAllSps()87     private void loadAllSps() {
88         Log.d(OSUManager.TAG, "Loading all SPs");
89         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
90         for (WifiConfiguration config : wifiManager.getPrivilegedConfiguredNetworks()) {
91             String moTree = config.getMoTree();
92             if (moTree != null) {
93                 try {
94                     mPasspointConfigs.put(config.FQDN, new PasspointConfig(config));
95                 } catch (IOException | SAXException e) {
96                     Log.w(OSUManager.TAG, "Failed to parse MO: " + e);
97                 }
98             }
99         }
100     }
101 
getLoadedSPs()102     public Collection<HomeSP> getLoadedSPs() {
103         List<HomeSP> homeSPs = new ArrayList<>();
104         for (PasspointConfig config : mPasspointConfigs.values()) {
105             homeSPs.add(config.getHomeSP());
106         }
107         return homeSPs;
108     }
109 
getMOTree(HomeSP homeSP)110     public MOTree getMOTree(HomeSP homeSP) {
111         PasspointConfig config = mPasspointConfigs.get(homeSP.getFQDN());
112         return config != null ? config.getmMOTree() : null;
113     }
114 
launchBrowser(URL target, Network network, URL endRedirect)115     public void launchBrowser(URL target, Network network, URL endRedirect) {
116         Log.d(OSUManager.TAG, "Browser to " + target + ", land at " + endRedirect);
117 
118         final Intent intent = new Intent(
119                 ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
120         intent.putExtra(ConnectivityManager.EXTRA_NETWORK, network);
121         intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
122                 new CaptivePortal(new ICaptivePortal.Stub() {
123                     @Override
124                     public void appResponse(int response) {
125                     }
126                 }));
127         //intent.setData(Uri.parse(target.toString()));     !!! Doesn't work!
128         intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL, target.toString());
129         intent.setFlags(
130                 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
131         mContext.startActivity(intent);
132     }
133 
addSP(MOTree instanceTree)134     public HomeSP addSP(MOTree instanceTree) throws IOException, SAXException {
135         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
136         String xml = instanceTree.toXml();
137         wifiManager.addPasspointManagementObject(xml);
138         return MOManager.buildSP(xml);
139     }
140 
removeSP(String fqdn)141     public void removeSP(String fqdn) throws IOException {
142         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
143     }
144 
modifySP(HomeSP homeSP, Collection<MOData> mods)145     public HomeSP modifySP(HomeSP homeSP, Collection<MOData> mods)
146             throws IOException {
147         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
148         return null;
149     }
150 
getCurrentNetwork()151     public Network getCurrentNetwork() {
152         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
153         return wifiManager.getCurrentNetwork();
154     }
155 
getActiveWifiConfig()156     public WifiConfiguration getActiveWifiConfig() {
157         WifiInfo wifiInfo = getConnectionInfo();
158         if (wifiInfo == null) {
159             return null;
160         }
161         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
162         for (WifiConfiguration config : wifiManager.getConfiguredNetworks()) {
163             if (config.networkId == wifiInfo.getNetworkId()) {
164                 return config;
165             }
166         }
167         return null;
168     }
169 
getConnectionInfo()170     public WifiInfo getConnectionInfo() {
171         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
172         return wifiManager.getConnectionInfo();
173     }
174 
matchProviderWithCurrentNetwork(String fqdn)175     public PasspointMatch matchProviderWithCurrentNetwork(String fqdn) {
176         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
177         int ordinal = wifiManager.matchProviderWithCurrentNetwork(fqdn);
178         return ordinal >= 0 && ordinal < PasspointMatch.values().length ?
179                 PasspointMatch.values()[ordinal] : null;
180     }
181 
getWifiConfig(HomeSP homeSP)182     public WifiConfiguration getWifiConfig(HomeSP homeSP) {
183         PasspointConfig passpointConfig = mPasspointConfigs.get(homeSP.getFQDN());
184         return passpointConfig != null ? passpointConfig.getWifiConfiguration() : null;
185     }
186 
getActivePasspointNetwork()187     public WifiConfiguration getActivePasspointNetwork() {
188         PasspointConfig passpointConfig = getActivePasspointConfig();
189         return passpointConfig != null ? passpointConfig.getWifiConfiguration() : null;
190     }
191 
getActivePasspointConfig()192     private PasspointConfig getActivePasspointConfig() {
193         WifiInfo wifiInfo = getConnectionInfo();
194         if (wifiInfo == null) {
195             return null;
196         }
197 
198         for (PasspointConfig passpointConfig : mPasspointConfigs.values()) {
199             if (passpointConfig.getWifiConfiguration().networkId == wifiInfo.getNetworkId()) {
200                 return passpointConfig;
201             }
202         }
203         return null;
204     }
205 
getCurrentSP()206     public HomeSP getCurrentSP() {
207         PasspointConfig passpointConfig = getActivePasspointConfig();
208         return passpointConfig != null ? passpointConfig.getHomeSP() : null;
209     }
210 
doIconQuery(long bssid, String fileName)211     public void doIconQuery(long bssid, String fileName) {
212         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
213         Log.d("ZXZ", String.format("Icon query for %012x '%s'", bssid, fileName));
214         wifiManager.queryPasspointIcon(bssid, fileName);
215     }
216 
addNetwork(HomeSP homeSP, Map<OSUCertType, List<X509Certificate>> certs, PrivateKey privateKey, Network osuNetwork)217     public Integer addNetwork(HomeSP homeSP, Map<OSUCertType, List<X509Certificate>> certs,
218                               PrivateKey privateKey, Network osuNetwork)
219             throws IOException, GeneralSecurityException {
220 
221         List<X509Certificate> aaaTrust = certs.get(OSUCertType.AAA);
222         if (aaaTrust.isEmpty()) {
223             aaaTrust = certs.get(OSUCertType.CA);   // Get the CAs from the EST flow.
224         }
225 
226         WifiConfiguration config = ConfigBuilder.buildConfig(homeSP,
227                 aaaTrust.iterator().next(),
228                 certs.get(OSUCertType.Client), privateKey);
229 
230         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
231         int nwkId = wifiManager.addNetwork(config);
232         boolean saved = false;
233         if (nwkId >= 0) {
234             saved = wifiManager.saveConfiguration();
235         }
236         Log.d(OSUManager.TAG, "Wifi configuration " + nwkId +
237                 " " + (saved ? "saved" : "not saved"));
238 
239         if (saved) {
240             reconnect(osuNetwork, nwkId);
241             return nwkId;
242         } else {
243             return null;
244         }
245     }
246 
updateNetwork(HomeSP homeSP, X509Certificate caCert, List<X509Certificate> clientCerts, PrivateKey privateKey)247     public void updateNetwork(HomeSP homeSP, X509Certificate caCert,
248                               List<X509Certificate> clientCerts, PrivateKey privateKey)
249             throws IOException, GeneralSecurityException {
250 
251         WifiConfiguration config = getWifiConfig(homeSP);
252         if (config == null) {
253             throw new IOException("Failed to find matching network config");
254         }
255         Log.d(OSUManager.TAG, "Found matching config " + config.networkId + ", updating");
256 
257         WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
258         WifiConfiguration newConfig = ConfigBuilder.buildConfig(homeSP,
259                 caCert != null ? caCert : enterpriseConfig.getCaCertificate(),
260                 clientCerts, privateKey);
261         newConfig.networkId = config.networkId;
262 
263         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
264         wifiManager.save(newConfig, null);
265         wifiManager.saveConfiguration();
266     }
267 
268     /**
269      * Connect to an OSU provisioning network. The connection should not bring down other existing
270      * connection and the network should not be made the default network since the connection
271      * is solely for sign up and is neither intended for nor likely provides access to any
272      * generic resources.
273      *
274      * @param osuInfo The OSU info object that defines the parameters for the network. An OSU
275      *                network is either an open network, or, if the OSU NAI is set, an "OSEN"
276      *                network, which is an anonymous EAP-TLS network with special keys.
277      * @param info    An opaque string that is passed on to any user notification. The string is used
278      *                for the name of the service provider.
279      * @return an Integer holding the network-id of the just added network configuration, or null
280      * if the network existed prior to this call (was not added by the OSU infrastructure).
281      * The value will be used at the end of the OSU flow to delete the network as applicable.
282      * @throws IOException Issues:
283      *                     1. The network id is not returned. addNetwork cannot be called from here since the method
284      *                     runs in the context of the app and doesn't have the appropriate permission.
285      *                     2. The connection is not immediately usable if the network was not previously selected
286      *                     manually.
287      */
connect(OSUInfo osuInfo, final String info)288     public Integer connect(OSUInfo osuInfo, final String info) throws IOException {
289         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
290 
291         WifiConfiguration config = new WifiConfiguration();
292         config.SSID = '"' + osuInfo.getSSID() + '"';
293         if (osuInfo.getOSUBssid() != 0) {
294             config.BSSID = Utils.macToString(osuInfo.getOSUBssid());
295             Log.d(OSUManager.TAG, String.format("Setting BSSID of '%s' to %012x",
296                     osuInfo.getSSID(), osuInfo.getOSUBssid()));
297         }
298 
299         if (osuInfo.getOSUProvider().getOsuNai() == null) {
300             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
301         } else {
302             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OSEN);
303             config.allowedProtocols.set(WifiConfiguration.Protocol.OSEN);
304             config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
305             config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GTK_NOT_USED);
306             config.enterpriseConfig = new WifiEnterpriseConfig();
307             config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.UNAUTH_TLS);
308             config.enterpriseConfig.setIdentity(osuInfo.getOSUProvider().getOsuNai());
309             // !!! OSEN CA Cert???
310         }
311 
312         int networkId = wifiManager.addNetwork(config);
313         if (wifiManager.enableNetwork(networkId, true)) {
314             return networkId;
315         } else {
316             return null;
317         }
318 
319         /* sequence of addNetwork(), enableNetwork(), saveConfiguration() and reconnect()
320         wifiManager.connect(config, new WifiManager.ActionListener() {
321             @Override
322             public void onSuccess() {
323                 // Connection event comes from network change intent registered in initialize
324             }
325 
326             @Override
327             public void onFailure(int reason) {
328                 mOSUManager.notifyUser(OSUOperationStatus.ProvisioningFailure,
329                         "Cannot connect to OSU network: " + reason, info);
330             }
331         });
332         return null;
333 
334         /*
335         try {
336             int nwkID = wifiManager.addOrUpdateOSUNetwork(config);
337             if (nwkID == WifiConfiguration.INVALID_NETWORK_ID) {
338                 throw new IOException("Failed to add OSU network");
339             }
340             wifiManager.enableNetwork(nwkID, false);
341             wifiManager.reconnect();
342             return nwkID;
343         }
344         catch (SecurityException se) {
345             Log.d("ZXZ", "Blah: " + se, se);
346             wifiManager.connect(config, new WifiManager.ActionListener() {
347                 @Override
348                 public void onSuccess() {
349                     // Connection event comes from network change intent registered in initialize
350                 }
351 
352                 @Override
353                 public void onFailure(int reason) {
354                     mOSUManager.notifyUser(OSUOperationStatus.ProvisioningFailure,
355                             "Cannot connect to OSU network: " + reason, info);
356                 }
357             });
358             return null;
359         }
360         */
361     }
362 
reconnect(Network osuNetwork, int newNwkId)363     private void reconnect(Network osuNetwork, int newNwkId) {
364         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
365         if (osuNetwork != null) {
366             wifiManager.disableNetwork(osuNetwork.netId);
367         }
368         if (newNwkId != WifiConfiguration.INVALID_NETWORK_ID) {
369             wifiManager.enableNetwork(newNwkId, true);
370         }
371     }
372 
deleteNetwork(int id)373     public void deleteNetwork(int id) {
374         WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
375         wifiManager.disableNetwork(id);
376         wifiManager.forget(id, null);
377     }
378 
379     /**
380      * Set the re-authentication hold off time for the current network
381      *
382      * @param holdoff hold off time in milliseconds
383      * @param ess     set if the hold off pertains to an ESS rather than a BSS
384      */
setHoldoffTime(long holdoff, boolean ess)385     public void setHoldoffTime(long holdoff, boolean ess) {
386 
387     }
388 }
389