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 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