1 /* 2 * Copyright (C) 2010 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.content.Context; 20 import android.net.wifi.WifiConfiguration; 21 import android.net.wifi.WifiConfiguration.KeyMgmt; 22 import android.os.Environment; 23 import android.util.Log; 24 25 import com.android.internal.R; 26 27 import java.io.BufferedInputStream; 28 import java.io.BufferedOutputStream; 29 import java.io.DataInputStream; 30 import java.io.DataOutputStream; 31 import java.io.FileInputStream; 32 import java.io.FileOutputStream; 33 import java.io.IOException; 34 import java.util.ArrayList; 35 import java.util.UUID; 36 37 /** 38 * Provides API for reading/writing soft access point configuration. 39 */ 40 public class WifiApConfigStore { 41 42 private static final String TAG = "WifiApConfigStore"; 43 44 private static final String DEFAULT_AP_CONFIG_FILE = 45 Environment.getDataDirectory() + "/misc/wifi/softap.conf"; 46 47 private static final int AP_CONFIG_FILE_VERSION = 2; 48 49 private WifiConfiguration mWifiApConfig = null; 50 51 private ArrayList<Integer> mAllowed2GChannel = null; 52 53 private final Context mContext; 54 private final String mApConfigFile; 55 private final BackupManagerProxy mBackupManagerProxy; 56 WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy)57 WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy) { 58 this(context, backupManagerProxy, DEFAULT_AP_CONFIG_FILE); 59 } 60 WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy, String apConfigFile)61 WifiApConfigStore(Context context, 62 BackupManagerProxy backupManagerProxy, 63 String apConfigFile) { 64 mContext = context; 65 mBackupManagerProxy = backupManagerProxy; 66 mApConfigFile = apConfigFile; 67 68 String ap2GChannelListStr = mContext.getResources().getString( 69 R.string.config_wifi_framework_sap_2G_channel_list); 70 Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr); 71 72 if (ap2GChannelListStr != null) { 73 mAllowed2GChannel = new ArrayList<Integer>(); 74 String channelList[] = ap2GChannelListStr.split(","); 75 for (String tmp : channelList) { 76 mAllowed2GChannel.add(Integer.parseInt(tmp)); 77 } 78 } 79 80 /* Load AP configuration from persistent storage. */ 81 mWifiApConfig = loadApConfiguration(mApConfigFile); 82 if (mWifiApConfig == null) { 83 /* Use default configuration. */ 84 Log.d(TAG, "Fallback to use default AP configuration"); 85 mWifiApConfig = getDefaultApConfiguration(); 86 87 /* Save the default configuration to persistent storage. */ 88 writeApConfiguration(mApConfigFile, mWifiApConfig); 89 } 90 } 91 92 /** 93 * Return the current soft access point configuration. 94 */ getApConfiguration()95 public synchronized WifiConfiguration getApConfiguration() { 96 return mWifiApConfig; 97 } 98 99 /** 100 * Update the current soft access point configuration. 101 * Restore to default AP configuration if null is provided. 102 * This can be invoked under context of binder threads (WifiManager.setWifiApConfiguration) 103 * and WifiStateMachine thread (CMD_START_AP). 104 */ setApConfiguration(WifiConfiguration config)105 public synchronized void setApConfiguration(WifiConfiguration config) { 106 if (config == null) { 107 mWifiApConfig = getDefaultApConfiguration(); 108 } else { 109 mWifiApConfig = config; 110 } 111 writeApConfiguration(mApConfigFile, mWifiApConfig); 112 113 // Stage the backup of the SettingsProvider package which backs this up 114 mBackupManagerProxy.notifyDataChanged(); 115 } 116 getAllowed2GChannel()117 public ArrayList<Integer> getAllowed2GChannel() { 118 return mAllowed2GChannel; 119 } 120 121 /** 122 * Load AP configuration from persistent storage. 123 */ loadApConfiguration(final String filename)124 private static WifiConfiguration loadApConfiguration(final String filename) { 125 WifiConfiguration config = null; 126 DataInputStream in = null; 127 try { 128 config = new WifiConfiguration(); 129 in = new DataInputStream( 130 new BufferedInputStream(new FileInputStream(filename))); 131 132 int version = in.readInt(); 133 if ((version != 1) && (version != 2)) { 134 Log.e(TAG, "Bad version on hotspot configuration file"); 135 return null; 136 } 137 config.SSID = in.readUTF(); 138 139 if (version >= 2) { 140 config.apBand = in.readInt(); 141 config.apChannel = in.readInt(); 142 } 143 144 int authType = in.readInt(); 145 config.allowedKeyManagement.set(authType); 146 if (authType != KeyMgmt.NONE) { 147 config.preSharedKey = in.readUTF(); 148 } 149 } catch (IOException e) { 150 Log.e(TAG, "Error reading hotspot configuration " + e); 151 config = null; 152 } finally { 153 if (in != null) { 154 try { 155 in.close(); 156 } catch (IOException e) { 157 Log.e(TAG, "Error closing hotspot configuration during read" + e); 158 } 159 } 160 } 161 return config; 162 } 163 164 /** 165 * Write AP configuration to persistent storage. 166 */ writeApConfiguration(final String filename, final WifiConfiguration config)167 private static void writeApConfiguration(final String filename, 168 final WifiConfiguration config) { 169 try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream( 170 new FileOutputStream(filename)))) { 171 out.writeInt(AP_CONFIG_FILE_VERSION); 172 out.writeUTF(config.SSID); 173 out.writeInt(config.apBand); 174 out.writeInt(config.apChannel); 175 int authType = config.getAuthType(); 176 out.writeInt(authType); 177 if (authType != KeyMgmt.NONE) { 178 out.writeUTF(config.preSharedKey); 179 } 180 } catch (IOException e) { 181 Log.e(TAG, "Error writing hotspot configuration" + e); 182 } 183 } 184 185 /** 186 * Generate a default WPA2 based configuration with a random password. 187 * We are changing the Wifi Ap configuration storage from secure settings to a 188 * flat file accessible only by the system. A WPA2 based default configuration 189 * will keep the device secure after the update. 190 */ getDefaultApConfiguration()191 private WifiConfiguration getDefaultApConfiguration() { 192 WifiConfiguration config = new WifiConfiguration(); 193 config.SSID = mContext.getResources().getString( 194 R.string.wifi_tether_configure_ssid_default); 195 config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); 196 String randomUUID = UUID.randomUUID().toString(); 197 //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 198 config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13); 199 return config; 200 } 201 } 202