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