void smpSendPkt(smpCcb_t *pCcb, uint8_t *pPkt) { /* if flow disabled */ if (pCcb->flowDisabled) { /* if packet already queued discard it and replace it with this new packet */ if (pCcb->pQueued != NULL) { SMP_TRACE_WARN1("smpSendPkt packet discarded cmd:%d", pCcb->pQueued[L2C_PAYLOAD_START]); WsfMsgFree(pCcb->pQueued); } /* queue packet */ pCcb->pQueued = pPkt; } /* else send it to L2CAP */ else { L2cDataReq(L2C_CID_SMP, pCcb->handle, smpPktLenTbl[pPkt[L2C_PAYLOAD_START]], pPkt); } }
void attcSendMsg(dmConnId_t connId, uint16_t handle, uint8_t msgId, attcPktParam_t *pPkt, bool_t continuing) { attcCcb_t *pCcb; uint16_t mtu; bool_t transTimedOut; WsfTaskLock(); /* get CCB and verify connection still in use */ if ((pCcb = attcCcbByConnId(connId)) != NULL) { /* get MTU size */ mtu = pCcb->pMainCcb->mtu; transTimedOut = pCcb->pMainCcb->transTimedOut; } /* else connection not in use */ else { /* MTU size unknown */ mtu = 0; transTimedOut = FALSE; } WsfTaskUnlock(); /* if MTU size known for connection */ if (mtu > 0) { /* if no transaction's timed out */ if (!transTimedOut) { uint16_t dataLen = 0; /* if packet is not null then find out its length */ if (pPkt != NULL) { /* if not prepare write request */ if (msgId != ATTC_MSG_API_PREP_WRITE) { dataLen = pPkt->len; } /* else prepare write request */ else { /* if not continuing */ if (!continuing) { /* single prepare write request */ dataLen = ATT_PREP_WRITE_REQ_LEN + pPkt->w.len; } /* else will be sent as multiple prepare write requests */ } } /* if packet length is less than or equal to negotiated MTU */ if (dataLen <= mtu) { attcApiMsg_t *pMsg; /* allocate message buffer */ if ((pMsg = WsfMsgAlloc(sizeof(attcApiMsg_t))) != NULL) { /* set parameters */ pMsg->hdr.param = connId; pMsg->hdr.status = continuing; pMsg->hdr.event = msgId; pMsg->pPkt = pPkt; pMsg->handle = handle; /* send message */ WsfMsgSend(attCb.handlerId, pMsg); return; } } /* else packet length exceeds MTU size */ else { /* call callback with failure status */ attcExecCallback(connId, msgId, handle, ATT_ERR_MTU_EXCEEDED); } } else /* transaction's timed out */ { /* call callback with failure status */ attcExecCallback(connId, msgId, handle, ATT_ERR_TIMEOUT); } } /* alloc failed, transaction's timed out or packet length exceeded MTU size; free packet buffer */ if (pPkt != NULL) { WsfMsgFree(pPkt); } }
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; }
static void smpDmConnCback(dmEvt_t *pDmEvt) { smpCcb_t *pCcb; wsfMsgHdr_t hdr; pCcb = smpCcbByConnId((dmConnId_t) pDmEvt->hdr.param); /* if new connection created */ if (pDmEvt->hdr.event == DM_CONN_OPEN_IND) { /* set up state machine for master or slave */ if (DmConnRole((dmConnId_t) pDmEvt->hdr.param) == DM_ROLE_MASTER) { pCcb->initiator = TRUE; pCcb->nextCmdCode = SMP_CMD_SECURITY_REQ; } else { pCcb->initiator = FALSE; pCcb->nextCmdCode = SMP_CMD_PAIR_REQ; } /* initialize control block */ pCcb->handle = pDmEvt->connOpen.handle; pCcb->connId = (dmConnId_t) pDmEvt->hdr.param; pCcb->secReq = FALSE; pCcb->flowDisabled = FALSE; pCcb->attempts = SmpDbGetFailureCount((dmConnId_t) pDmEvt->hdr.param); pCcb->lastSentKey = 0; pCcb->state = 0; /* Resume the attempts state if necessary */ smpResumeAttemptsState((dmConnId_t) pDmEvt->hdr.param); } /* else if connection has been opened */ else if (pCcb->connId != DM_CONN_ID_NONE) { /* handle close */ if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND) { /* store attempts count */ SmpDbSetFailureCount((dmConnId_t) pDmEvt->hdr.param, pCcb->attempts); /* send to state machine */ hdr.param = pDmEvt->hdr.param; hdr.event = SMP_MSG_DM_CONN_CLOSE; hdr.status = pDmEvt->connClose.reason + DM_SEC_HCI_ERR_BASE; smpSmExecute(pCcb, (smpMsg_t *) &hdr); /* clear conn ID after handling event */ pCcb->connId = DM_CONN_ID_NONE; /* free queued packet buffer */ if (pCcb->pQueued != NULL) { WsfMsgFree(pCcb->pQueued); pCcb->pQueued = NULL; } } } }