blob: f8048ffebaeb3d359e1910428666f7f4cc9e5929 [file] [log] [blame]
Irfan Sheriff19d245b792010-11-11 16:40:06 -08001/*
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
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080017package com.android.server.wifi;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080018
Wink Saville64c42ca2011-04-18 14:55:10 -070019import com.android.internal.util.State;
20import com.android.internal.util.StateMachine;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080021
Irfan Sheriff19d245b792010-11-11 16:40:06 -080022import android.content.Context;
23import android.content.Intent;
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080024import android.net.wifi.SupplicantState;
25import android.net.wifi.WifiConfiguration;
26import android.net.wifi.WifiManager;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080027import android.os.Handler;
28import android.os.Message;
29import android.os.Parcelable;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070030import android.os.UserHandle;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080031import android.util.Log;
32
Irfan Sherifff0afe412012-11-30 14:07:44 -080033import java.io.FileDescriptor;
34import java.io.PrintWriter;
35
Irfan Sheriff19d245b792010-11-11 16:40:06 -080036/**
37 * Tracks the state changes in supplicant and provides functionality
38 * that is based on these state changes:
39 * - detect a failed WPA handshake that loops indefinitely
Irfan Sheriffb98d8782011-01-19 15:09:14 -080040 * - authentication failure handling
Irfan Sheriff19d245b792010-11-11 16:40:06 -080041 */
Wink Saville64c42ca2011-04-18 14:55:10 -070042class SupplicantStateTracker extends StateMachine {
Irfan Sheriff19d245b792010-11-11 16:40:06 -080043
44 private static final String TAG = "SupplicantStateTracker";
45 private static final boolean DBG = false;
46
47 private WifiStateMachine mWifiStateMachine;
Irfan Sherifffc7f95a2012-01-04 14:50:09 -080048 private WifiConfigStore mWifiConfigStore;
Irfan Sheriffb98d8782011-01-19 15:09:14 -080049 private int mAuthenticationFailuresCount = 0;
Deepthi Gowric1b631e2013-04-30 18:23:57 +053050 private int mAssociationRejectCount = 0;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080051 /* Indicates authentication failure in supplicant broadcast.
52 * TODO: enhance auth failure reporting to include notification
53 * for all type of failures: EAP, WPS & WPA networks */
54 private boolean mAuthFailureInSupplicantBroadcast = false;
55
Irfan Sheriffb98d8782011-01-19 15:09:14 -080056 /* Maximum retries on a authentication failure notification */
57 private static final int MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080058
Deepthi Gowric1b631e2013-04-30 18:23:57 +053059 /* Maximum retries on assoc rejection events */
Vinit Deshapnde8fa06ee2013-11-13 15:48:11 -080060 private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 16;
Deepthi Gowric1b631e2013-04-30 18:23:57 +053061
Irfan Sheriff8e86b892010-12-22 11:02:20 -080062 /* Tracks if networks have been disabled during a connection */
63 private boolean mNetworksDisabledDuringConnect = false;
64
Irfan Sheriff19d245b792010-11-11 16:40:06 -080065 private Context mContext;
66
Wink Saville64c42ca2011-04-18 14:55:10 -070067 private State mUninitializedState = new UninitializedState();
68 private State mDefaultState = new DefaultState();
69 private State mInactiveState = new InactiveState();
70 private State mDisconnectState = new DisconnectedState();
71 private State mScanState = new ScanState();
72 private State mHandshakeState = new HandshakeState();
73 private State mCompletedState = new CompletedState();
74 private State mDormantState = new DormantState();
Irfan Sheriff19d245b792010-11-11 16:40:06 -080075
Irfan Sherifffc7f95a2012-01-04 14:50:09 -080076 public SupplicantStateTracker(Context c, WifiStateMachine wsm, WifiConfigStore wcs, Handler t) {
77 super(TAG, t.getLooper());
Irfan Sheriff19d245b792010-11-11 16:40:06 -080078
Irfan Sherifffc7f95a2012-01-04 14:50:09 -080079 mContext = c;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080080 mWifiStateMachine = wsm;
Irfan Sherifffc7f95a2012-01-04 14:50:09 -080081 mWifiConfigStore = wcs;
Irfan Sheriff19d245b792010-11-11 16:40:06 -080082 addState(mDefaultState);
83 addState(mUninitializedState, mDefaultState);
84 addState(mInactiveState, mDefaultState);
85 addState(mDisconnectState, mDefaultState);
86 addState(mScanState, mDefaultState);
87 addState(mHandshakeState, mDefaultState);
88 addState(mCompletedState, mDefaultState);
89 addState(mDormantState, mDefaultState);
90
91 setInitialState(mUninitializedState);
Irfan Sherifff0afe412012-11-30 14:07:44 -080092 setLogRecSize(50);
93 setLogOnlyTransitions(true);
Irfan Sheriff19d245b792010-11-11 16:40:06 -080094 //start the state machine
95 start();
96 }
97
Deepthi Gowric1b631e2013-04-30 18:23:57 +053098 private void handleNetworkConnectionFailure(int netId, int disableReason) {
Irfan Sheriff8e86b892010-12-22 11:02:20 -080099 /* If other networks disabled during connection, enable them */
100 if (mNetworksDisabledDuringConnect) {
Irfan Sherifffc7f95a2012-01-04 14:50:09 -0800101 mWifiConfigStore.enableAllNetworks();
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800102 mNetworksDisabledDuringConnect = false;
103 }
104 /* Disable failed network */
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530105 mWifiConfigStore.disableNetwork(netId, disableReason);
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800106 }
107
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800108 private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) {
109 SupplicantState supState = (SupplicantState) stateChangeResult.state;
110
111 if (DBG) Log.d(TAG, "Supplicant state: " + supState.toString() + "\n");
112
113 switch (supState) {
Irfan Sheriff319da8c2011-05-27 12:10:55 -0700114 case DISCONNECTED:
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800115 transitionTo(mDisconnectState);
116 break;
Irfan Sheriff319da8c2011-05-27 12:10:55 -0700117 case INTERFACE_DISABLED:
118 //we should have received a disconnection already, do nothing
119 break;
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800120 case SCANNING:
121 transitionTo(mScanState);
122 break;
Irfan Sheriff319da8c2011-05-27 12:10:55 -0700123 case AUTHENTICATING:
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800124 case ASSOCIATING:
125 case ASSOCIATED:
126 case FOUR_WAY_HANDSHAKE:
127 case GROUP_HANDSHAKE:
128 transitionTo(mHandshakeState);
129 break;
130 case COMPLETED:
131 transitionTo(mCompletedState);
132 break;
133 case DORMANT:
134 transitionTo(mDormantState);
135 break;
136 case INACTIVE:
137 transitionTo(mInactiveState);
138 break;
139 case UNINITIALIZED:
140 case INVALID:
141 transitionTo(mUninitializedState);
142 break;
143 default:
144 Log.e(TAG, "Unknown supplicant state " + supState);
145 break;
146 }
147 }
148
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800149 private void sendSupplicantStateChangedBroadcast(SupplicantState state, boolean failedAuth) {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800150 Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
151 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
152 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800153 intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable) state);
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800154 if (failedAuth) {
155 intent.putExtra(
156 WifiManager.EXTRA_SUPPLICANT_ERROR,
157 WifiManager.ERROR_AUTHENTICATING);
158 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700159 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800160 }
161
162 /********************************************************
163 * HSM states
164 *******************************************************/
165
Wink Saville64c42ca2011-04-18 14:55:10 -0700166 class DefaultState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800167 @Override
168 public void enter() {
169 if (DBG) Log.d(TAG, getName() + "\n");
170 }
171 @Override
172 public boolean processMessage(Message message) {
173 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
174 switch (message.what) {
repo sync55bc5f32011-06-24 14:23:07 -0700175 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
Irfan Sheriffb98d8782011-01-19 15:09:14 -0800176 mAuthenticationFailuresCount++;
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800177 mAuthFailureInSupplicantBroadcast = true;
178 break;
repo sync55bc5f32011-06-24 14:23:07 -0700179 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800180 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800181 SupplicantState state = stateChangeResult.state;
182 sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast);
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800183 mAuthFailureInSupplicantBroadcast = false;
184 transitionOnSupplicantStateChange(stateChangeResult);
185 break;
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800186 case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE:
187 transitionTo(mUninitializedState);
188 break;
Irfan Sheriffd3975a92012-02-24 10:54:13 -0800189 case WifiManager.CONNECT_NETWORK:
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800190 mNetworksDisabledDuringConnect = true;
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530191 mAssociationRejectCount = 0;
192 break;
193 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
194 mAssociationRejectCount++;
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800195 break;
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800196 default:
197 Log.e(TAG, "Ignoring " + message);
198 break;
199 }
200 return HANDLED;
201 }
202 }
203
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800204 /*
205 * This indicates that the supplicant state as seen
206 * by the framework is not initialized yet. We are
207 * in this state right after establishing a control
208 * channel connection before any supplicant events
209 * or after we have lost the control channel
210 * connection to the supplicant
211 */
Wink Saville64c42ca2011-04-18 14:55:10 -0700212 class UninitializedState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800213 @Override
214 public void enter() {
215 if (DBG) Log.d(TAG, getName() + "\n");
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800216 }
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800217 }
218
Wink Saville64c42ca2011-04-18 14:55:10 -0700219 class InactiveState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800220 @Override
221 public void enter() {
222 if (DBG) Log.d(TAG, getName() + "\n");
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800223 }
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800224 }
225
Wink Saville64c42ca2011-04-18 14:55:10 -0700226 class DisconnectedState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800227 @Override
228 public void enter() {
229 if (DBG) Log.d(TAG, getName() + "\n");
Irfan Sheriffb98d8782011-01-19 15:09:14 -0800230 /* If a disconnect event happens after authentication failure
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800231 * exceeds maximum retries, disable the network
232 */
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800233 Message message = getCurrentMessage();
234 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
235
Irfan Sheriffb98d8782011-01-19 15:09:14 -0800236 if (mAuthenticationFailuresCount >= MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800237 Log.d(TAG, "Failed to authenticate, disabling network " +
238 stateChangeResult.networkId);
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530239 handleNetworkConnectionFailure(stateChangeResult.networkId,
240 WifiConfiguration.DISABLED_AUTH_FAILURE);
Irfan Sheriffb98d8782011-01-19 15:09:14 -0800241 mAuthenticationFailuresCount = 0;
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800242 }
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530243 else if (mAssociationRejectCount >= MAX_RETRIES_ON_ASSOCIATION_REJECT) {
244 Log.d(TAG, "Association getting rejected, disabling network " +
245 stateChangeResult.networkId);
246 handleNetworkConnectionFailure(stateChangeResult.networkId,
247 WifiConfiguration.DISABLED_ASSOCIATION_REJECT);
248 mAssociationRejectCount = 0;
249 }
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800250 }
251 }
252
Wink Saville64c42ca2011-04-18 14:55:10 -0700253 class ScanState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800254 @Override
255 public void enter() {
256 if (DBG) Log.d(TAG, getName() + "\n");
257 }
258 }
259
Wink Saville64c42ca2011-04-18 14:55:10 -0700260 class HandshakeState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800261 /**
262 * The max number of the WPA supplicant loop iterations before we
263 * decide that the loop should be terminated:
264 */
265 private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
266 private int mLoopDetectIndex;
267 private int mLoopDetectCount;
268
269 @Override
270 public void enter() {
271 if (DBG) Log.d(TAG, getName() + "\n");
272 mLoopDetectIndex = 0;
273 mLoopDetectCount = 0;
274 }
275 @Override
276 public boolean processMessage(Message message) {
277 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
278 switch (message.what) {
repo sync55bc5f32011-06-24 14:23:07 -0700279 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800280 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800281 SupplicantState state = stateChangeResult.state;
Irfan Sheriff319da8c2011-05-27 12:10:55 -0700282 if (SupplicantState.isHandshakeState(state)) {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800283 if (mLoopDetectIndex > state.ordinal()) {
284 mLoopDetectCount++;
285 }
286 if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
287 Log.d(TAG, "Supplicant loop detected, disabling network " +
288 stateChangeResult.networkId);
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530289 handleNetworkConnectionFailure(stateChangeResult.networkId,
290 WifiConfiguration.DISABLED_AUTH_FAILURE);
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800291 }
292 mLoopDetectIndex = state.ordinal();
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800293 sendSupplicantStateChangedBroadcast(state,
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800294 mAuthFailureInSupplicantBroadcast);
295 } else {
296 //Have the DefaultState handle the transition
297 return NOT_HANDLED;
298 }
299 break;
300 default:
301 return NOT_HANDLED;
302 }
303 return HANDLED;
304 }
305 }
306
Wink Saville64c42ca2011-04-18 14:55:10 -0700307 class CompletedState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800308 @Override
309 public void enter() {
310 if (DBG) Log.d(TAG, getName() + "\n");
Irfan Sheriffb98d8782011-01-19 15:09:14 -0800311 /* Reset authentication failure count */
312 mAuthenticationFailuresCount = 0;
Deepthi Gowric1b631e2013-04-30 18:23:57 +0530313 mAssociationRejectCount = 0;
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800314 if (mNetworksDisabledDuringConnect) {
Irfan Sherifffc7f95a2012-01-04 14:50:09 -0800315 mWifiConfigStore.enableAllNetworks();
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800316 mNetworksDisabledDuringConnect = false;
317 }
318 }
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800319 @Override
320 public boolean processMessage(Message message) {
321 if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
322 switch(message.what) {
repo sync55bc5f32011-06-24 14:23:07 -0700323 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800324 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800325 SupplicantState state = stateChangeResult.state;
326 sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast);
Irfan Sheriff319da8c2011-05-27 12:10:55 -0700327 /* Ignore any connecting state in completed state. Group re-keying
328 * events and other auth events that do not affect connectivity are
329 * ignored
330 */
331 if (SupplicantState.isConnecting(state)) {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800332 break;
333 }
334 transitionOnSupplicantStateChange(stateChangeResult);
335 break;
Irfan Sheriffb45e7262010-12-21 09:44:15 -0800336 case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE:
337 sendSupplicantStateChangedBroadcast(SupplicantState.DISCONNECTED, false);
338 transitionTo(mUninitializedState);
339 break;
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800340 default:
341 return NOT_HANDLED;
342 }
343 return HANDLED;
344 }
345 }
346
347 //TODO: remove after getting rid of the state in supplicant
Wink Saville64c42ca2011-04-18 14:55:10 -0700348 class DormantState extends State {
Irfan Sheriff19d245b792010-11-11 16:40:06 -0800349 @Override
350 public void enter() {
351 if (DBG) Log.d(TAG, getName() + "\n");
352 }
353 }
Irfan Sherifff0afe412012-11-30 14:07:44 -0800354
355 @Override
356 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
357 super.dump(fd, pw, args);
358 pw.println("mAuthenticationFailuresCount " + mAuthenticationFailuresCount);
359 pw.println("mAuthFailureInSupplicantBroadcast " + mAuthFailureInSupplicantBroadcast);
360 pw.println("mNetworksDisabledDuringConnect " + mNetworksDisabledDuringConnect);
361 pw.println();
362 }
Irfan Sheriff6bb76522011-01-11 11:17:14 -0800363}