blob: bcd8d03e985fcda25f08b3369c69d68825689f91 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
import android.util.Log;
import com.android.internal.R;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;
/**
* Provides API for reading/writing soft access point configuration.
*/
public class WifiApConfigStore {
private static final String TAG = "WifiApConfigStore";
private static final String DEFAULT_AP_CONFIG_FILE =
Environment.getDataDirectory() + "/misc/wifi/softap.conf";
private static final int AP_CONFIG_FILE_VERSION = 2;
private WifiConfiguration mWifiApConfig = null;
private ArrayList<Integer> mAllowed2GChannel = null;
private final Context mContext;
private final String mApConfigFile;
private final BackupManagerProxy mBackupManagerProxy;
WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy) {
this(context, backupManagerProxy, DEFAULT_AP_CONFIG_FILE);
}
WifiApConfigStore(Context context,
BackupManagerProxy backupManagerProxy,
String apConfigFile) {
mContext = context;
mBackupManagerProxy = backupManagerProxy;
mApConfigFile = apConfigFile;
String ap2GChannelListStr = mContext.getResources().getString(
R.string.config_wifi_framework_sap_2G_channel_list);
Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr);
if (ap2GChannelListStr != null) {
mAllowed2GChannel = new ArrayList<Integer>();
String channelList[] = ap2GChannelListStr.split(",");
for (String tmp : channelList) {
mAllowed2GChannel.add(Integer.parseInt(tmp));
}
}
/* Load AP configuration from persistent storage. */
mWifiApConfig = loadApConfiguration(mApConfigFile);
if (mWifiApConfig == null) {
/* Use default configuration. */
Log.d(TAG, "Fallback to use default AP configuration");
mWifiApConfig = getDefaultApConfiguration();
/* Save the default configuration to persistent storage. */
writeApConfiguration(mApConfigFile, mWifiApConfig);
}
}
/**
* Return the current soft access point configuration.
*/
public synchronized WifiConfiguration getApConfiguration() {
return mWifiApConfig;
}
/**
* Update the current soft access point configuration.
* Restore to default AP configuration if null is provided.
* This can be invoked under context of binder threads (WifiManager.setWifiApConfiguration)
* and WifiStateMachine thread (CMD_START_AP).
*/
public synchronized void setApConfiguration(WifiConfiguration config) {
if (config == null) {
mWifiApConfig = getDefaultApConfiguration();
} else {
mWifiApConfig = config;
}
writeApConfiguration(mApConfigFile, mWifiApConfig);
// Stage the backup of the SettingsProvider package which backs this up
mBackupManagerProxy.notifyDataChanged();
}
public ArrayList<Integer> getAllowed2GChannel() {
return mAllowed2GChannel;
}
/**
* Load AP configuration from persistent storage.
*/
private static WifiConfiguration loadApConfiguration(final String filename) {
WifiConfiguration config = null;
DataInputStream in = null;
try {
config = new WifiConfiguration();
in = new DataInputStream(
new BufferedInputStream(new FileInputStream(filename)));
int version = in.readInt();
if ((version != 1) && (version != 2)) {
Log.e(TAG, "Bad version on hotspot configuration file");
return null;
}
config.SSID = in.readUTF();
if (version >= 2) {
config.apBand = in.readInt();
config.apChannel = in.readInt();
}
int authType = in.readInt();
config.allowedKeyManagement.set(authType);
if (authType != KeyMgmt.NONE) {
config.preSharedKey = in.readUTF();
}
} catch (IOException e) {
Log.e(TAG, "Error reading hotspot configuration " + e);
config = null;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e(TAG, "Error closing hotspot configuration during read" + e);
}
}
}
return config;
}
/**
* Write AP configuration to persistent storage.
*/
private static void writeApConfiguration(final String filename,
final WifiConfiguration config) {
try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(filename)))) {
out.writeInt(AP_CONFIG_FILE_VERSION);
out.writeUTF(config.SSID);
out.writeInt(config.apBand);
out.writeInt(config.apChannel);
int authType = config.getAuthType();
out.writeInt(authType);
if (authType != KeyMgmt.NONE) {
out.writeUTF(config.preSharedKey);
}
} catch (IOException e) {
Log.e(TAG, "Error writing hotspot configuration" + e);
}
}
/**
* Generate a default WPA2 based configuration with a random password.
* We are changing the Wifi Ap configuration storage from secure settings to a
* flat file accessible only by the system. A WPA2 based default configuration
* will keep the device secure after the update.
*/
private WifiConfiguration getDefaultApConfiguration() {
WifiConfiguration config = new WifiConfiguration();
config.SSID = mContext.getResources().getString(
R.string.wifi_tether_configure_ssid_default);
config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
String randomUUID = UUID.randomUUID().toString();
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
return config;
}
}