Loading wifi/java/android/net/wifi/SupplicantStateTracker.java 0 → 100644 +333 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import com.android.internal.util.HierarchicalState; import com.android.internal.util.HierarchicalStateMachine; import android.net.wifi.WifiStateMachine.StateChangeResult; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.util.Log; /** * Tracks the state changes in supplicant and provides functionality * that is based on these state changes: * - detect a failed WPA handshake that loops indefinitely * - password failure handling * - Enable networks after a WPS success/failure */ class SupplicantStateTracker extends HierarchicalStateMachine { private static final String TAG = "SupplicantStateTracker"; private static final boolean DBG = false; private WifiStateMachine mWifiStateMachine; private int mPasswordFailuresCount = 0; /* Indicates authentication failure in supplicant broadcast. * TODO: enhance auth failure reporting to include notification * for all type of failures: EAP, WPS & WPA networks */ private boolean mAuthFailureInSupplicantBroadcast = false; /* Maximum retries on a password failure notification */ private static final int MAX_RETRIES_ON_PASSWORD_FAILURE = 2; /* Track if WPS was started since we need to re-enable networks * and load configuration afterwards */ private boolean mWpsStarted = false; private Context mContext; private HierarchicalState mUninitializedState = new UninitializedState(); private HierarchicalState mDefaultState = new DefaultState(); private HierarchicalState mInactiveState = new InactiveState(); private HierarchicalState mDisconnectState = new DisconnectedState(); private HierarchicalState mScanState = new ScanState(); private HierarchicalState mHandshakeState = new HandshakeState(); private HierarchicalState mCompletedState = new CompletedState(); private HierarchicalState mDormantState = new DormantState(); public SupplicantStateTracker(Context context, WifiStateMachine wsm, Handler target) { super(TAG, target.getLooper()); mContext = context; mWifiStateMachine = wsm; addState(mDefaultState); addState(mUninitializedState, mDefaultState); addState(mInactiveState, mDefaultState); addState(mDisconnectState, mDefaultState); addState(mScanState, mDefaultState); addState(mHandshakeState, mDefaultState); addState(mCompletedState, mDefaultState); addState(mDormantState, mDefaultState); setInitialState(mUninitializedState); //start the state machine start(); } public void resetSupplicantState() { transitionTo(mUninitializedState); } private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) { SupplicantState supState = (SupplicantState) stateChangeResult.state; if (DBG) Log.d(TAG, "Supplicant state: " + supState.toString() + "\n"); switch (supState) { case DISCONNECTED: transitionTo(mDisconnectState); break; case SCANNING: transitionTo(mScanState); break; case ASSOCIATING: case ASSOCIATED: case FOUR_WAY_HANDSHAKE: case GROUP_HANDSHAKE: transitionTo(mHandshakeState); break; case COMPLETED: transitionTo(mCompletedState); break; case DORMANT: transitionTo(mDormantState); break; case INACTIVE: transitionTo(mInactiveState); break; case UNINITIALIZED: case INVALID: transitionTo(mUninitializedState); break; default: Log.e(TAG, "Unknown supplicant state " + supState); break; } } private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) { Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state); if (failedAuth) { intent.putExtra( WifiManager.EXTRA_SUPPLICANT_ERROR, WifiManager.ERROR_AUTHENTICATING); } mContext.sendStickyBroadcast(intent); } /******************************************************** * HSM states *******************************************************/ class DefaultState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case WifiStateMachine.PASSWORD_MAY_BE_INCORRECT_EVENT: mPasswordFailuresCount++; mAuthFailureInSupplicantBroadcast = true; break; case WifiStateMachine.CMD_START_WPS_PBC: case WifiStateMachine.CMD_START_WPS_PIN_FROM_AP: case WifiStateMachine.CMD_START_WPS_PIN_FROM_DEVICE: mWpsStarted = true; break; case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); mAuthFailureInSupplicantBroadcast = false; transitionOnSupplicantStateChange(stateChangeResult); break; default: Log.e(TAG, "Ignoring " + message); break; } return HANDLED; } } class UninitializedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); mWifiStateMachine.setNetworkAvailable(false); } @Override public void exit() { mWifiStateMachine.setNetworkAvailable(true); } } class InactiveState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* A failed WPS connection */ if (mWpsStarted) { Log.e(TAG, "WPS set up failed, enabling other networks"); WifiConfigStore.enableAllNetworks(); mWpsStarted = false; } mWifiStateMachine.setNetworkAvailable(false); } @Override public void exit() { mWifiStateMachine.setNetworkAvailable(true); } } class DisconnectedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* If a disconnect event happens after password key failure * exceeds maximum retries, disable the network */ Message message = getCurrentMessage(); StateChangeResult stateChangeResult = (StateChangeResult) message.obj; if (mPasswordFailuresCount >= MAX_RETRIES_ON_PASSWORD_FAILURE) { Log.d(TAG, "Failed to authenticate, disabling network " + stateChangeResult.networkId); WifiConfigStore.disableNetwork(stateChangeResult.networkId); mPasswordFailuresCount = 0; } } } class ScanState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } } class HandshakeState extends HierarchicalState { /** * The max number of the WPA supplicant loop iterations before we * decide that the loop should be terminated: */ private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; private int mLoopDetectIndex; private int mLoopDetectCount; @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); mLoopDetectIndex = 0; mLoopDetectCount = 0; } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; SupplicantState state = (SupplicantState) stateChangeResult.state; if (state == SupplicantState.ASSOCIATING || state == SupplicantState.ASSOCIATED || state == SupplicantState.FOUR_WAY_HANDSHAKE || state == SupplicantState.GROUP_HANDSHAKE) { if (mLoopDetectIndex > state.ordinal()) { mLoopDetectCount++; } if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { Log.d(TAG, "Supplicant loop detected, disabling network " + stateChangeResult.networkId); WifiConfigStore.disableNetwork(stateChangeResult.networkId); } mLoopDetectIndex = state.ordinal(); sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); } else { //Have the DefaultState handle the transition return NOT_HANDLED; } break; default: return NOT_HANDLED; } return HANDLED; } } class CompletedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* Reset password failure count */ mPasswordFailuresCount = 0; /* A successful WPS connection */ if (mWpsStarted) { WifiConfigStore.enableAllNetworks(); WifiConfigStore.loadConfiguredNetworks(); mWpsStarted = false; } } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch(message.what) { case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; SupplicantState state = (SupplicantState) stateChangeResult.state; sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); /* Ignore a re-auth in completed state */ if (state == SupplicantState.ASSOCIATING || state == SupplicantState.ASSOCIATED || state == SupplicantState.FOUR_WAY_HANDSHAKE || state == SupplicantState.GROUP_HANDSHAKE || state == SupplicantState.COMPLETED) { break; } transitionOnSupplicantStateChange(stateChangeResult); break; default: return NOT_HANDLED; } return HANDLED; } } //TODO: remove after getting rid of the state in supplicant class DormantState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } } } No newline at end of file wifi/java/android/net/wifi/WifiStateMachine.java +180 −515 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
wifi/java/android/net/wifi/SupplicantStateTracker.java 0 → 100644 +333 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import com.android.internal.util.HierarchicalState; import com.android.internal.util.HierarchicalStateMachine; import android.net.wifi.WifiStateMachine.StateChangeResult; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.util.Log; /** * Tracks the state changes in supplicant and provides functionality * that is based on these state changes: * - detect a failed WPA handshake that loops indefinitely * - password failure handling * - Enable networks after a WPS success/failure */ class SupplicantStateTracker extends HierarchicalStateMachine { private static final String TAG = "SupplicantStateTracker"; private static final boolean DBG = false; private WifiStateMachine mWifiStateMachine; private int mPasswordFailuresCount = 0; /* Indicates authentication failure in supplicant broadcast. * TODO: enhance auth failure reporting to include notification * for all type of failures: EAP, WPS & WPA networks */ private boolean mAuthFailureInSupplicantBroadcast = false; /* Maximum retries on a password failure notification */ private static final int MAX_RETRIES_ON_PASSWORD_FAILURE = 2; /* Track if WPS was started since we need to re-enable networks * and load configuration afterwards */ private boolean mWpsStarted = false; private Context mContext; private HierarchicalState mUninitializedState = new UninitializedState(); private HierarchicalState mDefaultState = new DefaultState(); private HierarchicalState mInactiveState = new InactiveState(); private HierarchicalState mDisconnectState = new DisconnectedState(); private HierarchicalState mScanState = new ScanState(); private HierarchicalState mHandshakeState = new HandshakeState(); private HierarchicalState mCompletedState = new CompletedState(); private HierarchicalState mDormantState = new DormantState(); public SupplicantStateTracker(Context context, WifiStateMachine wsm, Handler target) { super(TAG, target.getLooper()); mContext = context; mWifiStateMachine = wsm; addState(mDefaultState); addState(mUninitializedState, mDefaultState); addState(mInactiveState, mDefaultState); addState(mDisconnectState, mDefaultState); addState(mScanState, mDefaultState); addState(mHandshakeState, mDefaultState); addState(mCompletedState, mDefaultState); addState(mDormantState, mDefaultState); setInitialState(mUninitializedState); //start the state machine start(); } public void resetSupplicantState() { transitionTo(mUninitializedState); } private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) { SupplicantState supState = (SupplicantState) stateChangeResult.state; if (DBG) Log.d(TAG, "Supplicant state: " + supState.toString() + "\n"); switch (supState) { case DISCONNECTED: transitionTo(mDisconnectState); break; case SCANNING: transitionTo(mScanState); break; case ASSOCIATING: case ASSOCIATED: case FOUR_WAY_HANDSHAKE: case GROUP_HANDSHAKE: transitionTo(mHandshakeState); break; case COMPLETED: transitionTo(mCompletedState); break; case DORMANT: transitionTo(mDormantState); break; case INACTIVE: transitionTo(mInactiveState); break; case UNINITIALIZED: case INVALID: transitionTo(mUninitializedState); break; default: Log.e(TAG, "Unknown supplicant state " + supState); break; } } private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) { Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state); if (failedAuth) { intent.putExtra( WifiManager.EXTRA_SUPPLICANT_ERROR, WifiManager.ERROR_AUTHENTICATING); } mContext.sendStickyBroadcast(intent); } /******************************************************** * HSM states *******************************************************/ class DefaultState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case WifiStateMachine.PASSWORD_MAY_BE_INCORRECT_EVENT: mPasswordFailuresCount++; mAuthFailureInSupplicantBroadcast = true; break; case WifiStateMachine.CMD_START_WPS_PBC: case WifiStateMachine.CMD_START_WPS_PIN_FROM_AP: case WifiStateMachine.CMD_START_WPS_PIN_FROM_DEVICE: mWpsStarted = true; break; case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); mAuthFailureInSupplicantBroadcast = false; transitionOnSupplicantStateChange(stateChangeResult); break; default: Log.e(TAG, "Ignoring " + message); break; } return HANDLED; } } class UninitializedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); mWifiStateMachine.setNetworkAvailable(false); } @Override public void exit() { mWifiStateMachine.setNetworkAvailable(true); } } class InactiveState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* A failed WPS connection */ if (mWpsStarted) { Log.e(TAG, "WPS set up failed, enabling other networks"); WifiConfigStore.enableAllNetworks(); mWpsStarted = false; } mWifiStateMachine.setNetworkAvailable(false); } @Override public void exit() { mWifiStateMachine.setNetworkAvailable(true); } } class DisconnectedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* If a disconnect event happens after password key failure * exceeds maximum retries, disable the network */ Message message = getCurrentMessage(); StateChangeResult stateChangeResult = (StateChangeResult) message.obj; if (mPasswordFailuresCount >= MAX_RETRIES_ON_PASSWORD_FAILURE) { Log.d(TAG, "Failed to authenticate, disabling network " + stateChangeResult.networkId); WifiConfigStore.disableNetwork(stateChangeResult.networkId); mPasswordFailuresCount = 0; } } } class ScanState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } } class HandshakeState extends HierarchicalState { /** * The max number of the WPA supplicant loop iterations before we * decide that the loop should be terminated: */ private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; private int mLoopDetectIndex; private int mLoopDetectCount; @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); mLoopDetectIndex = 0; mLoopDetectCount = 0; } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; SupplicantState state = (SupplicantState) stateChangeResult.state; if (state == SupplicantState.ASSOCIATING || state == SupplicantState.ASSOCIATED || state == SupplicantState.FOUR_WAY_HANDSHAKE || state == SupplicantState.GROUP_HANDSHAKE) { if (mLoopDetectIndex > state.ordinal()) { mLoopDetectCount++; } if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { Log.d(TAG, "Supplicant loop detected, disabling network " + stateChangeResult.networkId); WifiConfigStore.disableNetwork(stateChangeResult.networkId); } mLoopDetectIndex = state.ordinal(); sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); } else { //Have the DefaultState handle the transition return NOT_HANDLED; } break; default: return NOT_HANDLED; } return HANDLED; } } class CompletedState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); /* Reset password failure count */ mPasswordFailuresCount = 0; /* A successful WPS connection */ if (mWpsStarted) { WifiConfigStore.enableAllNetworks(); WifiConfigStore.loadConfiguredNetworks(); mWpsStarted = false; } } @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch(message.what) { case WifiStateMachine.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; SupplicantState state = (SupplicantState) stateChangeResult.state; sendSupplicantStateChangedBroadcast(stateChangeResult, mAuthFailureInSupplicantBroadcast); /* Ignore a re-auth in completed state */ if (state == SupplicantState.ASSOCIATING || state == SupplicantState.ASSOCIATED || state == SupplicantState.FOUR_WAY_HANDSHAKE || state == SupplicantState.GROUP_HANDSHAKE || state == SupplicantState.COMPLETED) { break; } transitionOnSupplicantStateChange(stateChangeResult); break; default: return NOT_HANDLED; } return HANDLED; } } //TODO: remove after getting rid of the state in supplicant class DormantState extends HierarchicalState { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); } } } No newline at end of file
wifi/java/android/net/wifi/WifiStateMachine.java +180 −515 File changed.Preview size limit exceeded, changes collapsed. Show changes