WifiApConfigStore.java revision 52b6d4cbf2815d18f35c64af955bf3859907b5c1
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
17package com.android.server.wifi;
18
19import android.content.Context;
20import android.net.wifi.WifiConfiguration;
21import android.net.wifi.WifiConfiguration.KeyMgmt;
22import android.os.Environment;
23import android.os.Handler;
24import android.os.Message;
25import android.os.Messenger;
26import android.util.Log;
27
28import com.android.internal.util.AsyncChannel;
29import com.android.internal.R;
30import com.android.internal.util.State;
31import com.android.internal.util.StateMachine;
32
33import java.io.BufferedInputStream;
34import java.io.BufferedOutputStream;
35import java.io.DataInputStream;
36import java.io.DataOutputStream;
37import java.io.FileInputStream;
38import java.io.FileOutputStream;
39import java.io.IOException;
40import java.util.ArrayList;
41import java.util.UUID;
42
43/**
44 * Provides API to the WifiStateMachine for doing read/write access
45 * to soft access point configuration
46 */
47class WifiApConfigStore extends StateMachine {
48
49    private Context mContext;
50    private static final String TAG = "WifiApConfigStore";
51
52    private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
53        "/misc/wifi/softap.conf";
54
55    private static final int AP_CONFIG_FILE_VERSION = 2;
56
57    private State mDefaultState = new DefaultState();
58    private State mInactiveState = new InactiveState();
59    private State mActiveState = new ActiveState();
60
61    private WifiConfiguration mWifiApConfig = null;
62    private AsyncChannel mReplyChannel = new AsyncChannel();
63    public ArrayList <Integer> allowed2GChannel = null;
64
65    WifiApConfigStore(Context context, Handler target) {
66        super(TAG, target.getLooper());
67
68        mContext = context;
69        addState(mDefaultState);
70            addState(mInactiveState, mDefaultState);
71            addState(mActiveState, mDefaultState);
72
73        setInitialState(mInactiveState);
74        String ap2GChannelListStr = (mContext.getResources().getString(
75                R.string.config_wifi_framework_sap_2G_channel_list));
76        Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr);
77
78        if (ap2GChannelListStr != null) {
79            allowed2GChannel = new ArrayList<Integer>();
80            String channelList[] = ap2GChannelListStr.split(",");
81            for (String tmp : channelList) {
82                allowed2GChannel.add(Integer.parseInt(tmp));
83            }
84        }
85    }
86
87    public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
88        WifiApConfigStore s = new WifiApConfigStore(context, target);
89        s.start();
90        return s;
91    }
92
93    class DefaultState extends State {
94        public boolean processMessage(Message message) {
95            switch (message.what) {
96                case WifiStateMachine.CMD_SET_AP_CONFIG:
97                case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
98                    Log.e(TAG, "Unexpected message: " + message);
99                    break;
100                case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
101                    mReplyChannel.replyToMessage(message,
102                            WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
103                    break;
104                default:
105                    Log.e(TAG, "Failed to handle " + message);
106                    break;
107            }
108            return HANDLED;
109        }
110    }
111
112    class InactiveState extends State {
113        public boolean processMessage(Message message) {
114            switch (message.what) {
115                case WifiStateMachine.CMD_SET_AP_CONFIG:
116                     WifiConfiguration config = (WifiConfiguration)message.obj;
117                    if (config.SSID != null) {
118                        mWifiApConfig = config;
119                        transitionTo(mActiveState);
120                    } else {
121                        Log.e(TAG, "Try to setup AP config without SSID: " + message);
122                    }
123                    break;
124                default:
125                    return NOT_HANDLED;
126            }
127            return HANDLED;
128        }
129    }
130
131    class ActiveState extends State {
132        public void enter() {
133            new Thread(new Runnable() {
134                public void run() {
135                    writeApConfiguration(mWifiApConfig);
136                    sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
137                }
138            }).start();
139        }
140
141        public boolean processMessage(Message message) {
142            switch (message.what) {
143                //TODO: have feedback to the user when we do this
144                //to indicate the write is currently in progress
145                case WifiStateMachine.CMD_SET_AP_CONFIG:
146                    deferMessage(message);
147                    break;
148                case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
149                    transitionTo(mInactiveState);
150                    break;
151                default:
152                    return NOT_HANDLED;
153            }
154            return HANDLED;
155        }
156    }
157
158    void loadApConfiguration() {
159        DataInputStream in = null;
160        try {
161            WifiConfiguration config = new WifiConfiguration();
162            in = new DataInputStream(new BufferedInputStream(new FileInputStream(
163                            AP_CONFIG_FILE)));
164
165            int version = in.readInt();
166            if ((version != 1) && (version != 2)) {
167                Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
168                setDefaultApConfiguration();
169                return;
170            }
171            config.SSID = in.readUTF();
172
173            if (version >= 2) {
174                config.apBand = in.readInt();
175                config.apChannel = in.readInt();
176            }
177
178            int authType = in.readInt();
179            config.allowedKeyManagement.set(authType);
180            if (authType != KeyMgmt.NONE) {
181                config.preSharedKey = in.readUTF();
182            }
183
184            mWifiApConfig = config;
185        } catch (IOException ignore) {
186            setDefaultApConfiguration();
187        } finally {
188            if (in != null) {
189                try {
190                    in.close();
191                } catch (IOException e) {}
192            }
193        }
194    }
195
196    Messenger getMessenger() {
197        return new Messenger(getHandler());
198    }
199
200    private void writeApConfiguration(final WifiConfiguration config) {
201        DataOutputStream out = null;
202        try {
203            out = new DataOutputStream(new BufferedOutputStream(
204                        new FileOutputStream(AP_CONFIG_FILE)));
205
206            out.writeInt(AP_CONFIG_FILE_VERSION);
207            out.writeUTF(config.SSID);
208            out.writeInt(config.apBand);
209            out.writeInt(config.apChannel);
210            int authType = config.getAuthType();
211            out.writeInt(authType);
212            if(authType != KeyMgmt.NONE) {
213                out.writeUTF(config.preSharedKey);
214            }
215        } catch (IOException e) {
216            Log.e(TAG, "Error writing hotspot configuration" + e);
217        } finally {
218            if (out != null) {
219                try {
220                    out.close();
221                } catch (IOException e) {}
222            }
223        }
224    }
225
226    /* Generate a default WPA2 based configuration with a random password.
227       We are changing the Wifi Ap configuration storage from secure settings to a
228       flat file accessible only by the system. A WPA2 based default configuration
229       will keep the device secure after the update */
230    private void setDefaultApConfiguration() {
231        WifiConfiguration config = new WifiConfiguration();
232        config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
233        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
234        String randomUUID = UUID.randomUUID().toString();
235        //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
236        config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
237        sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
238    }
239}
240