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 android.net.wifi; 18 19 import android.content.Context; 20 import android.net.wifi.WifiConfiguration.KeyMgmt; 21 import android.os.Environment; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.os.Messenger; 25 import android.util.Log; 26 27 import com.android.internal.util.AsyncChannel; 28 import com.android.internal.R; 29 import com.android.internal.util.State; 30 import com.android.internal.util.StateMachine; 31 32 import java.io.BufferedInputStream; 33 import java.io.BufferedOutputStream; 34 import java.io.DataInputStream; 35 import java.io.DataOutputStream; 36 import java.io.FileInputStream; 37 import java.io.FileOutputStream; 38 import java.io.IOException; 39 import java.net.InetAddress; 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 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 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 { 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 { 100 public boolean processMessage(Message message) { 101 switch (message.what) { 102 case WifiStateMachine.CMD_SET_AP_CONFIG: 103 mWifiApConfig = (WifiConfiguration) message.obj; 104 transitionTo(mActiveState); 105 break; 106 default: 107 return NOT_HANDLED; 108 } 109 return HANDLED; 110 } 111 } 112 113 class ActiveState extends State { 114 public void enter() { 115 new Thread(new Runnable() { 116 public void run() { 117 writeApConfiguration(mWifiApConfig); 118 sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED); 119 } 120 }).start(); 121 } 122 123 public boolean processMessage(Message message) { 124 switch (message.what) { 125 //TODO: have feedback to the user when we do this 126 //to indicate the write is currently in progress 127 case WifiStateMachine.CMD_SET_AP_CONFIG: 128 deferMessage(message); 129 break; 130 case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: 131 transitionTo(mInactiveState); 132 break; 133 default: 134 return NOT_HANDLED; 135 } 136 return HANDLED; 137 } 138 } 139 140 void loadApConfiguration() { 141 DataInputStream in = null; 142 try { 143 WifiConfiguration config = new WifiConfiguration(); 144 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 145 AP_CONFIG_FILE))); 146 147 int version = in.readInt(); 148 if (version != 1) { 149 Log.e(TAG, "Bad version on hotspot configuration file, set defaults"); 150 setDefaultApConfiguration(); 151 return; 152 } 153 config.SSID = in.readUTF(); 154 int authType = in.readInt(); 155 config.allowedKeyManagement.set(authType); 156 if (authType != KeyMgmt.NONE) { 157 config.preSharedKey = in.readUTF(); 158 } 159 mWifiApConfig = config; 160 } catch (IOException ignore) { 161 setDefaultApConfiguration(); 162 } finally { 163 if (in != null) { 164 try { 165 in.close(); 166 } catch (IOException e) {} 167 } 168 } 169 } 170 171 Messenger getMessenger() { 172 return new Messenger(getHandler()); 173 } 174 175 private void writeApConfiguration(final WifiConfiguration config) { 176 DataOutputStream out = null; 177 try { 178 out = new DataOutputStream(new BufferedOutputStream( 179 new FileOutputStream(AP_CONFIG_FILE))); 180 181 out.writeInt(AP_CONFIG_FILE_VERSION); 182 out.writeUTF(config.SSID); 183 int authType = config.getAuthType(); 184 out.writeInt(authType); 185 if(authType != KeyMgmt.NONE) { 186 out.writeUTF(config.preSharedKey); 187 } 188 } catch (IOException e) { 189 Log.e(TAG, "Error writing hotspot configuration" + e); 190 } finally { 191 if (out != null) { 192 try { 193 out.close(); 194 } catch (IOException e) {} 195 } 196 } 197 } 198 199 /* Generate a default WPA2 based configuration with a random password. 200 We are changing the Wifi Ap configuration storage from secure settings to a 201 flat file accessible only by the system. A WPA2 based default configuration 202 will keep the device secure after the update */ 203 private void setDefaultApConfiguration() { 204 WifiConfiguration config = new WifiConfiguration(); 205 config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default); 206 config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); 207 String randomUUID = UUID.randomUUID().toString(); 208 //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 209 config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13); 210 sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config); 211 } 212 } 213