/** * suppRsnFsmProcessEvent * * FUNCTION * Passes an event to the RSN key FSM instance for immediate processing. * * @param fsm the RSN Key FSM instance * @param eventId the AAG event to process * @param arg an optional argument for this event * * @return ANI_OK if the operation succeeds */ int suppRsnFsmProcessEvent(tSuppRsnFsm *fsm, tRsnFsmEvent eventId, void *arg) { switch (eventId) { case RSN_FSM_TIMER_EXPIRED: // Proceed straight to checkTransition break; case RSN_FSM_AUTH_START: fsm->authReq = eANI_BOOLEAN_TRUE; suppRsnAuthStartEventHandler(fsm); break; case RSN_FSM_EAPOL_FRAME_AVAILABLE: fsm->eapolAvail = eANI_BOOLEAN_TRUE; break; case RSN_FSM_INTEG_FAILED: fsm->integFailed = eANI_BOOLEAN_TRUE; break; default: VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Supp unknown event for SuppFsm: %d\n", eventId); VOS_ASSERT( 0 ); return ANI_E_ILLEGAL_ARG; break; } checkTransition(fsm, arg); return ANI_OK; }
static int gotoStateIntegFailure(tAuthRsnFsm *fsm, tSirMicFailureInfo *micFailureInfo) { fsm->currentState = INTEG_FAILURE; fsm->integFailed = eANI_BOOLEAN_FALSE; checkTransition(fsm, NULL); // UCT return ANI_OK; }
static int gotoStateGetPsk(tAuthRsnFsm *fsm) { //This is simply a transaction because we already have the PMK. We always do. fsm->currentState = GET_PSK; fsm->numTries = 0; checkTransition(fsm, NULL); return ANI_OK; }
static int gotoStateAuthentication(tAuthRsnFsm *fsm) { fsm->currentState = AUTHENTICATION; zeroOutPtk(fsm); fsm->authReq = eANI_BOOLEAN_FALSE; checkTransition(fsm, NULL); // UCT rule return ANI_OK; }
static int gotoStateUpdateKeysReq(tAuthRsnFsm *fsm, tAniEapolKeyAvailEventData *data) { tAniEapolRsnKeyDesc *rxDesc; fsm->currentState = UPDATE_KEYS_REQ; rxDesc = data->keyDesc; aniSsmReplayCtrUpdate(fsm->staCtx->peerReplayCtr, rxDesc->replayCounter); checkTransition(fsm, data); return ANI_OK; }
static int gotoStatePtkInitNego(tAuthRsnFsm *fsm, void *arg) { fsm->currentState = PTK_INIT_NEGO; // Replay counter will be automatically updated when we create a // new packet fsm->numTries = 0; aniAsfPacketEmptyExplicit(fsm->lastEapol, EAPOL_TX_HEADER_SIZE); checkTransition(fsm, arg); return ANI_OK; }
static int gotoStateKeyUpdate(tAuthRsnFsm *fsm) { fsm->currentState = KEY_UPDATE; if( VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes(fsm->cryptHandle, fsm->aNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE) ) ) { // Replay counter will be automatically updated when we create a // new packet checkTransition(fsm, NULL); // UCT return ANI_OK; } return ANI_ERROR; }
static int gotoStateAuthentication2(tAuthRsnFsm *fsm) { fsm->currentState = AUTHENTICATION_2; if( !VOS_IS_STATUS_SUCCESS( vos_rand_get_bytes( fsm->cryptHandle, fsm->aNonce, ANI_EAPOL_KEY_RSN_NONCE_SIZE ) ) ) { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "gotoStateAuthentication2 fail to get random number. Disconnect\n" ); bapAuthDisconnect( fsm->ctx ); return ANI_ERROR; } fsm->numTries = 0; checkTransition(fsm, NULL); // UCT rule return ANI_OK; }
static int checkTransition(tSuppRsnFsm *fsm, void *arg) { tAniEapolKeyAvailEventData *data; tAniEapolRsnKeyDesc *rxDesc; v_BOOL_t retransmit; int retVal; if (fsm->authReq) { gotoStateAuthentication(fsm); return ANI_OK; } switch (fsm->currentState) { case INITIALIZE: break; case AUTHENTICATION: gotoStateGotPmk(fsm); checkTransition(fsm, arg); break; case GOT_PMK: if (fsm->eapolAvail) { fsm->eapolAvail = eANI_BOOLEAN_FALSE; data = (tAniEapolKeyAvailEventData *) arg; rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc; if (rxDesc->info.ackFlag) { aniSsmReplayCtrUpdate(fsm->peerReplayCtr, rxDesc->replayCounter); // Going from one state to another cannot be a retransmit retVal = gotoStateStaKeyStart(fsm, data, eANI_BOOLEAN_FALSE); } } break; case STA_KEY_START: if (fsm->eapolAvail) { fsm->eapolAvail = eANI_BOOLEAN_FALSE; data = (tAniEapolKeyAvailEventData *) arg; rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc; if (rxDesc->info.ackFlag) { retVal = checkPeerReplayCounter( fsm, data, &retransmit, rxDesc->info.micFlag, 0); // MIC not set means check for re-Tx M1. if (retVal != ANI_OK) return ANI_OK; // Caller should not fail if (retransmit) { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Resending EAPOL-Key Msg2 from " "supplicant to AP" ); retVal = gotoStateStaKeyStart(fsm, data, eANI_BOOLEAN_TRUE); } else { retVal = checkMic(fsm, data, rxDesc->info.unicastFlag); if (retVal != ANI_OK) { bapSuppDisconnect( fsm->ctx ); return retVal; } aniSsmReplayCtrUpdate(fsm->peerReplayCtr, rxDesc->replayCounter); gotoStateStaKeySet(fsm, data, eANI_BOOLEAN_FALSE); } } } break; case STA_KEY_SET: if (fsm->eapolAvail) { fsm->eapolAvail = eANI_BOOLEAN_FALSE; data = (tAniEapolKeyAvailEventData *) arg; rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc; retVal = checkPeerReplayCounter( fsm, data, &retransmit, rxDesc->info.micFlag, 1); // MIC set means check for re-Tx M3. if (retVal != ANI_OK) return ANI_OK; // Caller should not fail if (!retransmit) { retVal = checkMic(fsm, data, rxDesc->info.unicastFlag); if (retVal != ANI_OK) { bapSuppDisconnect( fsm->ctx ); return retVal; } aniSsmReplayCtrUpdate(fsm->peerReplayCtr, rxDesc->replayCounter); } if (rxDesc->info.unicastFlag) { /* * Handle pairwise key message...in this state * pairwise key messages can only be for retransmissions. */ if (retransmit) { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Resending EAPOL-Key Msg4 from " "supplicant \n" ); retVal = gotoStateStaKeySet(fsm, data, eANI_BOOLEAN_TRUE); } } else { /* * Handle group key message...with group key messages, * the replay counter has to change on * retransmissions. */ if (!retransmit) { retVal = gotoStateGroupKeySet(fsm, data); if( !ANI_IS_STATUS_SUCCESS( retVal ) ) { bapSuppDisconnect( fsm->ctx ); return retVal; } } } } else { if (fsm->integFailed) { gotoStateKeyUpdate(fsm, arg); } } break; case GROUP_KEY_SET: gotoStateStaKeySet(fsm, NULL, eANI_BOOLEAN_FALSE); break; case KEY_UPDATE: gotoStateRekeyMsg(fsm, arg); break; default: VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Illegal state for SuppRsnFsm: %d", fsm->currentState); VOS_ASSERT( 0 ); return ANI_E_FAILED; } return ANI_OK; }
static int gotoStateGroupKeySet(tSuppRsnFsm *fsm, tAniEapolKeyAvailEventData *data) { int retVal; tAniEapolRsnKeyDesc txDesc; tAniEapolRsnKeyDesc *rxDesc; int groupKeyLen; fsm->currentState = GROUP_KEY_SET; do { rxDesc = (tAniEapolRsnKeyDesc *) data->keyDesc; if( NULL == rxDesc) { retVal = ANI_E_NULL_VALUE; break; } if (rxDesc->keyDataLen == 0 || rxDesc->keyData == NULL) { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Supp: AP sent no group key in group EAPOL-Key message!\n" ); retVal = ANI_E_ILLEGAL_ARG; break; } if ( rxDesc->info.keyDescVers == ANI_EAPOL_KEY_DESC_VERS_AES ) { groupKeyLen = rxDesc->keyDataLen - ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE; if( groupKeyLen <= 0 ) { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Supp: AP sent GTK too short\n" ); retVal = ANI_E_ILLEGAL_ARG; break; } } else { VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Supp: AP sent unsupported keyDescVer %d!\n", rxDesc->info.keyDescVers ); retVal = ANI_E_ILLEGAL_ARG; break; } // Always create a new EAPOL frame aniAsfPacketEmptyExplicit( fsm->lastEapol, EAPOL_TX_HEADER_SIZE ); vos_mem_zero( &txDesc, sizeof(txDesc) ); // The Key Information bits... if (fsm->suppCtx->grpCipherType == eCSR_ENCRYPT_TYPE_AES) { txDesc.info.keyDescVers = ANI_EAPOL_KEY_DESC_VERS_AES; } txDesc.info.unicastFlag = eANI_BOOLEAN_FALSE; txDesc.info.keyId = rxDesc->info.keyId; txDesc.info.micFlag = eANI_BOOLEAN_TRUE; txDesc.info.secureFlag = eANI_BOOLEAN_TRUE; txDesc.keyLen = RSN_80211_KEY_LEN; // Send back the same replayCtr that the authenticator sent vos_mem_copy(txDesc.replayCounter, rxDesc->replayCounter, sizeof(txDesc.replayCounter)); retVal = aniEapolWriteKey(fsm->cryptHandle, fsm->lastEapol, fsm->suppCtx->authMac, fsm->suppCtx->suppMac, ANI_EAPOL_KEY_DESC_TYPE_RSN_NEW, &txDesc, fsm->suppCtx->ptk, CSR_AES_KEY_LEN); if( !ANI_IS_STATUS_SUCCESS( retVal ) ) break; if( !VOS_IS_STATUS_SUCCESS( bapRsnSendEapolFrame( fsm->ctx->pvosGCtx, fsm->lastEapol ) ) ) { retVal = ANI_ERROR; VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR, "Supp could not send eapol. Disconnect\n" ); break; } //FIX_RSN there is no need to set GTK retVal = setGtk(fsm->suppCtx, rxDesc->keyRecvSeqCounter); // This is never retransmitted aniAsfPacketEmptyExplicit( fsm->lastEapol, EAPOL_TX_HEADER_SIZE ); checkTransition(fsm, NULL); // UCT rule }while( 0 ); return retVal; }