Home | History | Annotate | Download | only in wifi
      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