• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Handler;
24 import android.os.Message;
25 import android.os.Messenger;
26 import android.util.Log;
27 
28 import com.android.internal.util.AsyncChannel;
29 import com.android.internal.R;
30 import com.android.internal.util.State;
31 import com.android.internal.util.StateMachine;
32 
33 import java.io.BufferedInputStream;
34 import java.io.BufferedOutputStream;
35 import java.io.DataInputStream;
36 import java.io.DataOutputStream;
37 import java.io.FileInputStream;
38 import java.io.FileOutputStream;
39 import java.io.IOException;
40 import java.util.ArrayList;
41 import java.util.UUID;
42 
43 /**
44  * Provides API to the WifiStateMachine for doing read/write access
45  * to soft access point configuration
46  */
47 class 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 
WifiApConfigStore(Context context, Handler target)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 
makeWifiApConfigStore(Context context, Handler target)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 {
processMessage(Message message)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 {
processMessage(Message message)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 {
enter()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 
processMessage(Message message)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 
loadApConfiguration()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 
getMessenger()196     Messenger getMessenger() {
197         return new Messenger(getHandler());
198     }
199 
writeApConfiguration(final WifiConfiguration config)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 */
setDefaultApConfiguration()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