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