1 /* 2 * Copyright (C) 2019 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.MacAddress; 21 import android.net.wifi.SoftApConfiguration; 22 import android.net.wifi.WifiConfiguration; 23 import android.net.wifi.WifiMigration; 24 import android.util.BackupUtils; 25 import android.util.Log; 26 27 import com.android.server.wifi.util.ApConfigUtil; 28 import com.android.server.wifi.util.SettingsMigrationDataHolder; 29 30 import java.io.ByteArrayInputStream; 31 import java.io.ByteArrayOutputStream; 32 import java.io.DataInputStream; 33 import java.io.DataOutputStream; 34 import java.io.IOException; 35 import java.util.ArrayList; 36 import java.util.Iterator; 37 import java.util.List; 38 39 /** 40 * Class used to backup/restore data using the SettingsBackupAgent. 41 * There are 2 symmetric API's exposed here: 42 * 1. retrieveBackupDataFromSoftApConfiguration: Retrieve the configuration data to be backed up. 43 * 2. retrieveSoftApConfigurationFromBackupData: Restore the configuration using the provided data. 44 * The byte stream to be backed up is versioned to migrate the data easily across 45 * revisions. 46 */ 47 public class SoftApBackupRestore { 48 private static final String TAG = "SoftApBackupRestore"; 49 50 /** 51 * Current backup data version. 52 */ 53 private static final int CURRENT_SAP_BACKUP_DATA_VERSION = 7; 54 55 private static final int ETHER_ADDR_LEN = 6; // Byte array size of MacAddress 56 57 private final Context mContext; 58 private final SettingsMigrationDataHolder mSettingsMigrationDataHolder; 59 SoftApBackupRestore(Context context, SettingsMigrationDataHolder settingsMigrationDataHolder)60 public SoftApBackupRestore(Context context, 61 SettingsMigrationDataHolder settingsMigrationDataHolder) { 62 mContext = context; 63 mSettingsMigrationDataHolder = settingsMigrationDataHolder; 64 } 65 66 /** 67 * Retrieve a byte stream representing the data that needs to be backed up from the 68 * provided softap configuration. 69 * 70 * @param config saved soft ap config that needs to be backed up. 71 * @return Raw byte stream that needs to be backed up. 72 */ retrieveBackupDataFromSoftApConfiguration(SoftApConfiguration config)73 public byte[] retrieveBackupDataFromSoftApConfiguration(SoftApConfiguration config) { 74 if (config == null) { 75 Log.e(TAG, "Invalid configuration received"); 76 return new byte[0]; 77 } 78 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 79 try { 80 DataOutputStream out = new DataOutputStream(baos); 81 82 out.writeInt(CURRENT_SAP_BACKUP_DATA_VERSION); 83 BackupUtils.writeString(out, config.getSsid()); 84 out.writeInt(config.getBand()); 85 out.writeInt(config.getChannel()); 86 BackupUtils.writeString(out, config.getPassphrase()); 87 out.writeInt(config.getSecurityType()); 88 out.writeBoolean(config.isHiddenSsid()); 89 out.writeInt(config.getMaxNumberOfClients()); 90 out.writeLong(config.getShutdownTimeoutMillis()); 91 out.writeBoolean(config.isClientControlByUserEnabled()); 92 writeMacAddressList(out, config.getBlockedClientList()); 93 writeMacAddressList(out, config.getAllowedClientList()); 94 out.writeBoolean(config.isAutoShutdownEnabled()); 95 } catch (IOException io) { 96 Log.e(TAG, "Invalid configuration received, IOException " + io); 97 return new byte[0]; 98 } 99 return baos.toByteArray(); 100 } 101 102 /** 103 * Parse out the configurations from the back up data. 104 * 105 * @param data raw byte stream representing the data. 106 * @return Soft ap config retrieved from the backed up data. 107 */ retrieveSoftApConfigurationFromBackupData(byte[] data)108 public SoftApConfiguration retrieveSoftApConfigurationFromBackupData(byte[] data) { 109 if (data == null || data.length == 0) { 110 Log.e(TAG, "Invalid backup data received"); 111 return null; 112 } 113 SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); 114 try { 115 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); 116 int version = in.readInt(); 117 if (version < 1 || version > CURRENT_SAP_BACKUP_DATA_VERSION) { 118 throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); 119 } 120 121 if (version == 1) return null; // Version 1 is a bad dataset. 122 123 configBuilder.setSsid(BackupUtils.readString(in)); 124 125 int band; 126 if (version < 4) { 127 band = ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(in.readInt()); 128 } else { 129 band = in.readInt(); 130 } 131 int channel = in.readInt(); 132 133 if (channel == 0) { 134 configBuilder.setBand(band); 135 } else { 136 configBuilder.setChannel(channel, band); 137 } 138 String passphrase = BackupUtils.readString(in); 139 int securityType = in.readInt(); 140 if (version < 4 && securityType == WifiConfiguration.KeyMgmt.WPA2_PSK) { 141 configBuilder.setPassphrase(passphrase, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 142 } else if (version >= 4 && securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) { 143 configBuilder.setPassphrase(passphrase, securityType); 144 } 145 if (version >= 3) { 146 configBuilder.setHiddenSsid(in.readBoolean()); 147 } 148 if (version >= 5) { 149 configBuilder.setMaxNumberOfClients(in.readInt()); 150 if (version >= 7) { 151 configBuilder.setShutdownTimeoutMillis(in.readLong()); 152 } else { 153 configBuilder.setShutdownTimeoutMillis(Long.valueOf(in.readInt())); 154 } 155 configBuilder.setClientControlByUserEnabled(in.readBoolean()); 156 int numberOfBlockedClient = in.readInt(); 157 List<MacAddress> blockedList = new ArrayList<>( 158 macAddressListFromByteArray(in, numberOfBlockedClient)); 159 int numberOfAllowedClient = in.readInt(); 160 List<MacAddress> allowedList = new ArrayList<>( 161 macAddressListFromByteArray(in, numberOfAllowedClient)); 162 configBuilder.setBlockedClientList(blockedList); 163 configBuilder.setAllowedClientList(allowedList); 164 } 165 if (version >= 6) { 166 configBuilder.setAutoShutdownEnabled(in.readBoolean()); 167 } else { 168 // Migrate data out of settings. 169 WifiMigration.SettingsMigrationData migrationData = 170 mSettingsMigrationDataHolder.retrieveData(); 171 if (migrationData == null) { 172 Log.e(TAG, "No migration data present"); 173 } else { 174 configBuilder.setAutoShutdownEnabled(migrationData.isSoftApTimeoutEnabled()); 175 } 176 } 177 } catch (IOException io) { 178 Log.e(TAG, "Invalid backup data received, IOException: " + io); 179 return null; 180 } catch (BackupUtils.BadVersionException badVersion) { 181 Log.e(TAG, "Invalid backup data received, BadVersionException: " + badVersion); 182 return null; 183 } catch (IllegalArgumentException ie) { 184 Log.e(TAG, "Invalid backup data received, IllegalArgumentException " + ie); 185 return null; 186 } 187 return configBuilder.build(); 188 } 189 writeMacAddressList(DataOutputStream out, List<MacAddress> macList)190 private void writeMacAddressList(DataOutputStream out, List<MacAddress> macList) 191 throws IOException { 192 out.writeInt(macList.size()); 193 Iterator<MacAddress> iterator = macList.iterator(); 194 while (iterator.hasNext()) { 195 byte[] mac = iterator.next().toByteArray(); 196 out.write(mac, 0, ETHER_ADDR_LEN); 197 } 198 } 199 macAddressListFromByteArray(DataInputStream in, int numberOfClients)200 private List<MacAddress> macAddressListFromByteArray(DataInputStream in, int numberOfClients) 201 throws IOException { 202 List<MacAddress> macList = new ArrayList<>(); 203 for (int i = 0; i < numberOfClients; i++) { 204 byte[] mac = new byte[ETHER_ADDR_LEN]; 205 in.read(mac, 0, ETHER_ADDR_LEN); 206 macList.add(MacAddress.fromBytes(mac)); 207 } 208 return macList; 209 } 210 } 211