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 com.android.internal.util.AsyncChannel; 20 import com.android.internal.util.State; 21 import com.android.internal.util.StateMachine; 22 23 import android.content.Context; 24 import android.content.Intent; 25 import android.net.wifi.StateChangeResult; 26 import android.net.wifi.WpsResult.Status; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.os.Parcelable; 30 import android.util.Log; 31 32 /** 33 * Manages a WPS connection. 34 * 35 * WPS consists as a series of EAP exchange triggered 36 * by a user action that leads to a successful connection 37 * after automatic creation of configuration in the 38 * supplicant. We currently support the following methods 39 * of WPS setup 40 * 1. Pin method: Pin can be either obtained from the device 41 * or from the access point to connect to. 42 * 2. Push button method: This involves pushing a button on 43 * the access point and the device 44 * 45 * After a successful WPS setup, the state machine 46 * reloads the configuration and updates the IP and proxy 47 * settings, if any. 48 */ 49 class WpsStateMachine extends StateMachine { 50 51 private static final String TAG = "WpsStateMachine"; 52 private static final boolean DBG = false; 53 54 private WifiStateMachine mWifiStateMachine; 55 56 private WpsInfo mWpsInfo; 57 58 private Context mContext; 59 AsyncChannel mReplyChannel = new AsyncChannel(); 60 61 private State mDefaultState = new DefaultState(); 62 private State mInactiveState = new InactiveState(); 63 private State mActiveState = new ActiveState(); 64 65 public WpsStateMachine(Context context, WifiStateMachine wsm, Handler target) { 66 super(TAG, target.getLooper()); 67 68 mContext = context; 69 mWifiStateMachine = wsm; 70 addState(mDefaultState); 71 addState(mInactiveState, mDefaultState); 72 addState(mActiveState, mDefaultState); 73 74 setInitialState(mInactiveState); 75 76 //start the state machine 77 start(); 78 } 79 80 81 /******************************************************** 82 * HSM states 83 *******************************************************/ 84 85 class DefaultState extends State { 86 @Override 87 public void enter() { 88 if (DBG) Log.d(TAG, getName() + "\n"); 89 } 90 @Override 91 public boolean processMessage(Message message) { 92 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 93 WpsInfo wpsConfig; 94 switch (message.what) { 95 case WifiStateMachine.CMD_START_WPS: 96 mWpsInfo = (WpsInfo) message.obj; 97 WpsResult result; 98 switch (mWpsInfo.setup) { 99 case WpsInfo.PBC: 100 result = WifiConfigStore.startWpsPbc(mWpsInfo); 101 break; 102 case WpsInfo.KEYPAD: 103 result = WifiConfigStore.startWpsWithPinFromAccessPoint(mWpsInfo); 104 break; 105 case WpsInfo.DISPLAY: 106 result = WifiConfigStore.startWpsWithPinFromDevice(mWpsInfo); 107 break; 108 default: 109 result = new WpsResult(Status.FAILURE); 110 Log.e(TAG, "Invalid setup for WPS"); 111 break; 112 } 113 mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED, result); 114 if (result.status == Status.SUCCESS) { 115 transitionTo(mActiveState); 116 } else { 117 Log.e(TAG, "Failed to start WPS with config " + mWpsInfo.toString()); 118 } 119 break; 120 case WifiStateMachine.CMD_RESET_WPS_STATE: 121 transitionTo(mInactiveState); 122 break; 123 default: 124 Log.e(TAG, "Failed to handle " + message); 125 break; 126 } 127 return HANDLED; 128 } 129 } 130 131 class ActiveState extends State { 132 @Override 133 public void enter() { 134 if (DBG) Log.d(TAG, getName() + "\n"); 135 } 136 137 @Override 138 public boolean processMessage(Message message) { 139 boolean retValue = HANDLED; 140 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 141 switch (message.what) { 142 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 143 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 144 SupplicantState supState = (SupplicantState) stateChangeResult.state; 145 switch (supState) { 146 case COMPLETED: 147 /* During WPS setup, all other networks are disabled. After 148 * a successful connect a new config is created in the supplicant. 149 * 150 * We need to enable all networks after a successful connection 151 * and the configuration list needs to be reloaded from the supplicant. 152 */ 153 Log.d(TAG, "WPS set up successful"); 154 WifiConfigStore.enableAllNetworks(); 155 WifiConfigStore.loadConfiguredNetworks(); 156 WifiConfigStore.updateIpAndProxyFromWpsConfig( 157 stateChangeResult.networkId, mWpsInfo); 158 mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT); 159 transitionTo(mInactiveState); 160 break; 161 case INACTIVE: 162 /* A failed WPS connection */ 163 Log.d(TAG, "WPS set up failed, enabling other networks"); 164 WifiConfigStore.enableAllNetworks(); 165 mWifiStateMachine.sendMessage(WifiStateMachine.WPS_COMPLETED_EVENT); 166 transitionTo(mInactiveState); 167 break; 168 default: 169 if (DBG) Log.d(TAG, "Ignoring supplicant state " + supState.name()); 170 break; 171 } 172 break; 173 case WifiStateMachine.CMD_START_WPS: 174 /* Ignore request and send an in progress message */ 175 mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED, 176 new WpsResult(Status.IN_PROGRESS)); 177 break; 178 default: 179 retValue = NOT_HANDLED; 180 } 181 return retValue; 182 } 183 } 184 185 class InactiveState extends State { 186 @Override 187 public void enter() { 188 if (DBG) Log.d(TAG, getName() + "\n"); 189 } 190 191 @Override 192 public boolean processMessage(Message message) { 193 boolean retValue = HANDLED; 194 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 195 switch (message.what) { 196 //Ignore supplicant state changes 197 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 198 break; 199 default: 200 retValue = NOT_HANDLED; 201 } 202 return retValue; 203 } 204 } 205 206 } 207