1155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande/* 2155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Copyright (C) 2010 The Android Open Source Project 3155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 4155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Licensed under the Apache License, Version 2.0 (the "License"); 5155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * you may not use this file except in compliance with the License. 6155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * You may obtain a copy of the License at 7155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 8155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * http://www.apache.org/licenses/LICENSE-2.0 9155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 10155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Unless required by applicable law or agreed to in writing, software 11155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * distributed under the License is distributed on an "AS IS" BASIS, 12155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * See the License for the specific language governing permissions and 14155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * limitations under the License. 15155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 16155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 17155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandepackage com.android.server.wifi; 18155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 19155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.Context; 20155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.net.wifi.WifiConfiguration; 21155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.net.wifi.WifiConfiguration.KeyMgmt; 22155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.os.Environment; 23155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.util.Log; 24155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 25155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport com.android.internal.R; 26155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 27155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.BufferedInputStream; 28155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.BufferedOutputStream; 29155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.DataInputStream; 30155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.DataOutputStream; 31155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.FileInputStream; 32155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.FileOutputStream; 33155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.IOException; 3452b6d4cbf2815d18f35c64af955bf3859907b5c1xinheimport java.util.ArrayList; 35155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.util.UUID; 36155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 37155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande/** 38c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Provides API for reading/writing soft access point configuration. 39155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 40c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiupublic class WifiApConfigStore { 41155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 42155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private static final String TAG = "WifiApConfigStore"; 43155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 44c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private static final String DEFAULT_AP_CONFIG_FILE = 45c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu Environment.getDataDirectory() + "/misc/wifi/softap.conf"; 46155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 470e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe private static final int AP_CONFIG_FILE_VERSION = 2; 48155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 49155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private WifiConfiguration mWifiApConfig = null; 50155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 51c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private ArrayList<Integer> mAllowed2GChannel = null; 52c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu 53c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private final Context mContext; 54c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private final String mApConfigFile; 55750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu private final BackupManagerProxy mBackupManagerProxy; 56c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu 57750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy) { 58750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu this(context, backupManagerProxy, DEFAULT_AP_CONFIG_FILE); 59c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } 60155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 61750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu WifiApConfigStore(Context context, 62750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu BackupManagerProxy backupManagerProxy, 63750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu String apConfigFile) { 64155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mContext = context; 65750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu mBackupManagerProxy = backupManagerProxy; 66c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mApConfigFile = apConfigFile; 67155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 68eee1d479d8d402a2e78e2f143e957030cfc77749Vinit Deshpande String ap2GChannelListStr = mContext.getResources().getString( 69eee1d479d8d402a2e78e2f143e957030cfc77749Vinit Deshpande R.string.config_wifi_framework_sap_2G_channel_list); 7052b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr); 7152b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe 7252b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe if (ap2GChannelListStr != null) { 73c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mAllowed2GChannel = new ArrayList<Integer>(); 7452b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe String channelList[] = ap2GChannelListStr.split(","); 7552b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe for (String tmp : channelList) { 76c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mAllowed2GChannel.add(Integer.parseInt(tmp)); 7752b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe } 7852b6d4cbf2815d18f35c64af955bf3859907b5c1xinhe } 79155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 80c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /* Load AP configuration from persistent storage. */ 81c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mWifiApConfig = loadApConfiguration(mApConfigFile); 82c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu if (mWifiApConfig == null) { 83c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /* Use default configuration. */ 84c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu Log.d(TAG, "Fallback to use default AP configuration"); 85c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mWifiApConfig = getDefaultApConfiguration(); 86155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 87c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /* Save the default configuration to persistent storage. */ 88c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu writeApConfiguration(mApConfigFile, mWifiApConfig); 89155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 90155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 91155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 92c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /** 93c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Return the current soft access point configuration. 94c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu */ 95c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu public synchronized WifiConfiguration getApConfiguration() { 96c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu return mWifiApConfig; 97155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 98155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 99c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /** 100c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Update the current soft access point configuration. 101c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Restore to default AP configuration if null is provided. 102c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * This can be invoked under context of binder threads (WifiManager.setWifiApConfiguration) 103c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * and WifiStateMachine thread (CMD_START_AP). 104c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu */ 105c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu public synchronized void setApConfiguration(WifiConfiguration config) { 106c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu if (config == null) { 107c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mWifiApConfig = getDefaultApConfiguration(); 108c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } else { 109c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu mWifiApConfig = config; 110155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 111c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu writeApConfiguration(mApConfigFile, mWifiApConfig); 112750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu 113c11476cd6b68ba6c5b34c99ea312c45e18a17658Ritesh Reddy // Stage the backup of the SettingsProvider package which backs this up 114750c6962838af6ab7ba034c80f2d325df7e74cbePeter Qiu mBackupManagerProxy.notifyDataChanged(); 115c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } 116155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 117c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu public ArrayList<Integer> getAllowed2GChannel() { 118c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu return mAllowed2GChannel; 119155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 120155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 121c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /** 122c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Load AP configuration from persistent storage. 123c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu */ 124c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private static WifiConfiguration loadApConfiguration(final String filename) { 125c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu WifiConfiguration config = null; 126155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande DataInputStream in = null; 127155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande try { 128c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu config = new WifiConfiguration(); 129c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu in = new DataInputStream( 130c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu new BufferedInputStream(new FileInputStream(filename))); 131155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 132155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande int version = in.readInt(); 1330e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe if ((version != 1) && (version != 2)) { 134c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu Log.e(TAG, "Bad version on hotspot configuration file"); 135c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu return null; 136155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 137155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande config.SSID = in.readUTF(); 1380e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe 1390e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe if (version >= 2) { 1400e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe config.apBand = in.readInt(); 1410e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe config.apChannel = in.readInt(); 1420e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe } 1430e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe 144155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande int authType = in.readInt(); 145155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande config.allowedKeyManagement.set(authType); 146155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (authType != KeyMgmt.NONE) { 147155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande config.preSharedKey = in.readUTF(); 148155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 149c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } catch (IOException e) { 150c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu Log.e(TAG, "Error reading hotspot configuration " + e); 151c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu config = null; 152155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } finally { 153155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (in != null) { 154155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande try { 155155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande in.close(); 156c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } catch (IOException e) { 157c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu Log.e(TAG, "Error closing hotspot configuration during read" + e); 158c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu } 159155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 160155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 161c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu return config; 162155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 163155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 164c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /** 165c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Write AP configuration to persistent storage. 166c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu */ 167b2c2f85c959cb0deba238b566f39b1b942eb70a8Ningyuan Wang private static void writeApConfiguration(final String filename, 168b2c2f85c959cb0deba238b566f39b1b942eb70a8Ningyuan Wang final WifiConfiguration config) { 169b2c2f85c959cb0deba238b566f39b1b942eb70a8Ningyuan Wang try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream( 170b2c2f85c959cb0deba238b566f39b1b942eb70a8Ningyuan Wang new FileOutputStream(filename)))) { 171155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande out.writeInt(AP_CONFIG_FILE_VERSION); 172155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande out.writeUTF(config.SSID); 1730e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe out.writeInt(config.apBand); 1740e8f0d87d62589d9dda54d5a4941d0309e3ecf2axinhe out.writeInt(config.apChannel); 175155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande int authType = config.getAuthType(); 176155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande out.writeInt(authType); 177c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu if (authType != KeyMgmt.NONE) { 178155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande out.writeUTF(config.preSharedKey); 179155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 180155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } catch (IOException e) { 181155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande Log.e(TAG, "Error writing hotspot configuration" + e); 182155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 183155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 184155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 185c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu /** 186c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * Generate a default WPA2 based configuration with a random password. 187c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * We are changing the Wifi Ap configuration storage from secure settings to a 188c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * flat file accessible only by the system. A WPA2 based default configuration 189c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu * will keep the device secure after the update. 190c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu */ 191c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu private WifiConfiguration getDefaultApConfiguration() { 192155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiConfiguration config = new WifiConfiguration(); 193eee1d479d8d402a2e78e2f143e957030cfc77749Vinit Deshpande config.SSID = mContext.getResources().getString( 194eee1d479d8d402a2e78e2f143e957030cfc77749Vinit Deshpande R.string.wifi_tether_configure_ssid_default); 195155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); 196155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande String randomUUID = UUID.randomUUID().toString(); 197155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 198c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13); 199c79666b79e273ceaa2f74090b02ca6cf83c61387Peter Qiu return config; 200155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 201155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande} 202