/*************************************************************************************************/ /*! * \file * * \brief SMP common utility functions and action functions. * * Copyright (c) 2010-2018 Arm Ltd. * * Copyright (c) 2019 Packetcraft, Inc. * * 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. */ /*************************************************************************************************/ #include #include "wsf_types.h" #include "wsf_buf.h" #include "wsf_msg.h" #include "wsf_trace.h" #include "util/bstream.h" #include "util/calc128.h" #include "dm_api.h" #include "smp_api.h" #include "smp_main.h" #ifndef SMP_EXTRA_TRACE #define SMP_EXTRA_TRACE FALSE #endif /*************************************************************************************************/ /*! * \brief Start SMP response timer. * * \param pCcb Connection control block. * * \return None. */ /*************************************************************************************************/ void smpStartRspTimer(smpCcb_t *pCcb) { /* start smp response timer */ pCcb->rspTimer.msg.event = SMP_MSG_INT_RSP_TIMEOUT; pCcb->rspTimer.msg.status = SMP_ERR_TIMEOUT; WsfTimerStartSec(&pCcb->rspTimer, SMP_TIMEOUT); } /*************************************************************************************************/ /*! * \brief No action. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActNone(smpCcb_t *pCcb, smpMsg_t *pMsg) { return; } /*************************************************************************************************/ /*! * \brief Cleanup CCB. * * \param pCcb Connection control block. * * \return None. */ /*************************************************************************************************/ void smpCleanup(smpCcb_t *pCcb) { /* free scratch buffer */ if (pCcb->pScr != NULL) { WsfBufFree(pCcb->pScr); pCcb->pScr = NULL; } /* stop response timer */ WsfTimerStop(&pCcb->rspTimer); /* stop wait interval timer */ WsfTimerStop(&pCcb->waitTimer); pCcb->secReq = FALSE; pCcb->nextCmdCode = (pCcb->initiator) ? SMP_CMD_SECURITY_REQ : SMP_CMD_PAIR_REQ; pCcb->lastSentKey = 0; } /*************************************************************************************************/ /*! * \brief Cleanup CCB. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActCleanup(smpCcb_t *pCcb, smpMsg_t *pMsg) { smpCleanup(pCcb); } /*************************************************************************************************/ /*! * \brief Send a pairing failed packet. * * \param pCcb Connection control block. * \param reason Failure reason. * * \return None. */ /*************************************************************************************************/ void smpSendPairingFailed(smpCcb_t *pCcb, uint8_t reason) { uint8_t *pPacket; uint8_t *p; if ((pPacket = smpMsgAlloc(L2C_PAYLOAD_START + SMP_PAIR_FAIL_LEN)) != NULL) { p = pPacket + L2C_PAYLOAD_START; UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_FAIL); UINT8_TO_BSTREAM(p, reason); smpSendPkt(pCcb, pPacket); } } /*************************************************************************************************/ /*! * \brief Pairing failed. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairingFailed(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* clean up */ smpCleanup(pCcb); /* set connection idle */ DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_IDLE); /* notify DM of pairing failure */ pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND; DmSmpCbackExec((dmEvt_t *) pMsg); } /*************************************************************************************************/ /*! * \brief Pairing cancelled by user. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairingCancel(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* send pairing failed packet */ smpSendPairingFailed(pCcb, pMsg->hdr.status); smpActPairingFailed(pCcb, pMsg); } /*************************************************************************************************/ /*! * \brief Store the authentication data. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActStorePin(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* copy authentication data to scratchpad */ memcpy(pCcb->pScr->buf.b1, pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen); /* zero out unused pin data */ if (pMsg->dm.authRsp.authDataLen == SMP_PIN_LEN) { memset(&pCcb->pScr->buf.b1[SMP_PIN_LEN], 0, SMP_OOB_LEN - SMP_PIN_LEN); } } /*************************************************************************************************/ /*! * \brief Process a pairing request and response data. * * \param pCcb Connection control block. * \param pOob Return parameter, TRUE if out-of-band data requested. * \param pDisplay Return parameter, TRUE if pin is to be displayed. * * \return TRUE on success, FALSE otherwise. */ /*************************************************************************************************/ bool_t smpProcPairing(smpCcb_t *pCcb, uint8_t *pOob, uint8_t *pDisplay) { bool_t justWorks = TRUE; uint8_t localAuth; wsfMsgHdr_t hdr; *pDisplay = FALSE; *pOob = FALSE; /* if OOB available use that */ if (pCcb->pairReq[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT && pCcb->pairRsp[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT) { *pOob = SMP_OOB_DATA_PRESENT; justWorks = FALSE; } /* if either device set mitm flag */ else if ((pCcb->pairReq[SMP_AUTHREQ_POS] & SMP_AUTH_MITM_FLAG) || (pCcb->pairRsp[SMP_AUTHREQ_POS] & SMP_AUTH_MITM_FLAG)) { /* check for compatible I/O settings */ if ((pCcb->pairReq[SMP_IO_POS] != SMP_IO_NO_IN_NO_OUT) && /* initiator has i/o and */ (pCcb->pairRsp[SMP_IO_POS] != SMP_IO_NO_IN_NO_OUT) && /* responder has i/o and */ !(((pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_ONLY) || /* both don't have display only */ (pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_YES_NO)) && ((pCcb->pairRsp[SMP_IO_POS] == SMP_IO_DISP_ONLY) || (pCcb->pairRsp[SMP_IO_POS] == SMP_IO_DISP_YES_NO)))) { /* use pin */ justWorks = FALSE; /* check if pin should be displayed (as initiator) */ *pDisplay = ((pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_ONLY) || /* initiator is display only or */ (pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_YES_NO) || /* initiator is display y/n or */ ((pCcb->pairReq[SMP_IO_POS] == SMP_IO_KEY_DISP) && /* initiator is key/display and */ (pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_ONLY || /* responder is key only or key/display */ pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_DISP))); /* invert display setting if we are not initiator and both are not key only */ if (!(pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_ONLY && pCcb->pairReq[SMP_IO_POS] == SMP_IO_KEY_ONLY)) { *pDisplay ^= !pCcb->initiator; } } } if (!justWorks) { /* set auth flags with mitm bit set */ pCcb->auth = (pCcb->pairReq[SMP_AUTHREQ_POS] & pCcb->pairRsp[SMP_AUTHREQ_POS]) | SMP_AUTH_MITM_FLAG; } else { /* set auth flags with mitm bit cleared */ pCcb->auth = pCcb->pairReq[SMP_AUTHREQ_POS] & pCcb->pairRsp[SMP_AUTHREQ_POS] & ~SMP_AUTH_MITM_FLAG; } /* if we ended up with 'just works' but the device configuration requires authentication */ localAuth = (pCcb->initiator) ? pCcb->pairReq[SMP_AUTHREQ_POS] : pCcb->pairRsp[SMP_AUTHREQ_POS]; if (justWorks && (pSmpCfg->auth & localAuth & SMP_AUTH_MITM_FLAG)) { /* cancel pairing */ hdr.param = pCcb->connId; hdr.status = SMP_ERR_AUTH_REQ; hdr.event = SMP_MSG_API_CANCEL_REQ; smpSmExecute(pCcb, (smpMsg_t *) &hdr); return FALSE; } /* if max encryption key is less than our minimum */ if (pCcb->pairReq[SMP_MAXKEY_POS] < pSmpCfg->minKeyLen || pCcb->pairRsp[SMP_MAXKEY_POS] < pSmpCfg->minKeyLen) { /* cancel pairing */ hdr.param = pCcb->connId; hdr.status = SMP_ERR_ENC_KEY_SIZE; hdr.event = SMP_MSG_API_CANCEL_REQ; smpSmExecute(pCcb, (smpMsg_t *) &hdr); return FALSE; } return TRUE; } /*************************************************************************************************/ /*! * \brief Request authentication data or send ourselves an authentication response. * * \param pCcb Connection control block. * \param oob Out-of-band data requested. * \param display TRUE if pin is to be displayed. * * \return None. */ /*************************************************************************************************/ void smpAuthReq(smpCcb_t *pCcb, uint8_t oob, uint8_t display) { /* use a union to save a bit of memory on the stack */ union { smpDmAuthRsp_t authRsp; dmSecAuthReqIndEvt_t authReq; } buf; /* if authenticated pairing */ if (pCcb->auth & SMP_AUTH_MITM_FLAG) { /* request pin or oob from user */ buf.authReq.hdr.param = pCcb->connId; buf.authReq.hdr.event = DM_SEC_AUTH_REQ_IND; buf.authReq.oob = oob; buf.authReq.display = display; DmSmpCbackExec((dmEvt_t *) &buf.authReq); } else { /* else use just works; send ourselves a auth rsp with all zero pin */ buf.authRsp.hdr.param = pCcb->connId; buf.authRsp.hdr.event = SMP_MSG_API_AUTH_RSP; buf.authRsp.authData[0] = 0; buf.authRsp.authData[1] = 0; buf.authRsp.authData[2] = 0; buf.authRsp.authDataLen = SMP_PIN_LEN; smpSmExecute(pCcb, (smpMsg_t *) &buf.authRsp); } } /*************************************************************************************************/ /*! * \brief Perform first part of pairing confirm calculation. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairCnfCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* store authentication data */ smpActStorePin(pCcb, pMsg); /* get random number to scratchpad */ SecRand(pCcb->pScr->buf.b4, SMP_RAND_LEN); /* execute calculation */ smpCalcC1Part1(pCcb, pCcb->pScr->buf.b1, pCcb->pScr->buf.b4); } /*************************************************************************************************/ /*! * \brief Perform second part of pairing confirm calculation. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairCnfCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg) { smpCalcC1Part2(pCcb, pCcb->pScr->buf.b1, pMsg->aes.pCiphertext); } /*************************************************************************************************/ /*! * \brief Send a pairing confirm packet. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActSendPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg) { uint8_t *pPkt; uint8_t *p; /* set next expected packet */ pCcb->nextCmdCode = (pCcb->initiator) ? SMP_CMD_PAIR_CNF : SMP_CMD_PAIR_RAND; /* start smp response timer */ smpStartRspTimer(pCcb); /* allocate packet buffer */ if ((pPkt = smpMsgAlloc(SMP_PAIR_CNF_LEN + L2C_PAYLOAD_START)) != NULL) { /* build packet */ p = pPkt + L2C_PAYLOAD_START; UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_CNF); memcpy(p, pMsg->aes.pCiphertext, SMP_CONFIRM_LEN); /* send packet */ smpSendPkt(pCcb, pPkt); } } /*************************************************************************************************/ /*! * \brief Perform first part of the pairing confirm verification calculation. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairCnfVerCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg) { uint8_t *p; /* go to start of received pairing random packet */ p = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN; /* store random value */ memcpy(pCcb->pScr->buf.b2, p, SMP_RAND_LEN); /* execute calculation */ smpCalcC1Part1(pCcb, pCcb->pScr->buf.b1, p); } /*************************************************************************************************/ /*! * \brief Perform first part of the pairing confirm verification calculation. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairCnfVerCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg) { smpCalcC1Part2(pCcb, pCcb->pScr->buf.b1, pMsg->aes.pCiphertext); } /*************************************************************************************************/ /*! * \brief Send a key. * * \param pCcb Connection control block. * \param keyDist Key distribution mask. * * \return TRUE if done sending keys, FALSE otherwise. */ /*************************************************************************************************/ bool_t smpSendKey(smpCcb_t *pCcb, uint8_t keyDist) { uint8_t *pPkt; uint8_t *p; wsfMsgHdr_t *pHdr; if (smpCb.lescSupported && pCcb->pScCcb->lescEnabled && pCcb->lastSentKey == 0) { dmSecKeyIndEvt_t keyInd; /* pass LTK to app via DM */ if (DmConnRole(pCcb->connId) == DM_ROLE_MASTER) { keyInd.type = DM_KEY_PEER_LTK; } else { keyInd.type = DM_KEY_LOCAL_LTK; } keyInd.hdr.event = DM_SEC_KEY_IND; keyInd.hdr.param = pCcb->connId; keyInd.secLevel = smpGetScSecLevel(pCcb); keyInd.keyData.ltk.ediv = 0; memset(keyInd.keyData.ltk.rand, 0, SMP_RAND8_LEN); Calc128Cpy(keyInd.keyData.ltk.key, pCcb->pScCcb->pLtk->ltk_t); DmSmpCbackExec((dmEvt_t *)&keyInd); pCcb->lastSentKey = SMP_CMD_MASTER_ID; } /* check if we're done sending keys */ if ((keyDist == 0) || (keyDist == SMP_KEY_DIST_ENC && pCcb->lastSentKey == SMP_CMD_MASTER_ID) || (keyDist <= (SMP_KEY_DIST_ENC | SMP_KEY_DIST_ID) && pCcb->lastSentKey == SMP_CMD_ID_ADDR_INFO) || (pCcb->lastSentKey == SMP_CMD_SIGN_INFO)) { return TRUE; } /* if flow disabled return */ if (pCcb->flowDisabled) { return FALSE; } /* allocate packet buffer for largest packet size */ if ((pPkt = smpMsgAlloc(SMP_ENC_INFO_LEN + L2C_PAYLOAD_START)) != NULL) { p = pPkt + L2C_PAYLOAD_START; /* determine next key to send */ if (pCcb->lastSentKey == 0 && (keyDist & SMP_KEY_DIST_ENC)) { /* generate LTK, EDIV, and RAND */ smpGenerateLtk(pCcb); /* send first part of LTK */ UINT8_TO_BSTREAM(p, SMP_CMD_ENC_INFO); Calc128Cpy(p, pCcb->pScr->keyInd.keyData.ltk.key); } else if (pCcb->lastSentKey == SMP_CMD_ENC_INFO) { /* send second part of LTK */ UINT8_TO_BSTREAM(p, SMP_CMD_MASTER_ID); UINT16_TO_BSTREAM(p, pCcb->pScr->keyInd.keyData.ltk.ediv); memcpy(p, pCcb->pScr->keyInd.keyData.ltk.rand, SMP_RAND8_LEN); } else if ((keyDist & SMP_KEY_DIST_ID) && (pCcb->lastSentKey == 0 || pCcb->lastSentKey == SMP_CMD_MASTER_ID)) { /* send first part of IRK */ UINT8_TO_BSTREAM(p, SMP_CMD_ID_INFO); Calc128Cpy(p, DmSecGetLocalIrk()); } else if (pCcb->lastSentKey == SMP_CMD_ID_INFO) { /* send second part of IRK */ UINT8_TO_BSTREAM(p, SMP_CMD_ID_ADDR_INFO); UINT8_TO_BSTREAM(p, DM_ADDR_PUBLIC); BDA_TO_BSTREAM(p, HciGetBdAddr()); } else if ((keyDist & SMP_KEY_DIST_SIGN) && (pCcb->lastSentKey == 0 || pCcb->lastSentKey == SMP_CMD_ID_ADDR_INFO || pCcb->lastSentKey == SMP_CMD_MASTER_ID)) { /* send SRK */ UINT8_TO_BSTREAM(p, SMP_CMD_SIGN_INFO); Calc128Cpy(p, DmSecGetLocalCsrk()); } else { /* should never get here */ WsfMsgFree(pPkt); SMP_TRACE_WARN2("smpSendKey unexpected state keyDist:%d lastSentKey:%d", keyDist, pCcb->lastSentKey); return TRUE; } /* set last sent key to command code */ pCcb->lastSentKey = pPkt[L2C_PAYLOAD_START]; /* send command packet */ smpSendPkt(pCcb, pPkt); /* if flow not disabled set up to send next key */ if (!pCcb->flowDisabled) { if ((pHdr = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL) { pHdr->event = SMP_MSG_INT_SEND_NEXT_KEY; pHdr->param = pCcb->connId; WsfMsgSend(smpCb.handlerId, pHdr); } } } return FALSE; } /*************************************************************************************************/ /*! * \brief Process received key packet and pass it to DM if complete. * * \param pCcb Connection control block. * \param pKeyInd Key data structure allocated by caller. * \param pBuf Buffer containing packet. * \param keyDist Key distribution mask. * * \return TRUE if done receiving keys, FALSE otherwise. */ /*************************************************************************************************/ bool_t smpProcRcvKey(smpCcb_t *pCcb, dmSecKeyIndEvt_t *pKeyInd, uint8_t *pBuf, uint8_t keyDist) { bool_t keyIndReady = FALSE; bool_t done = FALSE; uint8_t cmdCode; /* go to start of packet */ pBuf += L2C_PAYLOAD_START; cmdCode = *pBuf++; if (cmdCode == SMP_CMD_ENC_INFO) { /* parse encryption information packet */ Calc128Cpy(pKeyInd->keyData.ltk.key, pBuf); } else if (cmdCode == SMP_CMD_MASTER_ID) { /* parse master identification packet */ BSTREAM_TO_UINT16(pKeyInd->keyData.ltk.ediv, pBuf); memcpy(pKeyInd->keyData.ltk.rand, pBuf, SMP_RAND8_LEN); pKeyInd->secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ? DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC; pKeyInd->type = DM_KEY_PEER_LTK; keyIndReady = TRUE; } else if (cmdCode == SMP_CMD_ID_INFO) { /* parse identity information packet */ Calc128Cpy(pKeyInd->keyData.irk.key, pBuf); } else if (cmdCode == SMP_CMD_ID_ADDR_INFO) { /* parse identity address information packet */ BSTREAM_TO_UINT8(pKeyInd->keyData.irk.addrType, pBuf); BSTREAM_TO_BDA(pKeyInd->keyData.irk.bdAddr, pBuf); pKeyInd->type = DM_KEY_IRK; keyIndReady = TRUE; } else if (cmdCode == SMP_CMD_SIGN_INFO) { /* parse signing information packet */ Calc128Cpy(pKeyInd->keyData.csrk.key, pBuf); pKeyInd->type = DM_KEY_CSRK; keyIndReady = TRUE; } /* set up to receive next key */ /* if just got first part of LTK or IRK */ if (pCcb->nextCmdCode == SMP_CMD_ENC_INFO || pCcb->nextCmdCode == SMP_CMD_ID_INFO) { /* wait for second part of LTK or IRK info */ pCcb->nextCmdCode++; } /* else if got LTK and need IRK */ else if ((keyDist & SMP_KEY_DIST_ID) && (pCcb->nextCmdCode == SMP_CMD_MASTER_ID)) { /* wait for first part of IRK */ pCcb->nextCmdCode = SMP_CMD_ID_INFO; } /* else if got LTK or IRK and need SRK */ else if ((keyDist & SMP_KEY_DIST_SIGN) && (pCcb->nextCmdCode == SMP_CMD_MASTER_ID || pCcb->nextCmdCode == SMP_CMD_ID_ADDR_INFO)) { /* wait for SRK */ pCcb->nextCmdCode = SMP_CMD_SIGN_INFO; } else { /* done receiving keys */ done = TRUE; } /* call callback if key ready */ if (keyIndReady) { pKeyInd->hdr.event = DM_SEC_KEY_IND; DmSmpCbackExec((dmEvt_t *) pKeyInd); } return done; } /*************************************************************************************************/ /*! * \brief Maximum unsuccessful pairing attempts reached. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActMaxAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg) { uint32_t timeout; /* send paring failed packet; note this stops the timer so call this first */ smpActPairingCancel(pCcb, pMsg); /* Check SMP device DB to determine time to wait before pairing can happen again */ timeout = SmpDbMaxAttemptReached(pCcb->connId); /* start wait interval timer */ pCcb->waitTimer.msg.event = SMP_MSG_INT_WI_TIMEOUT; WsfTimerStartMs(&pCcb->waitTimer, timeout); /* clear attempts count */ pCcb->attempts = 0; } /*************************************************************************************************/ /*! * \brief A pairing attempt was received while in 'repeated attempts' state. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActAttemptRcvd(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* set that attempt was received */ pCcb->attempts = 1; } /*************************************************************************************************/ /*! * \brief Notify DM of a pairing failure due to max attempt failures. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActNotifyDmAttemptsFailure(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* notify DM of pairing failure */ pMsg->hdr.status = SMP_ERR_ATTEMPTS; pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND; DmSmpCbackExec((dmEvt_t *) pMsg); } /*************************************************************************************************/ /*! * \brief Notify DM of a pairing failure due to response timeout. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActNotifyDmRspToFailure(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* notify DM of pairing failure */ pMsg->hdr.status = SMP_ERR_TIMEOUT; pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND; DmSmpCbackExec((dmEvt_t *) pMsg); } /*************************************************************************************************/ /*! * \brief Check if any pairing attempts received when leaving 'repeated attempts' state. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActCheckAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg) { /* check if attempt was received */ if (pCcb->attempts) { pCcb->attempts = 0; smpSendPairingFailed(pCcb, SMP_ERR_ATTEMPTS); /* notify DM of pairing failure */ smpActNotifyDmAttemptsFailure(pCcb, pMsg); smpCleanup(pCcb); } } /*************************************************************************************************/ /*! * \brief Pairing completed successfully. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpActPairingCmpl(smpCcb_t *pCcb, smpMsg_t *pMsg) { dmSecPairCmplIndEvt_t pairCmpl; smpCleanup(pCcb); /* set connection idle */ DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_IDLE); pairCmpl.auth = pCcb->auth; pairCmpl.hdr.param = pCcb->connId; pairCmpl.hdr.event = DM_SEC_PAIR_CMPL_IND; DmSmpCbackExec((dmEvt_t *) &pairCmpl); } /*************************************************************************************************/ /*! * \brief Execute the SMP state machine. * * \param pCcb Connection control block. * \param pMsg State machine message. * * \return None. */ /*************************************************************************************************/ void smpSmExecute(smpCcb_t *pCcb, smpMsg_t *pMsg) { smpTblEntry_t const *pTblEntry; smpSmIf_t const *pSmIf; #if SMP_EXTRA_TRACE == TRUE if (smpCb.lescSupported) SMP_TRACE_INFO2("SMP Exe: evt=%s st=%s", smpEventStr(pMsg->hdr.event), smpStateStr(pCcb->state)); else #endif SMP_TRACE_INFO2("smpSmExecute event=%d state=%d", pMsg->hdr.event, pCcb->state); /* look up state table for state */ pSmIf = DmConnRole(pCcb->connId) == DM_ROLE_SLAVE? smpCb.pSlave : smpCb.pMaster; pTblEntry = pSmIf->pStateTbl[pCcb->state]; /* run through state machine twice; once with state table for current state * and once with the state table for common events */ for(;;) { /* look for event match and execute action */ do { /* if match */ if ((*pTblEntry)[SMP_SM_POS_EVENT] == pMsg->hdr.event) { /* set next state */ pCcb->state = (*pTblEntry)[SMP_SM_POS_NEXT_STATE]; /* execute action */ (*pSmIf->pActionTbl[(*pTblEntry)[SMP_SM_POS_ACTION]])(pCcb, pMsg); return; } /* next entry */ pTblEntry++; /* while not at end */ } while ((*pTblEntry)[SMP_SM_POS_EVENT] != 0); /* if we've reached end of the common state table */ if (pTblEntry == (pSmIf->pCommonTbl + SMP_STATE_TBL_COMMON_MAX - 1)) { /* we're done */ break; } /* else we haven't run through common state table yet */ else { /* set it up */ pTblEntry = pSmIf->pCommonTbl; } } }