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