initial commit
This commit is contained in:
+523
@@ -0,0 +1,523 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* control block */
|
||||
dmAdvCb_t dmAdvCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the advertising CB for a given handle.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvCbInit(uint8_t advHandle)
|
||||
{
|
||||
/* initialize control block */
|
||||
dmAdvCb.advType[advHandle] = DM_ADV_NONE;
|
||||
dmAdvCb.intervalMin[advHandle] = DM_GAP_ADV_SLOW_INT_MIN;
|
||||
dmAdvCb.intervalMax[advHandle] = DM_GAP_ADV_SLOW_INT_MAX;
|
||||
dmAdvCb.channelMap[advHandle] = DM_ADV_CHAN_ALL;
|
||||
dmCb.advFiltPolicy[advHandle] = HCI_ADV_FILT_NONE;
|
||||
dmAdvCb.advState[advHandle] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the legacy adv module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
dmAdvCbInit(i);
|
||||
}
|
||||
|
||||
dmAdvCb.advTimer.handlerId = dmCb.handlerId;
|
||||
dmCb.advAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an enhanced connection complete event.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param status Status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvGenConnCmpl(uint8_t advHandle, uint8_t status)
|
||||
{
|
||||
hciLeConnCmplEvt_t leConnCmpl;
|
||||
|
||||
/* generate enhanced connection complete event */
|
||||
memset(&leConnCmpl, 0, sizeof(leConnCmpl));
|
||||
|
||||
leConnCmpl.hdr.event = HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT;
|
||||
leConnCmpl.hdr.status = leConnCmpl.status = status;
|
||||
leConnCmpl.role = DM_ROLE_SLAVE;
|
||||
leConnCmpl.addrType = dmAdvCb.peerAddrType[advHandle];
|
||||
BdaCpy(leConnCmpl.peerAddr, dmAdvCb.peerAddr[advHandle]);
|
||||
|
||||
/* pass connection complete event to DM connection management module */
|
||||
dmDevPassHciEvtToConn((hciEvt_t *) &leConnCmpl);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising parameters using the given advertising type, and peer address.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advType Advertising type.
|
||||
* \param peerAddrType Peer address type.
|
||||
* \param pPeerAddr Peer address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvConfig(uint8_t advHandle, uint8_t advType, uint8_t peerAddrType, uint8_t *pPeerAddr)
|
||||
{
|
||||
dmAdvApiConfig_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiConfig_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_CONFIG;
|
||||
pMsg->advType = advType;
|
||||
pMsg->advHandle = advHandle;
|
||||
pMsg->peerAddrType = peerAddrType;
|
||||
BdaCpy(pMsg->peerAddr, pPeerAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising or scan response data to the given data.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Data operation.
|
||||
* \param location Data location.
|
||||
* \param len Length of the data. Maximum length is 236 bytes.
|
||||
* \param pData Pointer to the data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetData(uint8_t advHandle, uint8_t op, uint8_t location, uint8_t len, uint8_t *pData)
|
||||
{
|
||||
dmAdvApiSetData_t *pMsg;
|
||||
|
||||
WSF_ASSERT((location == DM_DATA_LOC_SCAN) || (location == DM_DATA_LOC_ADV));
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiSetData_t) + len)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_SET_DATA;
|
||||
pMsg->advHandle = advHandle;
|
||||
pMsg->op = op;
|
||||
pMsg->location = location;
|
||||
pMsg->len = len;
|
||||
memcpy(pMsg->pData, pData, len);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising using the given advertising set and duration.
|
||||
*
|
||||
* \param numSets Number of advertising sets to enable.
|
||||
* \param pAdvHandles Advertising handles array.
|
||||
* \param pDuration Advertising duration (in milliseconds) array.
|
||||
* \param pMaxEaEvents Maximum number of extended advertising events array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvStart(uint8_t numSets, uint8_t *pAdvHandles, uint16_t *pDuration, uint8_t *pMaxEaEvents)
|
||||
{
|
||||
uint8_t i;
|
||||
dmAdvApiStart_t *pMsg;
|
||||
|
||||
WSF_ASSERT(numSets <= DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_START;
|
||||
pMsg->numSets = numSets;
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
pMsg->advHandle[i] = pAdvHandles[i];
|
||||
pMsg->duration[i] = pDuration[i];
|
||||
pMsg->maxEaEvents[i] = pMaxEaEvents[i];
|
||||
}
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop advertising for the given advertising set. If the number of sets is set to 0
|
||||
* then all advertising sets are disabled.
|
||||
*
|
||||
* \param numSets Number of advertising sets to disable.
|
||||
* \param pAdvHandles Advertising handles array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvStop(uint8_t numSets, uint8_t *pAdvHandles)
|
||||
{
|
||||
uint8_t i;
|
||||
dmAdvApiStop_t *pMsg;
|
||||
|
||||
WSF_ASSERT(numSets <= DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_STOP;
|
||||
pMsg->numSets = numSets;
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
pMsg->advHandle[i] = pAdvHandles[i];
|
||||
}
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove an advertising set.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvRemoveAdvSet(uint8_t advHandle)
|
||||
{
|
||||
dmAdvApiRemove_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiRemove_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_REMOVE;
|
||||
pMsg->advHandle = advHandle;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear advertising sets.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvClearAdvSets(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_ADV_MSG_API_CLEAR;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random device address for a given advertising set.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pAddr Random device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetRandAddr(uint8_t advHandle, const uint8_t *pAddr)
|
||||
{
|
||||
dmAdvApiSetRandAddr_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiSetRandAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_SET_RAND_ADDR;
|
||||
pMsg->advHandle = advHandle;
|
||||
BdaCpy(pMsg->addr, pAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the minimum and maximum advertising intervals.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param intervalMin Minimum advertising interval.
|
||||
* \param intervalMax Maximum advertising interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetInterval(uint8_t advHandle, uint16_t intervalMin, uint16_t intervalMax)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
WsfTaskLock();
|
||||
dmAdvCb.intervalMin[advHandle] = intervalMin;
|
||||
dmAdvCb.intervalMax[advHandle] = intervalMax;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Include or exclude certain channels from the advertising channel map.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param channelMap Advertising channel map.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetChannelMap(uint8_t advHandle, uint8_t channelMap)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
WsfTaskLock();
|
||||
dmAdvCb.channelMap[advHandle] = channelMap;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used while advertising. This function can be used to
|
||||
* configure advertising to use a random address.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.advAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the value of an advertising data element in the given advertising or
|
||||
* scan response data. If the element already exists in the data then it is replaced
|
||||
* with the new value. If the element does not exist in the data it is appended
|
||||
* to it, space permitting.
|
||||
*
|
||||
* \param adType Advertising data element type.
|
||||
* \param len Length of the value. Maximum length is 29 bytes.
|
||||
* \param pValue Pointer to the value.
|
||||
* \param pAdvDataLen Advertising or scan response data length. The new length is returned
|
||||
* in this parameter.
|
||||
* \param pAdvData Pointer to advertising or scan response data.
|
||||
* \param advDataBufLen Length of the advertising or scan response data buffer maintained by
|
||||
* Application.
|
||||
*
|
||||
* \return TRUE if the element was successfully added to the data, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvSetAdValue(uint8_t adType, uint8_t len, uint8_t *pValue, uint16_t *pAdvDataLen,
|
||||
uint8_t *pAdvData, uint16_t advDataBufLen)
|
||||
{
|
||||
uint8_t *pElem;
|
||||
uint8_t *pNext;
|
||||
uint16_t totalLen;
|
||||
uint16_t newAdvDataLen;
|
||||
bool_t valueSet = FALSE;
|
||||
|
||||
/* find ad type in data */
|
||||
if ((pElem = DmFindAdType(adType, *pAdvDataLen, pAdvData)) != NULL)
|
||||
{
|
||||
/* if new length equals existing length */
|
||||
if ((len + 1) == pElem[DM_AD_LEN_IDX])
|
||||
{
|
||||
/* copy new ad value to data in existing location */
|
||||
memcpy(&pElem[DM_AD_DATA_IDX], pValue, len);
|
||||
valueSet = TRUE;
|
||||
}
|
||||
/* else if new value can replace old value and still fit */
|
||||
else
|
||||
{
|
||||
/* calculate the advertising data length if old element was replaced with new */
|
||||
newAdvDataLen = *pAdvDataLen + len + 1 - pElem[DM_AD_LEN_IDX];
|
||||
|
||||
/* if length is ok */
|
||||
if (newAdvDataLen <= advDataBufLen)
|
||||
{
|
||||
/* delete item (then we will replace it) */
|
||||
|
||||
/* get the start of element that follows the element to delete */
|
||||
totalLen = pElem[DM_AD_LEN_IDX] + 1;
|
||||
pNext = pElem + totalLen;
|
||||
|
||||
/* move data from start of next element to start of current item;
|
||||
* length is equal the data that remains after pNext
|
||||
*/
|
||||
memmove(pElem, pNext, *pAdvDataLen - (uint8_t)(pNext - pAdvData));
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen - totalLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if value not set */
|
||||
if (!valueSet)
|
||||
{
|
||||
/* if new value fits */
|
||||
if ((*pAdvDataLen + len + 2) <= advDataBufLen)
|
||||
{
|
||||
/* construct AD item in advertising data */
|
||||
pElem = &pAdvData[*pAdvDataLen];
|
||||
*pElem++ = len + 1;
|
||||
*pElem++ = adType;
|
||||
memcpy(pElem, pValue, len);
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen + len + 2;
|
||||
|
||||
valueSet = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the device name in the given advertising or scan response data. If the
|
||||
* device can only fit in the data if it is shortened, the name is shortened
|
||||
* and the AD type is changed to DM_ADV_TYPE_SHORT_NAME.
|
||||
*
|
||||
* \param len Length of the name. Maximum length is 29 bytes.
|
||||
* \param pValue Pointer to the name in UTF-8 format.
|
||||
* \param pAdvDataLen Advertising or scan response data length. The new length is returned
|
||||
* in this parameter.
|
||||
* \param pAdvData Pointer to advertising or scan response data.
|
||||
* \param advDataBufLen Length of the advertising or scan response data buffer maintained by
|
||||
* Application.
|
||||
*
|
||||
* \return TRUE if the element was successfully added to the data, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvSetName(uint8_t len, uint8_t *pValue, uint16_t *pAdvDataLen, uint8_t *pAdvData,
|
||||
uint16_t advDataBufLen)
|
||||
{
|
||||
uint8_t *pElem;
|
||||
uint8_t *pNext;
|
||||
uint16_t totalLen;
|
||||
uint8_t adType;
|
||||
|
||||
/* find name in data */
|
||||
if ((pElem = DmFindAdType(DM_ADV_TYPE_LOCAL_NAME, *pAdvDataLen, pAdvData)) == NULL)
|
||||
{
|
||||
pElem = DmFindAdType(DM_ADV_TYPE_SHORT_NAME, *pAdvDataLen, pAdvData);
|
||||
}
|
||||
|
||||
/* if found delete it */
|
||||
if (pElem != NULL)
|
||||
{
|
||||
/* get the start of element that follows the element to delete */
|
||||
totalLen = pElem[DM_AD_LEN_IDX] + 1;
|
||||
pNext = pElem + totalLen;
|
||||
|
||||
/* move data from start of next element to start of current item;
|
||||
* length is equal the data that remains after pNext
|
||||
*/
|
||||
memmove(pElem, pNext, *pAdvDataLen - (uint8_t)(pNext - pAdvData));
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen - totalLen;
|
||||
}
|
||||
|
||||
/* if name will fit */
|
||||
if (*pAdvDataLen <= (advDataBufLen - 2))
|
||||
{
|
||||
/* if full device name won't fit */
|
||||
if ((*pAdvDataLen + len + 2) > advDataBufLen)
|
||||
{
|
||||
/* adjust length so that it will fit */
|
||||
len = (advDataBufLen - 2) - *pAdvDataLen;
|
||||
|
||||
/* set ad type to shortened local name */
|
||||
adType = DM_ADV_TYPE_SHORT_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
adType = DM_ADV_TYPE_LOCAL_NAME;
|
||||
}
|
||||
|
||||
/* construct AD item in advertising data */
|
||||
pElem = &pAdvData[*pAdvDataLen];
|
||||
*pElem++ = len + 1;
|
||||
*pElem++ = adType;
|
||||
memcpy(pElem, pValue, len);
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen + len + 2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_ADV_H
|
||||
#define DM_ADV_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "sec_api.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM adv event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_ADV_MSG_API_CONFIG = DM_MSG_START(DM_ID_ADV),
|
||||
DM_ADV_MSG_API_SET_DATA,
|
||||
DM_ADV_MSG_API_START,
|
||||
DM_ADV_MSG_API_STOP,
|
||||
DM_ADV_MSG_API_REMOVE,
|
||||
DM_ADV_MSG_API_CLEAR,
|
||||
DM_ADV_MSG_API_SET_RAND_ADDR,
|
||||
DM_ADV_MSG_TIMEOUT
|
||||
};
|
||||
|
||||
/* DM adv periodic event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_ADV_PER_MSG_API_CONFIG = DM_MSG_START(DM_ID_ADV_PER),
|
||||
DM_ADV_PER_MSG_API_SET_DATA,
|
||||
DM_ADV_PER_MSG_API_START,
|
||||
DM_ADV_PER_MSG_API_STOP,
|
||||
};
|
||||
|
||||
/* DM advertising states */
|
||||
enum
|
||||
{
|
||||
DM_ADV_STATE_IDLE, /* idle */
|
||||
DM_ADV_STATE_ADVERTISING, /* advertising */
|
||||
DM_ADV_STATE_STARTING_DIRECTED, /* starting high duty cycle directed advertising */
|
||||
DM_ADV_STATE_STARTING, /* starting undirected or low duty cycle directed advertising */
|
||||
DM_ADV_STATE_STOPPING_DIRECTED, /* stopping high duty cycle directed advertising */
|
||||
DM_ADV_STATE_STOPPING, /* stopping undirected or low duty cycle directed advertising */
|
||||
DM_ADV_STATE_REMOVING_SET, /* removing advertising set */
|
||||
DM_ADV_STATE_CLEARING_SETS /* clearing all advertising sets */
|
||||
};
|
||||
|
||||
/* DM periodic advertising states */
|
||||
enum
|
||||
{
|
||||
DM_ADV_PER_STATE_IDLE,
|
||||
DM_ADV_PER_STATE_ADVERTISING,
|
||||
DM_ADV_PER_STATE_STARTING,
|
||||
DM_ADV_PER_STATE_STOPPING
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t advType;
|
||||
uint8_t peerAddrType;
|
||||
bdAddr_t peerAddr;
|
||||
bool_t scanReqNotifEna;
|
||||
} dmAdvApiConfig_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_SET_DATA */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t op;
|
||||
uint8_t location;
|
||||
uint8_t len;
|
||||
uint8_t pData[];
|
||||
} dmAdvApiSetData_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t numSets;
|
||||
uint8_t advHandle[DM_NUM_ADV_SETS];
|
||||
uint16_t duration[DM_NUM_ADV_SETS];
|
||||
uint8_t maxEaEvents[DM_NUM_ADV_SETS];
|
||||
} dmAdvApiStart_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t numSets;
|
||||
uint8_t advHandle[DM_NUM_ADV_SETS];
|
||||
} dmAdvApiStop_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_REMOVE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvApiRemove_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_SET_RAND_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
bdAddr_t addr;
|
||||
} dmAdvApiSetRandAddr_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiConfig_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_SET_DATA */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t op;
|
||||
uint8_t len;
|
||||
uint8_t pData[];
|
||||
} dmAdvPerApiSetData_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiStart_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiStop_t;
|
||||
|
||||
/* Union of all adv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmAdvApiConfig_t apiConfig;
|
||||
dmAdvApiSetData_t apiSetData;
|
||||
dmAdvApiStart_t apiStart;
|
||||
dmAdvApiStop_t apiStop;
|
||||
dmAdvApiRemove_t apiRemove;
|
||||
dmAdvApiSetRandAddr_t apiSetRandAddr;
|
||||
dmAdvPerApiConfig_t apiPerConfig;
|
||||
dmAdvPerApiSetData_t apiPerSetData;
|
||||
dmAdvPerApiStart_t apiPerStart;
|
||||
dmAdvPerApiStop_t apiPerStop;
|
||||
secAes_t aes;
|
||||
} dmAdvMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmAdvAct_t)(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* Control block for advertising module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t advTimer;
|
||||
uint16_t intervalMin[DM_NUM_ADV_SETS];
|
||||
uint16_t intervalMax[DM_NUM_ADV_SETS];
|
||||
uint8_t advType[DM_NUM_ADV_SETS];
|
||||
uint8_t channelMap[DM_NUM_ADV_SETS];
|
||||
uint8_t localAddrType;
|
||||
uint8_t advState[DM_NUM_ADV_SETS];
|
||||
uint16_t advDuration[DM_NUM_ADV_SETS];
|
||||
bool_t advEnabled;
|
||||
bdAddr_t peerAddr[DM_NUM_ADV_SETS];
|
||||
uint8_t peerAddrType[DM_NUM_ADV_SETS];
|
||||
} dmAdvCb_t;
|
||||
|
||||
extern dmAdvCb_t dmAdvCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* legacy adv component inteface */
|
||||
void dmAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmAdvReset(void);
|
||||
|
||||
/* legacy adv action functions */
|
||||
void dmAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActStop(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActRemoveSet(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActClearSets(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActSetRandAddr(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActTimeout(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* extended adv component inteface */
|
||||
void dmExtAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmExtAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmExtAdvReset(void);
|
||||
|
||||
/* extended adv action functions */
|
||||
void dmExtAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActStop(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActRemoveSet(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActClearSets(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActSetRandAddr(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActTimeout(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* periodic adv action functions */
|
||||
void dmPerAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActStop(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* periodic adv component inteface */
|
||||
void dmPerAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPerAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmPerAdvReset(void);
|
||||
|
||||
/* legacy adv directed advertising interface */
|
||||
void dmAdvStartDirected(uint8_t advType, uint16_t duration, uint8_t addrType, uint8_t *pAddr);
|
||||
void dmAdvStopDirected(void);
|
||||
void dmAdvConnected(void);
|
||||
void dmAdvConnectFailed(void);
|
||||
|
||||
/* extended adv directed advertising interface */
|
||||
void dmExtAdvStartDirected(dmConnId_t connId, uint8_t advHandle, uint8_t advType,
|
||||
uint16_t duration, uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr);
|
||||
void dmExtAdvStopDirected(dmConnId_t connId);
|
||||
void dmExtAdvConnected(dmConnId_t connId);
|
||||
void dmExtAdvConnectFailed(dmConnId_t connId);
|
||||
|
||||
/* adv utility functions */
|
||||
void dmAdvInit(void);
|
||||
void dmAdvCbInit(uint8_t advHandle);
|
||||
void dmAdvGenConnCmpl(uint8_t advHandle, uint8_t status);
|
||||
|
||||
/* extended and periodic adv utility functions */
|
||||
void dmExtAdvInit(void);
|
||||
void dmPerAdvInit(void);
|
||||
uint8_t dmPerAdvState(uint8_t advHandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_ADV_H */
|
||||
+1941
File diff suppressed because it is too large
Load Diff
Vendored
+562
@@ -0,0 +1,562 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block for legacy advertising module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t advType; /*!< Advertising type. */
|
||||
} dmLegAdvCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmAdvAct_t dmAdvAct[] =
|
||||
{
|
||||
dmAdvActConfig,
|
||||
dmAdvActSetData,
|
||||
dmAdvActStart,
|
||||
dmAdvActStop,
|
||||
dmAdvActRemoveSet,
|
||||
dmAdvActClearSets,
|
||||
dmAdvActSetRandAddr,
|
||||
dmAdvActTimeout
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmAdvFcnIf =
|
||||
{
|
||||
dmAdvReset,
|
||||
dmAdvHciHandler,
|
||||
dmAdvMsgHandler
|
||||
};
|
||||
|
||||
/* control block */
|
||||
static dmLegAdvCb_t dmLegAdvCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising parameters using the given advertising type, and peer address.
|
||||
*
|
||||
* \param advType Advertising type.
|
||||
* \param peerAddrType Peer address type.
|
||||
* \param pPeerAddr Peer address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmAdvConfig(uint8_t advType, uint8_t peerAddrType, uint8_t *pPeerAddr)
|
||||
{
|
||||
/* set advertising parameters */
|
||||
HciLeSetAdvParamCmd(dmAdvCb.intervalMin[DM_ADV_HANDLE_DEFAULT], /* advIntervalMin */
|
||||
dmAdvCb.intervalMax[DM_ADV_HANDLE_DEFAULT], /* advIntervalMax */
|
||||
advType, /* advType */
|
||||
DmLlAddrType(dmCb.advAddrType), /* ownAddrType */
|
||||
peerAddrType, /* peerAddrType */
|
||||
pPeerAddr, /* pPeerAddr */
|
||||
dmAdvCb.channelMap[DM_ADV_HANDLE_DEFAULT], /* advChanMap */
|
||||
dmCb.advFiltPolicy[DM_ADV_HANDLE_DEFAULT]); /* advFiltPolicy */
|
||||
|
||||
/* store advertising type */
|
||||
dmLegAdvCb.advType = advType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActConfig(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActConfig: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("DmAdvConfig during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set advertising parameters */
|
||||
dmAdvConfig(pMsg->apiConfig.advType, pMsg->apiConfig.peerAddrType, pMsg->apiConfig.peerAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising or scan response data to the given data.
|
||||
*
|
||||
* \param location Data location.
|
||||
* \param len Length of the data. Maximum length is 31 bytes.
|
||||
* \param pData Pointer to the data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActSetData(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
WSF_ASSERT(pMsg->apiSetData.len <= HCI_ADV_DATA_LEN);
|
||||
|
||||
DM_TRACE_INFO1("dmAdvActSetData: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* set new data in HCI */
|
||||
if (pMsg->apiSetData.location == DM_DATA_LOC_ADV)
|
||||
{
|
||||
HciLeSetAdvDataCmd(pMsg->apiSetData.len, pMsg->apiSetData.pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
HciLeSetScanRespDataCmd(pMsg->apiSetData.len, pMsg->apiSetData.pData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActStart(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActStart: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("dmAdvActStart during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STARTING;
|
||||
dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] = pMsg->apiStart.duration[DM_ADV_HANDLE_DEFAULT];
|
||||
HciLeSetAdvEnableCmd(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActStop(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActStop: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("DmAdvStop during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove an advertising set action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActRemoveSet(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear advertising sets action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActClearSets(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random device address for a given advertising set.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActSetRandAddr(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an advertising timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActTimeout(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO0("dmAdvActTimeout!");
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING)
|
||||
{
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the legacy adv module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvReset(void)
|
||||
{
|
||||
wsfMsgHdr_t advStop;
|
||||
|
||||
/* if stopping undirected advertisement or advertising but not high duty cycle directed adv */
|
||||
if ((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STOPPING) ||
|
||||
((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING) &&
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] != DM_ADV_CONN_DIRECT)))
|
||||
{
|
||||
/* stop advertising timer */
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* generate advertising stop event */
|
||||
advStop.status = HCI_SUCCESS;
|
||||
advStop.event = DM_ADV_STOP_IND;
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) &advStop);
|
||||
}
|
||||
|
||||
/* reset legacy adv module */
|
||||
dmAdvInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM adv HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
if (pEvent->hdr.event == HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
uint8_t cbackEvent = 0;
|
||||
|
||||
DM_TRACE_INFO1("HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
switch (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT])
|
||||
{
|
||||
case DM_ADV_STATE_STARTING:
|
||||
case DM_ADV_STATE_STARTING_DIRECTED:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING)
|
||||
{
|
||||
/* start advertising timer if applicable */
|
||||
if (dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] > 0)
|
||||
{
|
||||
dmAdvCb.advTimer.msg.event = DM_ADV_MSG_TIMEOUT;
|
||||
WsfTimerStartMs(&dmAdvCb.advTimer, dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT]);
|
||||
}
|
||||
|
||||
/* Application callbacks only sent in undirected state */
|
||||
if (dmLegAdvCb.advType != DM_ADV_CONN_DIRECT_LO_DUTY)
|
||||
{
|
||||
cbackEvent = DM_ADV_START_IND;
|
||||
}
|
||||
}
|
||||
|
||||
/* pass advertising start event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_START, DM_ADV_START_IND, 0, 0);
|
||||
|
||||
/* store advertising type and state */
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = dmLegAdvCb.advType;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_ADVERTISING;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_ADV_STATE_STOPPING:
|
||||
case DM_ADV_STATE_STOPPING_DIRECTED:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STOPPING)
|
||||
{
|
||||
/* stop advertising timer */
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* Application and DM callbacks only sent in undirected or low duty cycle directed state */
|
||||
if (dmLegAdvCb.advType == DM_ADV_CONN_DIRECT_LO_DUTY)
|
||||
{
|
||||
cbackEvent = HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT;
|
||||
}
|
||||
else
|
||||
{
|
||||
cbackEvent = DM_ADV_STOP_IND;
|
||||
}
|
||||
}
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
/* store advertising type and state */
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_ADVERTISING;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore the event */
|
||||
break;
|
||||
}
|
||||
|
||||
/* if DM conn notify needed */
|
||||
if (cbackEvent == HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmAdvGenConnCmpl(DM_ADV_HANDLE_DEFAULT, HCI_ERR_ADV_TIMEOUT);
|
||||
}
|
||||
/* else if app callback needed */
|
||||
else if (cbackEvent)
|
||||
{
|
||||
pEvent->hdr.event = cbackEvent;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM adv event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmAdvAct[DM_MSG_MASK(pMsg->event)])((dmAdvMsg_t *)pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start directed advertising.
|
||||
*
|
||||
* \param advType Advertising type.
|
||||
* \param duration Advertising duration (in ms).
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvStartDirected(uint8_t advType, uint16_t duration, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvStartDirected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
/* if not advertising */
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* start advertising */
|
||||
HciLeSetAdvEnableCmd(TRUE);
|
||||
|
||||
/* store advertising info */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = (advType == DM_ADV_CONN_DIRECT) ? \
|
||||
DM_ADV_STATE_STARTING_DIRECTED : DM_ADV_STATE_STARTING;
|
||||
|
||||
dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] = duration;
|
||||
BdaCpy(dmAdvCb.peerAddr[DM_ADV_HANDLE_DEFAULT], pAddr);
|
||||
dmAdvCb.peerAddrType[DM_ADV_HANDLE_DEFAULT] = addrType;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop directed advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvStopDirected(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvStopDirected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
/* if advertising or starting advertising */
|
||||
if ((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING) ||
|
||||
(dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING) ||
|
||||
(dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING_DIRECTED))
|
||||
{
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = (dmLegAdvCb.advType == DM_ADV_CONN_DIRECT) ? \
|
||||
DM_ADV_STATE_STOPPING_DIRECTED : DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called when a connection is established from directed advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvConnected(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvConnected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called when a directed advertising connection fails.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvConnectFailed(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvConnectFailed: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM legacy advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvInit(void)
|
||||
{
|
||||
WsfTaskLock();
|
||||
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_ADV] = (dmFcnIf_t *) &dmAdvFcnIf;
|
||||
|
||||
/* initialize legacy adv module */
|
||||
dmAdvInit();
|
||||
|
||||
/* clear set advertising set random address callback */
|
||||
dmDevCb.advSetRandAddrCback = NULL;
|
||||
|
||||
/* initialize HCI VS module */
|
||||
HciVsInit(0);
|
||||
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether DM advertising is in legacy mode.
|
||||
*
|
||||
* \return TRUE if DM advertising is in legacy mode. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvModeLeg(void)
|
||||
{
|
||||
return (dmFcnIfTbl[DM_ID_ADV] == (dmFcnIf_t *) &dmAdvFcnIf) ? TRUE : FALSE;
|
||||
}
|
||||
+1595
File diff suppressed because it is too large
Load Diff
+369
@@ -0,0 +1,369 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM connection management module.
|
||||
*
|
||||
* Copyright (c) 2016-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_CONN_H
|
||||
#define DM_CONN_H
|
||||
|
||||
#include "dm_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Uninitialized HCI handle */
|
||||
#define DM_CONN_HCI_HANDLE_NONE 0xFFFF
|
||||
|
||||
/* Action set initializer */
|
||||
#define DM_CONN_ACT_SET_INIT(n) ((n) << 4)
|
||||
|
||||
/* Get action set ID from action */
|
||||
#define DM_CONN_ACT_SET_ID(action) ((action) >> 4)
|
||||
|
||||
/* Get action ID from action */
|
||||
#define DM_CONN_ACT_ID(action) ((action) & 0x0F)
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM conn event handler messages for state machine */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_CONN_MSG_API_OPEN = DM_MSG_START(DM_ID_CONN), /*!< Open Connection */
|
||||
DM_CONN_MSG_API_CLOSE, /*!< Close Connection */
|
||||
DM_CONN_MSG_API_ACCEPT, /*!< Accept Connection */
|
||||
DM_CONN_MSG_API_UPDATE_MASTER, /*!< Master Connection Parameter Update */
|
||||
DM_CONN_MSG_API_UPDATE_SLAVE, /*!< Slave Connecteion Parameter Update */
|
||||
|
||||
/* messages from L2C */
|
||||
DM_CONN_MSG_L2C_UPDATE_IND, /*!< L2CAP Parameter update indication */
|
||||
DM_CONN_MSG_L2C_UPDATE_CNF, /*!< L2CAP Parameter update confirmation */
|
||||
|
||||
/* messages from HCI */
|
||||
DM_CONN_MSG_HCI_LE_CONN_CMPL_FAIL, /*!< HCI LE Connection Complete Failure Event */
|
||||
DM_CONN_MSG_HCI_LE_CONN_CMPL, /*!< HCI LE Connection Compelte Event */
|
||||
DM_CONN_MSG_HCI_DISCONNECT_CMPL, /*!< HCI Disconnection Complete Event */
|
||||
DM_CONN_MSG_HCI_LE_CONN_UPDATE_CMPL, /*!< HCI LE Connection Update Complete Event */
|
||||
DM_CONN_MSG_HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL, /*!< HCI LE Create Connection Cancel Command Complet Event */
|
||||
|
||||
/* other internal messages */
|
||||
DM_CONN_MSG_INT_UPDATE_TIMEOUT /*!< Internal Update Timeout */
|
||||
};
|
||||
|
||||
/* Number of messages */
|
||||
#define DM_CONN_NUM_MSGS (DM_CONN_MSG_INT_UPDATE_TIMEOUT - DM_CONN_MSG_API_OPEN + 1)
|
||||
|
||||
/* DM conn event handler messages, non-state machine */
|
||||
enum
|
||||
{
|
||||
DM_CONN_MSG_API_FEAT = DM_MSG_START(DM_ID_CONN_2),
|
||||
DM_CONN_MSG_API_READ_RSSI,
|
||||
DM_CONN_MSG_API_REM_CONN_PARAM_REQ_REPLY,
|
||||
DM_CONN_MSG_API_REM_CONN_PARAM_REQ_NEG_REPLY,
|
||||
DM_CONN_MSG_API_SET_DATA_LEN,
|
||||
DM_CONN_MSG_API_WRITE_AUTH_TO,
|
||||
|
||||
/* messages from HCI */
|
||||
DM_CONN_MSG_HCI_READ_RSSI_CMPL,
|
||||
DM_CONN_MSG_HCI_FEAT_CMPL
|
||||
};
|
||||
|
||||
/* State machine action function sets */
|
||||
enum
|
||||
{
|
||||
DM_CONN_ACT_SET_MAIN,
|
||||
DM_CONN_ACT_SET_MASTER,
|
||||
DM_CONN_ACT_SET_SLAVE,
|
||||
DM_CONN_NUM_ACT_SETS
|
||||
};
|
||||
|
||||
/*! State machine actions */
|
||||
enum
|
||||
{
|
||||
DM_CONN_SM_ACT_NONE = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_MAIN), /*!< No Action */
|
||||
DM_CONN_SM_ACT_CLOSE, /*!< Process Connection Close */
|
||||
DM_CONN_SM_ACT_CONN_OPENED, /*!< Procoess Connection Opened */
|
||||
DM_CONN_SM_ACT_CONN_FAILED, /*!< Process Connection Failed */
|
||||
DM_CONN_SM_ACT_CONN_CLOSED, /*!< Process Connection Closed */
|
||||
DM_CONN_SM_ACT_HCI_UPDATED, /*!< Process HCI Connection Update */
|
||||
|
||||
DM_CONN_SM_ACT_OPEN = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_MASTER), /*!< Process Master Connection Open */
|
||||
DM_CONN_SM_ACT_CANCEL_OPEN, /*!< Process Master Cancel Connection Open */
|
||||
DM_CONN_SM_ACT_UPDATE_MASTER, /*!< Process Master Connection Parameter Update */
|
||||
DM_CONN_SM_ACT_L2C_UPDATE_IND, /*!< Process Master L2CAP Connection Parameter Update Indication */
|
||||
|
||||
DM_CONN_SM_ACT_ACCEPT = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_SLAVE), /*!< Process Slave Connection Accept */
|
||||
DM_CONN_SM_ACT_CANCEL_ACCEPT, /*!< Process Slave Cancel Connection Accept */
|
||||
DM_CONN_SM_ACT_UPDATE_SLAVE, /*!< Process Slave Connection Update */
|
||||
DM_CONN_SM_ACT_CONN_ACCEPTED, /*!< Process Slave Connection Accepted */
|
||||
DM_CONN_SM_ACT_ACCEPT_FAILED, /*!< Process Slave Connection Accept Failure */
|
||||
DM_CONN_SM_ACT_L2C_UPDATE_CNF /*!< Process Slave L2CAP Connection Parameter Update Confirmation */
|
||||
};
|
||||
|
||||
/*! State machine states */
|
||||
enum
|
||||
{
|
||||
DM_CONN_SM_ST_IDLE, /*!< Idle State */
|
||||
DM_CONN_SM_ST_CONNECTING, /*!< Connecting State */
|
||||
DM_CONN_SM_ST_ACCEPTING, /*!< Accepting State */
|
||||
DM_CONN_SM_ST_CONNECTED, /*!< Connected State */
|
||||
DM_CONN_SM_ST_DISCONNECTING, /*!< Disconnecting State */
|
||||
DM_CONN_SM_NUM_STATES
|
||||
};
|
||||
|
||||
/* Data structure for DM_CONN_MSG_API_OPEN and DM_CONN_MSG_API_ACCEPT */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t initPhys;
|
||||
uint8_t advHandle;
|
||||
uint8_t advType;
|
||||
uint16_t duration;
|
||||
uint8_t maxEaEvents;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t addrType;
|
||||
uint8_t clientId;
|
||||
} dmConnApiOpen_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_CLOSE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t reason;
|
||||
uint8_t clientId;
|
||||
} dmConnApiClose_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_UPDATE_MASTER and SLAVE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t connSpec;
|
||||
} dmConnApiUpdate_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_L2C_UPDATE_IND */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t *pConnSpec;
|
||||
uint8_t identifier;
|
||||
} dmConnL2cUpdateInd_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_L2C_UPDATE_CNF */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t result;
|
||||
} dmConnL2cUpdateCnf_t;
|
||||
|
||||
/*! Union of all DM Conn state machine messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmConnApiOpen_t apiOpen;
|
||||
dmConnApiClose_t apiClose;
|
||||
dmConnApiUpdate_t apiUpdate;
|
||||
dmConnL2cUpdateInd_t l2cUpdateInd;
|
||||
dmConnL2cUpdateCnf_t l2cUpdateCnf;
|
||||
hciLeConnCmplEvt_t hciLeConnCmpl;
|
||||
hciDisconnectCmplEvt_t hciDisconnectCmpl;
|
||||
hciLeConnUpdateCmplEvt_t hciLeConnUpdateCmpl;
|
||||
} dmConnMsg_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_FEAT */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t handle;
|
||||
uint8_t type;
|
||||
uint8_t feature;
|
||||
} dmConnApiFeat_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_READ_RSSI */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
} dmConnApiReadRssi_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_REM_CONN_PARAM_REQ_REPLY */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t connSpec;
|
||||
} dmConnApiRemConnParamReqReply_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_REM_CONN_PARAM_REQ_NEG_REPLY */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t reason;
|
||||
} dmConnApiRemConnParamReqNegReply_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_SET_DATA_LEN */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t txOctets;
|
||||
uint16_t txTime;
|
||||
} dmConnApiSetDataLen_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_WRITE_AUTH_TO */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t timeout;
|
||||
} dmConnApiWriteAuthPayloadTo_t;
|
||||
|
||||
/*! Union of all DM Conn 2 messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmConnApiFeat_t apiFeat;
|
||||
dmConnApiReadRssi_t apiReadRssi;
|
||||
dmConnApiRemConnParamReqReply_t apiRemConnParamReqReply;
|
||||
dmConnApiRemConnParamReqNegReply_t apiRemConnParamReqNegReply;
|
||||
dmConnApiSetDataLen_t apiSetDataLen;
|
||||
dmConnApiWriteAuthPayloadTo_t apiWriteAuthPayloadTo;
|
||||
} dmConn2Msg_t;
|
||||
|
||||
/*! Connection control block */
|
||||
typedef struct
|
||||
{
|
||||
bdAddr_t peerAddr;
|
||||
bdAddr_t localAddr;
|
||||
uint16_t handle;
|
||||
uint16_t idleMask;
|
||||
dmConnId_t connId;
|
||||
bool_t updating;
|
||||
bool_t usingLtk;
|
||||
uint8_t peerAddrType;
|
||||
uint8_t localAddrType;
|
||||
uint8_t state;
|
||||
uint8_t inUse;
|
||||
uint8_t secLevel;
|
||||
uint8_t tmpSecLevel;
|
||||
uint8_t role;
|
||||
|
||||
/* enhanced fields */
|
||||
bdAddr_t localRpa;
|
||||
bdAddr_t peerRpa;
|
||||
|
||||
uint32_t features;
|
||||
bool_t featuresPresent;
|
||||
} dmConnCcb_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmConnAct_t)(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/*! Control block of the DM conn module */
|
||||
typedef struct
|
||||
{
|
||||
dmConnCcb_t ccb[DM_CONN_MAX];
|
||||
dmCback_t connCback[DM_CLIENT_ID_MAX];
|
||||
hciConnSpec_t connSpec[DM_NUM_PHYS];
|
||||
uint16_t scanInterval[DM_NUM_PHYS];
|
||||
uint16_t scanWindow[DM_NUM_PHYS];
|
||||
} dmConnCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! State machine action sets */
|
||||
extern dmConnAct_t *dmConnActSet[DM_CONN_NUM_ACT_SETS];
|
||||
|
||||
/*! Control block */
|
||||
extern dmConnCb_t dmConnCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* utility functions */
|
||||
dmConnCcb_t *dmConnCcbAlloc(uint8_t *pAddr);
|
||||
void dmConnCcbDealloc(dmConnCcb_t *pCcb);
|
||||
dmConnCcb_t *dmConnCcbByHandle(uint16_t handle);
|
||||
dmConnCcb_t *dmConnCcbByBdAddr(uint8_t *pAddr);
|
||||
dmConnCcb_t *dmConnCcbById(dmConnId_t connId);
|
||||
uint8_t dmConnNum(void);
|
||||
dmConnId_t dmConnOpenAccept(uint8_t clientId, uint8_t initPhys, uint8_t advHandle, uint8_t advType,
|
||||
uint16_t duration, uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr,
|
||||
uint8_t role);
|
||||
void dmConnExecCback(dmConnMsg_t *pMsg);
|
||||
|
||||
/* component inteface */
|
||||
void dmConnReset(void);
|
||||
void dmConnMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmConnHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* component 2 inteface */
|
||||
void dmConn2MsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmConn2HciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* state machine */
|
||||
void dmConnSmExecute(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* main action functions */
|
||||
void dmConnSmActNone(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActClose(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnOpened(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnClosed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActHciUpdated(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* common master action functions */
|
||||
void dmConnSmActCancelOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActUpdateMaster(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActL2cUpdateInd(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* legacy master action functions */
|
||||
void dmConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* extended master action functions */
|
||||
void dmExtConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* common slave action functions */
|
||||
void dmConnSmActUpdateSlave(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActL2cUpdateCnf(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* legacy slave action functions */
|
||||
void dmConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* extended slave action functions */
|
||||
void dmExtConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_CONN_H */
|
||||
Vendored
+840
@@ -0,0 +1,840 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager Connection Constant Tone Extension (CTE) module.
|
||||
*
|
||||
* Copyright (c) 2018-2019 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM connection CTE states */
|
||||
enum
|
||||
{
|
||||
DM_CONN_CTE_STATE_IDLE, /*!< Idle */
|
||||
DM_CONN_CTE_STATE_INITIATING, /*!< Initiating CTE request */
|
||||
DM_CONN_CTE_STATE_RESPONDING, /*!< Responding to CTE request */
|
||||
DM_CONN_CTE_STATE_SAMPLING, /*!< Sampling received CTE */
|
||||
DM_CONN_CTE_STATE_STARTING, /*!< Starting CTE request, CTE response or sampling received CTE */
|
||||
DM_CONN_CTE_STATE_STOPPING, /*!< Stopping CTE request, CTE response or sampling received CTE */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RX_SAMPLE_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint8_t slotDurations; /*!< Switching and sampling slot durations */
|
||||
uint8_t switchPatternLen; /*!< Number of Antenna IDs in switching pattern */
|
||||
uint8_t *pAntennaIDs; /*!< List of Antenna IDs in switching pattern */
|
||||
} dmConnCteApiRxSampleStart_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiRxSampleStop_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_TX_CFG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint8_t cteTypeBits; /*!< Permitted CTE type bits */
|
||||
uint8_t switchPatternLen; /*!< Number of Antenna IDs in switching pattern */
|
||||
uint8_t *pAntennaIDs; /*!< List of Antenna IDs in switching pattern */
|
||||
} dmConnCteApiTxConfig_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_REQ_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint16_t cteReqInt; /*!< CTE request interval */
|
||||
uint8_t reqCteLen; /*!< Minimum length of CTE being requested in 8 us units */
|
||||
uint8_t reqCteType; /*!< Requested CTE type */
|
||||
} dmConnCteApiReqStart_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_REQ_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiReqStop_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RSP_START and DM_CONN_CTE_MSG_API_RSP_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiRspEnable_t;
|
||||
|
||||
/*! Union of all DM Connection CTE API messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnCteApiRxSampleStart_t rxSampleStart; /*!< Start sampling received CTE, and configure CTE Rx parameters to be used */
|
||||
dmConnCteApiRxSampleStop_t rxSampleStop; /*!< Stop sampling received CTE */
|
||||
dmConnCteApiTxConfig_t txCfg; /*!< Configure CTE Tx parameters */
|
||||
dmConnCteApiReqStart_t reqStart; /*!< Start initiating CTE request */
|
||||
dmConnCteApiReqStop_t reqStop; /*!< Stop initiating CTE request */
|
||||
dmConnCteApiRspEnable_t rspEnable; /*!< Start or stop responding to CTE request */
|
||||
} dmConnCteMsg_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmConnCteAct_t)(dmConnCteMsg_t *pMsg);
|
||||
|
||||
/*! Control block for connection CTE module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rxSampleState; /*!< Sampling received CTE state */
|
||||
uint8_t reqState; /*!< Connection CTE Request state */
|
||||
uint8_t rspState; /*!< Connection CTE Response state */
|
||||
} dmConnCteCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
void dmConnCteInit(void);
|
||||
void dmConnCteReset(void);
|
||||
void dmConnCteHciHandler(hciEvt_t *pEvent);
|
||||
void dmConnCteMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*! Action functions */
|
||||
static void dmConnCteActRxSampleStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRxSampleStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActTxCfg(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActReqStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActReqStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRspStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRspStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActState(dmConnCteMsg_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table */
|
||||
static const dmConnCteAct_t dmConnCteAct[] =
|
||||
{
|
||||
dmConnCteActRxSampleStart,
|
||||
dmConnCteActRxSampleStop,
|
||||
dmConnCteActTxCfg,
|
||||
dmConnCteActReqStart,
|
||||
dmConnCteActReqStop,
|
||||
dmConnCteActRspStart,
|
||||
dmConnCteActRspStop,
|
||||
dmConnCteActState
|
||||
};
|
||||
|
||||
/*! DM Connection CTE component function interface */
|
||||
static const dmFcnIf_t dmConnCteFcnIf =
|
||||
{
|
||||
dmConnCteReset,
|
||||
dmConnCteHciHandler,
|
||||
dmConnCteMsgHandler
|
||||
};
|
||||
|
||||
/*! Connection CTE control block */
|
||||
static dmConnCteCb_t dmConnCteCb[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize connection CTE control block entry.
|
||||
*
|
||||
* \param pCteCb Pointer to connection CTE control block structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteCbInit(dmConnCteCb_t *pCteCb)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize connection CTE control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
dmConnCteCbInit(&dmConnCteCb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM Connection Constant Tone Extension (CTE) module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteInit(void)
|
||||
{
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_CONN_CTE] = (dmFcnIf_t *) &dmConnCteFcnIf;
|
||||
|
||||
/* initialize control block */
|
||||
dmConnCteInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the connection CTE module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteReset(void)
|
||||
{
|
||||
/* reset control block */
|
||||
dmConnCteInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_READ_ANTENNA_INFO_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if ccb found */
|
||||
if ((pCcb = dmConnCcbByHandle(pEvent->hdr.param)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* set conn id */
|
||||
pEvent->hdr.param = pCcb->connId;
|
||||
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_CONN_IQ_REPORT_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CONN_IQ_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CTE_REQ_FAILED_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CTE_REQ_FAIL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_CONN_CTE_RX_PARAMS_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling sampling */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_SAMPLING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RX_SAMPLE_START_IND;
|
||||
}
|
||||
/* else if disabling sampling */
|
||||
else if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_SAMPLING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RX_SAMPLE_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_CONN_CTE_TX_PARAMS_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CONN_CTE_TX_CFG_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CONN_CTE_REQ_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling request */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_INITIATING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_REQ_START_IND;
|
||||
}
|
||||
/* else if disabing request */
|
||||
else if (pCteCb->reqState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_INITIATING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_REQ_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CONN_CTE_RSP_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling response */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_RESPONDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RSP_START_IND;
|
||||
}
|
||||
/* else if disabling response */
|
||||
else if (pCteCb->rspState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_RESPONDING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RSP_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM Connection CTE event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmConnCteAct[DM_MSG_MASK(pMsg->event)])((dmConnCteMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start sampling received CTE, and configure CTE receive parameters action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActRxSampleStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rxSampleStart.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeSetConnCteRxParamsCmd(pCcb->handle, TRUE, pMsg->rxSampleStart.slotDurations,
|
||||
pMsg->rxSampleStart.switchPatternLen,
|
||||
pMsg->rxSampleStart.pAntennaIDs);
|
||||
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRxSampleStart ignored due to rxSampleState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop sampling received CTE action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActRxSampleStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rxSampleStop.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently sampling */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_SAMPLING)
|
||||
{
|
||||
HciLeSetConnCteRxParamsCmd(pCcb->handle, FALSE, 0, 0, NULL);
|
||||
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRxSampleStop ignored due to rxSampleState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure connection CTE transmit action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActTxCfg(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->txCfg.connId)) != NULL)
|
||||
{
|
||||
HciLeSetConnCteTxParamsCmd(pCcb->handle, pMsg->txCfg.cteTypeBits, pMsg->txCfg.switchPatternLen,
|
||||
pMsg->txCfg.pAntennaIDs);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start initiating CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActReqStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->reqStart.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeConnCteReqEnableCmd(pCcb->handle, TRUE, pMsg->reqStart.cteReqInt,
|
||||
pMsg->reqStart.reqCteLen, pMsg->reqStart.reqCteType);
|
||||
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteReqStart ignored due to reqState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop initiating CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActReqStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->reqStop.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently initiating */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_INITIATING)
|
||||
{
|
||||
HciLeConnCteReqEnableCmd(pCcb->handle, FALSE, 0, 0, 0);
|
||||
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteReqStop ignored due to reqState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start responding to CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActRspStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rspEnable.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeConnCteRspEnableCmd(pCcb->handle, TRUE);
|
||||
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRspStart ignored due to rspState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop responding to CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActRspStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rspEnable.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently responding */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_RESPONDING)
|
||||
{
|
||||
HciLeConnCteRspEnableCmd(pCcb->handle, FALSE);
|
||||
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRspStop ignored due to rspState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection state change action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActState(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
/* if connection closed */
|
||||
if (pMsg->hdr.status == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* reset all states */
|
||||
dmConnCteCbInit(&dmConnCteCb[pMsg->hdr.param - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable sampling received CTE fields on the specified connection, and configure the
|
||||
* antenna switching pattern, and switching and sampling slot durations to be used.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param slotDurations Switching and sampling slot durations to be used while receiving CTE.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRxSampleStart(dmConnId_t connId, uint8_t slotDurations, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
dmConnCteApiRxSampleStart_t *pMsg;
|
||||
|
||||
WSF_ASSERT((switchPatternLen >= HCI_MIN_NUM_ANTENNA_IDS) && \
|
||||
(switchPatternLen <= HCI_MAX_NUM_ANTENNA_IDS));
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRxSampleStart_t) + switchPatternLen)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RX_SAMPLE_START;
|
||||
pMsg->connId = connId;
|
||||
pMsg->slotDurations = slotDurations;
|
||||
pMsg->switchPatternLen = switchPatternLen;
|
||||
|
||||
/* Copy antenna IDs to space after end of config struct */
|
||||
pMsg->pAntennaIDs = (uint8_t *)(pMsg + 1);
|
||||
memcpy(pMsg->pAntennaIDs, pAntennaIDs, switchPatternLen);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Disable sampling received CTE fields on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRxSampleStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRxSampleStop_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRxSampleStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure the antenna switching pattern, and permitted CTE types used for transmitting
|
||||
* CTEs requested by the peer device on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param cteTypeBits Permitted CTE type bits used for transmitting CTEs requested by peer.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteTxConfig(dmConnId_t connId, uint8_t cteTypeBits, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
dmConnCteApiTxConfig_t *pMsg;
|
||||
|
||||
WSF_ASSERT((switchPatternLen >= HCI_MIN_NUM_ANTENNA_IDS) && \
|
||||
(switchPatternLen <= HCI_MAX_NUM_ANTENNA_IDS));
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiTxConfig_t) + switchPatternLen)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_TX_CFG;
|
||||
pMsg->connId = connId;
|
||||
pMsg->cteTypeBits = cteTypeBits;
|
||||
pMsg->switchPatternLen = switchPatternLen;
|
||||
|
||||
/* Copy antenna IDs to space after end of config struct */
|
||||
pMsg->pAntennaIDs = (uint8_t *)(pMsg + 1);
|
||||
memcpy(pMsg->pAntennaIDs, pAntennaIDs, switchPatternLen);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate the CTE Request procedure on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param cteReqInt CTE request interval.
|
||||
* \param reqCteLen Minimum length of CTE being requested in 8 us units.
|
||||
* \param reqCteType Requested CTE type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteReqStart(dmConnId_t connId, uint16_t cteReqInt, uint8_t reqCteLen,
|
||||
uint8_t reqCteType)
|
||||
{
|
||||
dmConnCteApiReqStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiReqStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_REQ_START;
|
||||
pMsg->connId = connId;
|
||||
pMsg->cteReqInt = cteReqInt;
|
||||
pMsg->reqCteLen = reqCteLen;
|
||||
pMsg->reqCteType = reqCteType;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop initiating the CTE Request procedure on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteReqStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiReqStop_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiReqStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_REQ_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start responding to LL_CTE_REQ PDUs with LL_CTE_RSP PDUs on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRspStart(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRspEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRspEnable_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RSP_START;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop responding to LL_CTE_REQ PDUs with LL_CTE_RSP PDUs on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRspStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRspEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRspEnable_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RSP_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the switching rates, the sampling rates, the number of antennae, and the maximum
|
||||
* length of a transmitted Constant Tone Extension supported by the Controller.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note The antenna info will be returned with DM indication \ref DM_READ_ANTENNA_INFO_IND.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmReadAntennaInfo(void)
|
||||
{
|
||||
HciLeReadAntennaInfoCmd();
|
||||
}
|
||||
Vendored
+145
@@ -0,0 +1,145 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for master.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_os.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel an opening connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActCancelOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* cancel create connection */
|
||||
HciLeCreateConnCancelCmd();
|
||||
|
||||
/* pass connection initiation stopped to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_STOP, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update a connection as a master.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActUpdateMaster(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* send HCI command */
|
||||
HciLeConnUpdateCmd(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an L2CAP connection update indication.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActL2cUpdateInd(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* always send back response */
|
||||
L2cDmConnUpdateRsp(pMsg->l2cUpdateInd.identifier, pCcb->handle, L2C_CONN_PARAM_ACCEPTED);
|
||||
|
||||
/* send HCI command */
|
||||
HciLeConnUpdateCmd(pCcb->handle, pMsg->l2cUpdateInd.pConnSpec);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function when it receives a connection update
|
||||
* request from a peer device.
|
||||
*
|
||||
* \param identifier Identifier value.
|
||||
* \param handle Connection handle.
|
||||
* \param pConnSpec Connection spec parameters.
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cConnUpdateInd(uint8_t identifier, uint16_t handle, hciConnSpec_t *pConnSpec)
|
||||
{
|
||||
dmConnL2cUpdateInd_t updateInd;
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if ((pCcb = dmConnCcbByHandle(handle)) != NULL)
|
||||
{
|
||||
updateInd.hdr.event = DM_CONN_MSG_L2C_UPDATE_IND;
|
||||
updateInd.pConnSpec = pConnSpec;
|
||||
updateInd.identifier = identifier;
|
||||
|
||||
dmConnSmExecute(pCcb, (dmConnMsg_t *) &updateInd);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param clientId The client identifier.
|
||||
* \param initPhys Initiator PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmConnId_t DmConnOpen(uint8_t clientId, uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
return dmConnOpenAccept(clientId, initPhys, 0, 0, 0, 0, addrType, pAddr, DM_ROLE_MASTER);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used for connections created with DmConnOpen().
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.connAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management module for extended master.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetMaster[] =
|
||||
{
|
||||
dmExtConnSmActOpen,
|
||||
dmConnSmActCancelOpen,
|
||||
dmConnSmActUpdateMaster,
|
||||
dmConnSmActL2cUpdateInd
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param initPhys Initiating PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmExtConnOpen(uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t idx;
|
||||
uint8_t phyIdx;
|
||||
hciExtInitParam_t initParam;
|
||||
hciConnSpec_t connSpec[DM_NUM_PHYS];
|
||||
hciExtInitScanParam_t scanParam[DM_NUM_PHYS];
|
||||
|
||||
/* set initiating parameters */
|
||||
initParam.filterPolicy = dmCb.initFiltPolicy;
|
||||
initParam.ownAddrType = DmLlAddrType(dmCb.connAddrType);
|
||||
initParam.peerAddrType = addrType;
|
||||
initParam.pPeerAddr = pAddr;
|
||||
initParam.initPhys = initPhys;
|
||||
|
||||
/* see advertising packets to be received on which PHY */
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (initPhys & (1 << i))
|
||||
{
|
||||
phyIdx = DmInitPhyToIdx(1 << i);
|
||||
|
||||
/* set extended create conection parameters for this PHY */
|
||||
scanParam[idx].scanInterval = dmConnCb.scanInterval[phyIdx];
|
||||
scanParam[idx].scanWindow = dmConnCb.scanWindow[phyIdx];
|
||||
connSpec[idx] = dmConnCb.connSpec[phyIdx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create connection */
|
||||
HciLeExtCreateConnCmd(&initParam, scanParam, connSpec);
|
||||
|
||||
/* pass connection initiation started to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_START, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtConnOpen(pMsg->apiOpen.initPhys, pMsg->apiOpen.addrType, pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as extended master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtConnMasterInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_MASTER] = (dmConnAct_t *) dmConnActSetMaster;
|
||||
}
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management module for legacy master.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetMaster[] =
|
||||
{
|
||||
dmConnSmActOpen,
|
||||
dmConnSmActCancelOpen,
|
||||
dmConnSmActUpdateMaster,
|
||||
dmConnSmActL2cUpdateInd
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param initPhys Initiating PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnOpen(uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
uint8_t phyIdx = DmScanPhyToIdx(HCI_SCAN_PHY_LE_1M_BIT);
|
||||
|
||||
/* Create connection */
|
||||
HciLeCreateConnCmd(dmConnCb.scanInterval[phyIdx], dmConnCb.scanWindow[phyIdx], dmCb.initFiltPolicy,
|
||||
addrType, pAddr, DmLlAddrType(dmCb.connAddrType), &(dmConnCb.connSpec[phyIdx]));
|
||||
|
||||
/* pass connection initiation started to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_START, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmConnOpen(pMsg->apiOpen.initPhys, pMsg->apiOpen.addrType, pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as legacy master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnMasterInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_MASTER] = (dmConnAct_t *) dmConnActSetMaster;
|
||||
}
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager slave connection management for slave.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Call application callback with the connection update complete event.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param status Status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnUpdateCback(dmConnCcb_t *pCcb, uint8_t status)
|
||||
{
|
||||
hciLeConnUpdateCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_CONN_UPDATE_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = status;
|
||||
evt.handle = pCcb->handle;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *) &evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update a connection as a slave.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActUpdateSlave(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
if ((pCcb->features & HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC) &&
|
||||
(HciGetLeSupFeat() & HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC))
|
||||
{
|
||||
HciLeConnUpdateCmd(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
/* else if L2CAP connection update not already in progress */
|
||||
else if (!pCcb->updating)
|
||||
{
|
||||
pCcb->updating = TRUE;
|
||||
|
||||
/* send request via L2CAP */
|
||||
L2cDmConnUpdateReq(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
/* else L2CAP connection update pending */
|
||||
else
|
||||
{
|
||||
/* call callback */
|
||||
dmConnUpdateCback(pCcb, (uint8_t) HCI_ERR_CMD_DISALLOWED);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an L2CAP connection update confirm.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActL2cUpdateCnf(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* if connection update in progress */
|
||||
if (pCcb->updating)
|
||||
{
|
||||
pCcb->updating = FALSE;
|
||||
|
||||
/* if reason indicates failure */
|
||||
if (pMsg->l2cUpdateCnf.result != L2C_CONN_PARAM_ACCEPTED)
|
||||
{
|
||||
/* call callback */
|
||||
dmConnUpdateCback(pCcb, (uint8_t) pMsg->l2cUpdateCnf.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function to send the result of an L2CAP
|
||||
* connection update response to DM.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
* \param result Connection update result code.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cConnUpdateCnf(uint16_t handle, uint16_t result)
|
||||
{
|
||||
dmConnL2cUpdateCnf_t updateCnf;
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if ((pCcb = dmConnCcbByHandle(handle)) != NULL)
|
||||
{
|
||||
updateCnf.hdr.event = DM_CONN_MSG_L2C_UPDATE_CNF;
|
||||
updateCnf.result = result;
|
||||
|
||||
dmConnSmExecute(pCcb, (dmConnMsg_t *) &updateCnf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function to send the result of an L2CAP
|
||||
* Command Reject indication up to the application.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
* \param result Connection update result code.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cCmdRejInd(uint16_t handle, uint16_t result)
|
||||
{
|
||||
dmL2cCmdRejEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_L2C_CMD_REJ_IND;
|
||||
evt.hdr.status = HCI_SUCCESS;
|
||||
evt.reason = result;
|
||||
evt.handle = handle;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection from the given peer device by initiating directed advertising.
|
||||
*
|
||||
* \param clientId The client identifier.
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advType Advertising type.
|
||||
* \param duration Advertising duration (in ms).
|
||||
* \param maxEaEvents Maximum number of extended advertising events.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmConnId_t DmConnAccept(uint8_t clientId, uint8_t advHandle, uint8_t advType, uint16_t duration,
|
||||
uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
return dmConnOpenAccept(clientId, 0, advHandle, advType, duration, maxEaEvents, addrType, pAddr,
|
||||
DM_ROLE_SLAVE);
|
||||
}
|
||||
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for extended slave.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetSlave[] =
|
||||
{
|
||||
dmExtConnSmActAccept,
|
||||
dmExtConnSmActCancelAccept,
|
||||
dmConnSmActUpdateSlave,
|
||||
dmExtConnSmActConnAccepted,
|
||||
dmExtConnSmActAcceptFailed,
|
||||
dmConnSmActL2cUpdateCnf
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvStartDirected(pCcb->connId, pMsg->apiOpen.advHandle, pMsg->apiOpen.advType,
|
||||
pMsg->apiOpen.duration, pMsg->apiOpen.maxEaEvents, pMsg->apiOpen.addrType,
|
||||
pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel a connection accept.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvStopDirected(pCcb->connId);
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accepted.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvConnected(pCcb->connId);
|
||||
|
||||
dmConnSmActConnOpened(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accept failed.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvConnectFailed(pCcb->connId);
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as extended slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtConnSlaveInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_SLAVE] = (dmConnAct_t *) dmConnActSetSlave;
|
||||
}
|
||||
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for legacy slave.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetSlave[] =
|
||||
{
|
||||
dmConnSmActAccept,
|
||||
dmConnSmActCancelAccept,
|
||||
dmConnSmActUpdateSlave,
|
||||
dmConnSmActConnAccepted,
|
||||
dmConnSmActAcceptFailed,
|
||||
dmConnSmActL2cUpdateCnf
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvStartDirected(pMsg->apiOpen.advType, pMsg->apiOpen.duration, pMsg->apiOpen.addrType,
|
||||
pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel a connection accept.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvStopDirected();
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accepted.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvConnected();
|
||||
|
||||
dmConnSmActConnOpened(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accept failed.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvConnectFailed();
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as legacy slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnSlaveInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_SLAVE] = (dmConnAct_t *) dmConnActSetSlave;
|
||||
}
|
||||
Vendored
+187
@@ -0,0 +1,187 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management state machine.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Column position of next state */
|
||||
#define DM_CONN_NEXT_STATE 0
|
||||
|
||||
/*! Column position of action */
|
||||
#define DM_CONN_ACTION 1
|
||||
|
||||
/*! Number of columns in the state machine state tables */
|
||||
#define DM_CONN_NUM_COLS 2
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM Conn state machine state tables */
|
||||
static const uint8_t dmConnStateTbl[DM_CONN_SM_NUM_STATES][DM_CONN_NUM_MSGS][DM_CONN_NUM_COLS] =
|
||||
{
|
||||
/* Idle state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_OPEN},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_ACCEPT},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_ACCEPTED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Connecting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CANCEL_OPEN},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_FAILED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_OPENED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_FAILED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Accepting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CANCEL_ACCEPT},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_ACCEPT_FAILED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_ACCEPTED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_ACCEPT_FAILED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Connected state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CLOSE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_UPDATE_MASTER},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_UPDATE_SLAVE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_L2C_UPDATE_IND},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_L2C_UPDATE_CNF},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_HCI_UPDATED},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_HCI_UPDATED}
|
||||
},
|
||||
/* Disconnecting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CLOSE},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! State machine action set array */
|
||||
dmConnAct_t *dmConnActSet[DM_CONN_NUM_ACT_SETS];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the DM connection state machine.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmExecute(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmConnAct_t *actSet;
|
||||
uint8_t action;
|
||||
uint8_t event;
|
||||
|
||||
DM_TRACE_INFO2("dmConnSmExecute event=%d state=%d", pMsg->hdr.event, pCcb->state);
|
||||
|
||||
/* get the event */
|
||||
event = DM_MSG_MASK(pMsg->hdr.event);
|
||||
|
||||
/* get action */
|
||||
action = dmConnStateTbl[pCcb->state][event][DM_CONN_ACTION];
|
||||
|
||||
/* set next state */
|
||||
pCcb->state = dmConnStateTbl[pCcb->state][event][DM_CONN_NEXT_STATE];
|
||||
|
||||
/* look up action set */
|
||||
actSet = dmConnActSet[DM_CONN_ACT_SET_ID(action)];
|
||||
|
||||
/* if action set present */
|
||||
if (actSet != NULL)
|
||||
{
|
||||
/* execute action function in action set */
|
||||
(*actSet[DM_CONN_ACT_ID(action)])(pCcb, pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no action */
|
||||
dmConnSmActNone(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM local device management module.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmDevAct_t dmDevAct[] =
|
||||
{
|
||||
dmDevActReset
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
const dmFcnIf_t dmDevFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmDevHciHandler,
|
||||
dmDevMsgHandler
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmDevCb_t dmDevCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevActReset(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if DM not resetting */
|
||||
if (!dmCb.resetting)
|
||||
{
|
||||
/* set resetting state */
|
||||
dmCb.resetting = TRUE;
|
||||
|
||||
/* for each DM component */
|
||||
for (i = 0; i < DM_NUM_IDS; i++)
|
||||
{
|
||||
/* call component's reset function */
|
||||
(*(dmFcnIfTbl[i]->reset))();
|
||||
}
|
||||
|
||||
/* start HCI reset sequence */
|
||||
HciResetSequence();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a reset complete event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtReset(hciEvt_t *pEvent)
|
||||
{
|
||||
/* reset resetting state */
|
||||
dmCb.resetting = FALSE;
|
||||
|
||||
pEvent->hdr.event = DM_RESET_CMPL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a vendor specific event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtVendorSpec(hciEvt_t *pEvent)
|
||||
{
|
||||
pEvent->hdr.event = DM_VENDOR_SPEC_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an hardware error event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtHwError(hciEvt_t *pEvent)
|
||||
{
|
||||
pEvent->hdr.event = DM_HW_ERROR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_RESET_SEQ_CMPL_CBACK_EVT:
|
||||
dmDevHciEvtReset(pEvent);
|
||||
break;
|
||||
|
||||
case HCI_VENDOR_SPEC_CBACK_EVT:
|
||||
dmDevHciEvtVendorSpec(pEvent);
|
||||
break;
|
||||
|
||||
case HCI_HW_ERROR_CBACK_EVT:
|
||||
dmDevHciEvtHwError(pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore event */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmDevAct[DM_MSG_MASK(pMsg->event)])(pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass an event to the device privacy module.
|
||||
*
|
||||
* \param event Device privacy event.
|
||||
* \param param DM or Privacy event.
|
||||
* \param advHandle Advertising handle.
|
||||
* \param connectable TRUE if connectable extended advertising. FALSE, otherwise.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassEvtToDevPriv(uint8_t event, uint8_t param, uint8_t advHandle, bool_t connectable)
|
||||
{
|
||||
dmDevPrivMsg_t evt;
|
||||
|
||||
DM_TRACE_INFO3("dmDevPassEvtToDevPriv: event: %d, param: %d, advHandle: %d", event, param, advHandle);
|
||||
|
||||
/* build event */
|
||||
evt.hdr.event = event;
|
||||
evt.hdr.param = param;
|
||||
evt.privCtrl.advHandle = advHandle;
|
||||
evt.privCtrl.connectable = connectable;
|
||||
|
||||
/* pass event to device privacy */
|
||||
(*(dmFcnIfTbl[DM_ID_DEV_PRIV]->msgHandler))((wsfMsgHdr_t *) &evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass a connection state change event to the Connection CTE module.
|
||||
*
|
||||
* \param state Connection state.
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassEvtToConnCte(uint8_t state, dmConnId_t connId)
|
||||
{
|
||||
wsfMsgHdr_t evt;
|
||||
|
||||
/* build event */
|
||||
evt.event = DM_CONN_CTE_MSG_STATE;
|
||||
evt.status = state;
|
||||
evt.param = connId;
|
||||
|
||||
/* pass event to Connection CTE */
|
||||
(*(dmFcnIfTbl[DM_ID_CONN_CTE]->msgHandler))(&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the device.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevReset(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_DEV_MSG_API_RESET;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random address to be used by the local device.
|
||||
*
|
||||
* \param pAddr Random address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevSetRandAddr(uint8_t *pAddr)
|
||||
{
|
||||
BdaCpy(dmCb.localAddr, pAddr);
|
||||
HciLeSetRandAddrCmd(pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add a peer device to the white list. Note that this function cannot be called
|
||||
* while advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListAdd(uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
HciLeAddDevWhiteListCmd(addrType, pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove a peer device from the white list. Note that this function cannot be called
|
||||
* while advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListRemove(uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
HciLeRemoveDevWhiteListCmd(addrType, pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear the white list. Note that this function cannot be called while
|
||||
* advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListClear(void)
|
||||
{
|
||||
HciLeClearWhiteListCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising, Scanning or Initiator filter policy.
|
||||
*
|
||||
* \param advHandle Advertising handle (only applicable to advertising).
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t dmDevSetFilterPolicy(uint8_t advHandle, uint8_t mode, uint8_t policy)
|
||||
{
|
||||
bool_t policySet = FALSE;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DM_FILT_POLICY_MODE_ADV:
|
||||
/* if Advertising filter policy is valid */
|
||||
if (policy <= HCI_ADV_FILT_ALL)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* update the filter policy */
|
||||
dmCb.advFiltPolicy[advHandle] = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_SCAN:
|
||||
/* if Scanning filter policy is valid */
|
||||
if (policy <= HCI_FILT_WHITE_LIST_RES_INIT)
|
||||
{
|
||||
/* update the filter policy */
|
||||
dmCb.scanFiltPolicy = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_INIT:
|
||||
/* if Initiator filter policy is valid */
|
||||
if (policy <= HCI_FILT_WHITE_LIST)
|
||||
{
|
||||
/* update the filter policy */
|
||||
dmCb.initFiltPolicy = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_SYNC:
|
||||
/* if Synchronization filter policy is valid */
|
||||
if (policy <= HCI_FILT_PER_ADV_LIST)
|
||||
{
|
||||
/* clear the filter policy bit */
|
||||
dmCb.syncOptions &= ~HCI_OPTIONS_FILT_POLICY_BIT;
|
||||
|
||||
/* set the filter policy bit */
|
||||
dmCb.syncOptions |= policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid filter policy mode */
|
||||
break;
|
||||
}
|
||||
|
||||
return policySet;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising, Scanning or Initiator filter policy.
|
||||
*
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmDevSetFilterPolicy(uint8_t mode, uint8_t policy)
|
||||
{
|
||||
return dmDevSetFilterPolicy(DM_ADV_HANDLE_DEFAULT, mode, policy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising filter policy for the given advertising, Scanning or Initiator
|
||||
* filter policy.
|
||||
*
|
||||
* \param advHandle Advertising handle (only applicable to advertising).
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmDevSetExtFilterPolicy(uint8_t advHandle, uint8_t mode, uint8_t policy)
|
||||
{
|
||||
return dmDevSetFilterPolicy(advHandle, mode, policy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Vendor-specific controller initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevVsInit(uint8_t param)
|
||||
{
|
||||
HciVsInit(param);
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM local device management module.
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_DEV_H
|
||||
#define DM_DEV_H
|
||||
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM device event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_MSG_API_RESET = DM_MSG_START(DM_ID_DEV)
|
||||
};
|
||||
|
||||
/* DM device privacy event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_PRIV_MSG_API_START = DM_MSG_START(DM_ID_DEV_PRIV),
|
||||
DM_DEV_PRIV_MSG_API_STOP,
|
||||
DM_DEV_PRIV_MSG_TIMEOUT,
|
||||
DM_DEV_PRIV_MSG_AES_CMPL,
|
||||
DM_DEV_PRIV_MSG_RPA_START,
|
||||
DM_DEV_PRIV_MSG_RPA_STOP,
|
||||
DM_DEV_PRIV_MSG_CTRL,
|
||||
};
|
||||
|
||||
/* DM device privacy control messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_PRIV_MSG_CONN_INIT_START, /* connection initiation started */
|
||||
DM_DEV_PRIV_MSG_CONN_INIT_STOP, /* connection initiation stopped */
|
||||
DM_DEV_PRIV_MSG_ADV_SET_ADD, /* advertising set created */
|
||||
DM_DEV_PRIV_MSG_ADV_SET_REMOVE, /* advertising set removed */
|
||||
DM_DEV_PRIV_MSG_ADV_SETS_CLEAR /* advertising sets cleared */
|
||||
};
|
||||
|
||||
/*! DM connection CTE event handler messages */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_CONN_CTE_MSG_API_RX_SAMPLE_START = DM_MSG_START(DM_ID_CONN_CTE), /*!< Start sampling received CTE, and configure CTE Rx parameters to be used */
|
||||
DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP, /*!< Stop sampling received CTE */
|
||||
DM_CONN_CTE_MSG_API_TX_CFG, /*!< Configure CTE Tx parameters */
|
||||
DM_CONN_CTE_MSG_API_REQ_START, /*!< Start initiating CTE request */
|
||||
DM_CONN_CTE_MSG_API_REQ_STOP, /*!< Stop initiating CTE request */
|
||||
DM_CONN_CTE_MSG_API_RSP_START, /*!< Start responding to CTE request */
|
||||
DM_CONN_CTE_MSG_API_RSP_STOP, /*!< Stop responding to CTE request */
|
||||
DM_CONN_CTE_MSG_STATE /*!< DM connection state change event */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_DEV_PRIV_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t changeInterval;
|
||||
} dmDevPrivApiStart_t;
|
||||
|
||||
/* Data structure for DM_DEV_PRIV_MSG_CTRL */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
bool_t connectable;
|
||||
} dmDevPrivCtrl_t;
|
||||
|
||||
/* Union of all dev priv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmDevPrivApiStart_t apiPrivStart;
|
||||
dmDevPrivCtrl_t privCtrl;
|
||||
secAes_t aes;
|
||||
} dmDevPrivMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmDevAct_t)(wsfMsgHdr_t *pMsg);
|
||||
typedef void (*dmDevPrivAct_t)(dmDevPrivMsg_t *pMsg);
|
||||
|
||||
/* DM device set advertising set random address callback type */
|
||||
typedef void (*dmDevAdvSetRandAddrCback_t)(uint8_t advHandle, const uint8_t *pAddr);
|
||||
|
||||
/* Main control block of the DM Dev subsystem */
|
||||
typedef struct
|
||||
{
|
||||
/* Set advertising set random address callback */
|
||||
dmDevAdvSetRandAddrCback_t advSetRandAddrCback;
|
||||
} dmDevCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
extern const dmFcnIf_t dmDevFcnIf;
|
||||
|
||||
/* Control block */
|
||||
extern dmDevCb_t dmDevCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* dev component inteface */
|
||||
void dmDevActReset(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/* dev action functions */
|
||||
void dmDevMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmDevHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* dev priv component inteface */
|
||||
void dmDevPrivHciHandler(hciEvt_t *pEvent);
|
||||
void dmDevPrivMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmDevPrivReset(void);
|
||||
|
||||
/* dev priv action functions */
|
||||
void dmDevPrivActStart(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActStop(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActTimeout(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActAesCmpl(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActRpaStart(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActRpaStop(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActCtrl(dmDevPrivMsg_t *pMsg);
|
||||
|
||||
/* utility function */
|
||||
void dmDevPassEvtToDevPriv(uint8_t event, uint8_t param, uint8_t advHandle, bool_t connectable);
|
||||
void dmDevPassEvtToConnCte(uint8_t state, dmConnId_t connId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_DEV_H */
|
||||
Vendored
+653
@@ -0,0 +1,653 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager device privacy module.
|
||||
*
|
||||
* Copyright (c) 2009-2019 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "hci_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Structure for extended advertising */
|
||||
typedef struct
|
||||
{
|
||||
bool_t configured;
|
||||
bool_t connectable;
|
||||
bool_t advertising;
|
||||
} dmDevPrivExtAdv_t;
|
||||
|
||||
/* Control block for device privacy module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t addrTimer;
|
||||
bool_t addrTimerStarted;
|
||||
uint8_t prand[DM_PRIV_PRAND_LEN];
|
||||
uint16_t changeInterval;
|
||||
bool_t useResolvable;
|
||||
bool_t addrInitialized;
|
||||
bdAddr_t pendingAddr;
|
||||
bool_t advertising;
|
||||
bool_t scanning;
|
||||
bool_t connecting;
|
||||
bool_t connected;
|
||||
dmDevPrivExtAdv_t extAdv[DM_NUM_ADV_SETS];
|
||||
} dmDevPrivCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmDevPrivAct_t dmDevPrivAct[] =
|
||||
{
|
||||
dmDevPrivActStart,
|
||||
dmDevPrivActStop,
|
||||
dmDevPrivActTimeout,
|
||||
dmDevPrivActAesCmpl,
|
||||
dmDevPrivActRpaStart,
|
||||
dmDevPrivActRpaStop,
|
||||
dmDevPrivActCtrl
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmDevPrivFcnIf =
|
||||
{
|
||||
dmDevPrivReset,
|
||||
dmDevPrivHciHandler,
|
||||
dmDevPrivMsgHandler
|
||||
};
|
||||
|
||||
/* control block */
|
||||
static dmDevPrivCb_t dmDevPrivCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether the legacy advertising or an advertising set using (non)connectable advertising
|
||||
* is enabled.
|
||||
*
|
||||
* \param nonconnectable Non-connectable advertising.
|
||||
*
|
||||
* \return TRUE if advertising is enabled. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t dmDevPrivAdvertising(bool_t nonconnectable)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if legacy advertising enabled */
|
||||
if (dmDevPrivCb.advertising)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* if (non)connectable extended advertising is enabled */
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
if (dmDevPrivCb.extAdv[i].configured &&
|
||||
dmDevPrivCb.extAdv[i].advertising &&
|
||||
(dmDevPrivCb.extAdv[i].connectable || nonconnectable))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start the address generation timer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivTimerStart(void)
|
||||
{
|
||||
/* if LL Privacy not enabled and device advertising, scanning or connected */
|
||||
if (!dmCb.llPrivEnabled && (dmDevPrivAdvertising(TRUE) || dmDevPrivCb.scanning || dmDevPrivCb.connected))
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivCb.addrTimerStarted = TRUE;
|
||||
dmDevPrivCb.addrTimer.msg.event = DM_DEV_PRIV_MSG_TIMEOUT;
|
||||
WsfTimerStartSec(&dmDevPrivCb.addrTimer, dmDevPrivCb.changeInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start resolvable address calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivAddrCalc(void)
|
||||
{
|
||||
uint8_t buf[DM_PRIV_PLAINTEXT_LEN];
|
||||
|
||||
/* get random number */
|
||||
SecRand(buf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set address type in random number */
|
||||
buf[2] = (buf[2] & 0x3F) | DM_RAND_ADDR_RESOLV;
|
||||
|
||||
/* pad buffer */
|
||||
memset(buf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* run calculation */
|
||||
SecAes(DmSecGetLocalIrk(), buf, dmCb.handlerId, 0, DM_DEV_PRIV_MSG_AES_CMPL);
|
||||
|
||||
/* store random number */
|
||||
memcpy(dmDevPrivCb.prand, buf, DM_PRIV_PRAND_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the RPA to be used by the local device.
|
||||
*
|
||||
* \param pAddr New RPA.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivSetRpa(uint8_t *pAddr)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* set new RPA as local address */
|
||||
BdaCpy(dmCb.localAddr, pAddr);
|
||||
|
||||
/* set RPA in device */
|
||||
HciLeSetRandAddrCmd(dmCb.localAddr);
|
||||
|
||||
if (dmDevCb.advSetRandAddrCback)
|
||||
{
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
if (dmDevPrivCb.extAdv[i].configured)
|
||||
{
|
||||
/* set RPA for advertising set */
|
||||
(*dmDevCb.advSetRandAddrCback)(i, dmCb.localAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the pending RPA to be used by the local device.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivSetPendingRpa(void)
|
||||
{
|
||||
/* if not advertising, scanning or initiating connection, and new RPA has been generated */
|
||||
if (!(dmDevPrivAdvertising(FALSE) || dmDevPrivCb.scanning || dmDevPrivCb.connecting) &&
|
||||
!BdaIsZeros(dmDevPrivCb.pendingAddr))
|
||||
{
|
||||
/* use pending RPA as local address */
|
||||
dmDevPrivSetRpa(dmDevPrivCb.pendingAddr);
|
||||
|
||||
/* clear out pending RPA */
|
||||
memset(dmDevPrivCb.pendingAddr, 0, BDA_ADDR_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start device privacy action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActStart(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* initialize and store parameters */
|
||||
dmDevPrivCb.useResolvable = TRUE;
|
||||
dmDevPrivCb.changeInterval = pMsg->apiPrivStart.changeInterval;
|
||||
dmDevPrivCb.addrTimer.handlerId = dmCb.handlerId;
|
||||
|
||||
/* set the local address type to random */
|
||||
DmAdvSetAddrType(DM_ADDR_RANDOM);
|
||||
DmScanSetAddrType(DM_ADDR_RANDOM);
|
||||
DmConnSetAddrType(DM_ADDR_RANDOM);
|
||||
|
||||
/* start the address generation timer if applicable */
|
||||
if (dmDevPrivCb.changeInterval > 0)
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
|
||||
/* if LL Privacy is supported */
|
||||
if (HciLlPrivacySupported())
|
||||
{
|
||||
/* Set LL resolvable private address timeout */
|
||||
DmPrivSetResolvablePrivateAddrTimeout(dmDevPrivCb.changeInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/* if private address has never been generated */
|
||||
if (dmDevPrivCb.addrInitialized == FALSE)
|
||||
{
|
||||
/* start address calculation */
|
||||
dmDevPrivAddrCalc();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop device privacy action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActStop(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* stop address generation timer */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
|
||||
dmDevPrivCb.useResolvable = FALSE;
|
||||
memset(dmDevPrivCb.pendingAddr, 0, BDA_ADDR_LEN);
|
||||
|
||||
/* set the local address type to public */
|
||||
DmAdvSetAddrType(DM_ADDR_PUBLIC);
|
||||
DmScanSetAddrType(DM_ADDR_PUBLIC);
|
||||
DmConnSetAddrType(DM_ADDR_PUBLIC);
|
||||
|
||||
/* if LL Privacy is supported */
|
||||
if (HciLlPrivacySupported())
|
||||
{
|
||||
/* remove all devices from resolving list and disable LL Privacy */
|
||||
DmPrivClearResList();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a private address generation timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActTimeout(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* if Host Privacy still enabled */
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* address generation timer has timed out */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
|
||||
/* restart address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
|
||||
/* start address calculation */
|
||||
dmDevPrivAddrCalc();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle AES calculation complete.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActAesCmpl(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
bdAddr_t localAddr;
|
||||
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* build and store address; hash is in ls bytes, random part in ms bytes */
|
||||
memcpy(localAddr, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN);
|
||||
memcpy(&localAddr[DM_PRIV_HASH_LEN], dmDevPrivCb.prand, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set generated address as random resolvable */
|
||||
DM_RAND_ADDR_SET(localAddr, DM_RAND_ADDR_RESOLV);
|
||||
|
||||
/* if not advertising, scanning or initiating connection */
|
||||
if (!(dmDevPrivAdvertising(FALSE) || dmDevPrivCb.scanning || dmDevPrivCb.connecting))
|
||||
{
|
||||
/* use new RPA as local address */
|
||||
dmDevPrivSetRpa(localAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* save new RPA for later */
|
||||
BdaCpy(dmDevPrivCb.pendingAddr, localAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy RPA start event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActRpaStart(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_ADV_START_IND:
|
||||
/* advertising started */
|
||||
dmDevPrivCb.advertising = TRUE;
|
||||
break;
|
||||
|
||||
case DM_ADV_SET_START_IND:
|
||||
/* extended advertising started */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].advertising = TRUE;
|
||||
break;
|
||||
|
||||
case DM_SCAN_START_IND:
|
||||
case DM_EXT_SCAN_START_IND:
|
||||
/* scanning started */
|
||||
dmDevPrivCb.scanning = TRUE;
|
||||
break;
|
||||
|
||||
case DM_CONN_OPEN_IND:
|
||||
/* connection opened */
|
||||
dmDevPrivCb.connected = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* LL Privacy disabled */
|
||||
break;
|
||||
}
|
||||
|
||||
/* if Host Privacy enabled and address generation timer not already running */
|
||||
if (dmDevPrivCb.useResolvable && !dmDevPrivCb.addrTimerStarted)
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy RPA stop event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActRpaStop(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_ADV_STOP_IND:
|
||||
/* advertising stopped */
|
||||
dmDevPrivCb.advertising = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_ADV_SET_STOP_IND:
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* extended advertising stopped */
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].advertising = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_SCAN_STOP_IND:
|
||||
case DM_EXT_SCAN_STOP_IND:
|
||||
/* scanning stopped */
|
||||
dmDevPrivCb.scanning = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
/* connection closed */
|
||||
dmDevPrivCb.connected = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* LL Privacy enabled see if address generation timer running */
|
||||
if (dmDevPrivCb.addrTimerStarted)
|
||||
{
|
||||
/* stop address generation timer (LL will generate RPAs) */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* let address generation timer timeout (if still running) and update address */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy control event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActCtrl(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_DEV_PRIV_MSG_CONN_INIT_START:
|
||||
/* connection initiation started */
|
||||
dmDevPrivCb.connecting = TRUE;
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_CONN_INIT_STOP:
|
||||
/* connection initiation stopped */
|
||||
dmDevPrivCb.connecting = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SET_ADD:
|
||||
/* advertising set created */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].configured = TRUE;
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].connectable = pMsg->privCtrl.connectable;
|
||||
|
||||
/* if Host Privacy enabled and private address has been generated */
|
||||
if (dmDevPrivCb.useResolvable && dmDevPrivCb.addrInitialized)
|
||||
{
|
||||
WSF_ASSERT(dmDevCb.advSetRandAddrCback != NULL);
|
||||
|
||||
/* set RPA for advertising set */
|
||||
(*dmDevCb.advSetRandAddrCback)(pMsg->privCtrl.advHandle, dmCb.localAddr);
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SET_REMOVE:
|
||||
/* advertising set removed */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* clear advertising set */
|
||||
/* note: advertising handle is checked before reaching this function */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
memset(&dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle], 0, sizeof(dmDevPrivExtAdv_t));
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SETS_CLEAR:
|
||||
/* clear advertising sets */
|
||||
memset(dmDevPrivCb.extAdv, 0, sizeof(dmDevPrivCb.extAdv));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unknown state message */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM device priv HCI callback event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
/* if Host Privacy enabled */
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* handle incoming event */
|
||||
if (pEvent->hdr.event == HCI_LE_SET_RAND_ADDR_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmAdvNewAddrIndEvt_t msg;
|
||||
|
||||
msg.hdr.event = DM_ADV_NEW_ADDR_IND;
|
||||
msg.hdr.status = pEvent->hdr.status;
|
||||
BdaCpy(msg.addr, dmCb.localAddr);
|
||||
msg.firstTime = !dmDevPrivCb.addrInitialized;
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) &msg);
|
||||
|
||||
dmDevPrivCb.addrInitialized = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM device privacy event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmDevPrivAct[DM_MSG_MASK(pMsg->event)])((dmDevPrivMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the device privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivReset(void)
|
||||
{
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* stop address generation timer */
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
}
|
||||
|
||||
/* initialize control block */
|
||||
memset(&dmDevPrivCb, 0, sizeof(dmDevPrivCb));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize device privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_DEV_PRIV] = (dmFcnIf_t *) &dmDevPrivFcnIf;
|
||||
|
||||
/* initialize set advertising set random address callback */
|
||||
dmDevCb.advSetRandAddrCback = NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start using a private resolvable address.
|
||||
*
|
||||
* \param changeInterval Interval between automatic address changes, in seconds.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivStart(uint16_t changeInterval)
|
||||
{
|
||||
dmDevPrivApiStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmDevPrivApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_DEV_PRIV_MSG_API_START;
|
||||
pMsg->changeInterval = changeInterval;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop using a private resolvable address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivStop(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_DEV_PRIV_MSG_API_STOP;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
+580
@@ -0,0 +1,580 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager main module.
|
||||
*
|
||||
* Copyright (c) 2009-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "hci_api.h"
|
||||
#include "l2c_defs.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_dev.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* HCI callback event routing table */
|
||||
static const uint8_t dmHciToIdTbl[] =
|
||||
{
|
||||
DM_ID_DEV, /* HCI_RESET_SEQ_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CONN_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_DISCONNECT_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CONN_UPDATE_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_RSSI_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_READ_CHAN_MAP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_TX_PWR_LVL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_REMOTE_VER_INFO_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_READ_REMOTE_FEAT_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_REPL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_NEG_REPL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_ENC_KEY_REFRESH_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_ENC_CHANGE_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CMD_STATUS_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_HW_ERROR_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_ADD_DEV_TO_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_REM_DEV_FROM_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_CLEAR_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_READ_PEER_RES_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_READ_LOCAL_RES_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_SET_ADDR_RES_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_ENCRYPT_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_RAND_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_REP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_NEG_REP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_READ_DEF_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_WRITE_DEF_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_SET_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_READ_MAX_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_REQ_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_DATA_LEN_CHANGE_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_WRITE_AUTH_PAYLOAD_TO_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_AUTH_PAYLOAD_TO_EXPIRED_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_READ_PHY_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_SET_DEF_PHY_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_PHY_UPDATE_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_EXT_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_SCAN_TIMEOUT_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_ADV_SET_TERM_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_SCAN_REQ_RCVD_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_SYNC_EST_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_SYNC_LOST_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_CH_SEL_ALGO_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_SCAN_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_EXT_SCAN_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_EXT_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV_PER, /* HCI_LE_PER_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV_PRIV, /* HCI_LE_SET_RAND_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_SYNC_TRSF_RCVD_CBACK_EVT */
|
||||
DM_ID_PAST, /* HCI_LE_PER_ADV_SYNC_TRSF_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PAST, /* HCI_LE_PER_ADV_SET_INFO_TRSF_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_IQ_REPORT_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CTE_REQ_FAILED_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_SET_CONN_CTE_RX_PARAMS_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_SET_CONN_CTE_TX_PARAMS_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_REQ_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_RSP_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE /* HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT */
|
||||
};
|
||||
|
||||
/* DM callback event length table */
|
||||
static const uint16_t dmEvtCbackLen[] =
|
||||
{
|
||||
sizeof(wsfMsgHdr_t), /* DM_RESET_CMPL_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ADV_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ADV_STOP_IND */
|
||||
sizeof(dmAdvNewAddrIndEvt_t), /* DM_ADV_NEW_ADDR_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SCAN_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SCAN_STOP_IND */
|
||||
sizeof(hciLeAdvReportEvt_t), /* DM_SCAN_REPORT_IND */
|
||||
sizeof(hciLeConnCmplEvt_t), /* DM_CONN_OPEN_IND */
|
||||
sizeof(hciDisconnectCmplEvt_t), /* DM_CONN_CLOSE_IND */
|
||||
sizeof(hciLeConnUpdateCmplEvt_t), /* DM_CONN_UPDATE_IND */
|
||||
sizeof(dmSecPairCmplIndEvt_t), /* DM_SEC_PAIR_CMPL_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SEC_PAIR_FAIL_IND */
|
||||
sizeof(dmSecEncryptIndEvt_t), /* DM_SEC_ENCRYPT_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SEC_ENCRYPT_FAIL_IND */
|
||||
sizeof(dmSecAuthReqIndEvt_t), /* DM_SEC_AUTH_REQ_IND */
|
||||
sizeof(dmSecKeyIndEvt_t), /* DM_SEC_KEY_IND */
|
||||
sizeof(hciLeLtkReqEvt_t), /* DM_SEC_LTK_REQ_IND */
|
||||
sizeof(dmSecPairIndEvt_t), /* DM_SEC_PAIR_IND */
|
||||
sizeof(dmSecSlaveIndEvt_t), /* DM_SEC_SLAVE_REQ_IND */
|
||||
sizeof(dmSecOobCalcIndEvt_t), /* DM_SEC_CALC_OOB_IND */
|
||||
sizeof(secEccMsg_t), /* DM_SEC_ECC_KEY_IND */
|
||||
sizeof(dmSecCnfIndEvt_t), /* DM_SEC_COMPARE_IND */
|
||||
sizeof(dmSecKeypressIndEvt_t), /* DM_SEC_KEYPRESS_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_PRIV_RESOLVED_ADDR_IND */
|
||||
sizeof(dmPrivGenAddrIndEvt_t), /* DM_PRIV_GENERATE_RPA_IND */
|
||||
sizeof(hciReadRssiCmdCmplEvt_t), /* DM_CONN_READ_RSSI_IND */
|
||||
sizeof(hciLeAddDevToResListCmdCmplEvt_t), /* DM_PRIV_ADD_DEV_TO_RES_LIST_IND */
|
||||
sizeof(hciLeRemDevFromResListCmdCmplEvt_t), /* DM_PRIV_REM_DEV_FROM_RES_LIST_IND */
|
||||
sizeof(hciLeClearResListCmdCmplEvt_t), /* DM_PRIV_CLEAR_RES_LIST_IND */
|
||||
sizeof(hciLeReadPeerResAddrCmdCmplEvt_t), /* DM_PRIV_READ_PEER_RES_ADDR_IND */
|
||||
sizeof(hciLeReadLocalResAddrCmdCmplEvt_t), /* DM_PRIV_READ_LOCAL_RES_ADDR_IND */
|
||||
sizeof(hciLeSetAddrResEnableCmdCmplEvt_t), /* DM_PRIV_SET_ADDR_RES_ENABLE_IND */
|
||||
sizeof(hciLeRemConnParamReqEvt_t), /* DM_REM_CONN_PARAM_REQ_IND */
|
||||
sizeof(hciLeDataLenChangeEvt_t), /* DM_CONN_DATA_LEN_CHANGE_IND */
|
||||
sizeof(hciWriteAuthPayloadToCmdCmplEvt_t), /* DM_CONN_WRITE_AUTH_TO_IND */
|
||||
sizeof(hciAuthPayloadToExpiredEvt_t), /* DM_CONN_AUTH_TO_EXPIRED_IND */
|
||||
sizeof(hciLeReadPhyCmdCmplEvt_t), /* DM_PHY_READ_IND */
|
||||
sizeof(hciLeSetDefPhyCmdCmplEvt_t), /* DM_PHY_SET_DEF_IND */
|
||||
sizeof(hciLePhyUpdateEvt_t), /* DM_PHY_UPDATE_IND */
|
||||
sizeof(dmAdvSetStartEvt_t), /* DM_ADV_SET_START_IND */
|
||||
sizeof(hciLeAdvSetTermEvt_t), /* DM_ADV_SET_STOP_IND */
|
||||
sizeof(hciLeScanReqRcvdEvt_t), /* DM_SCAN_REQ_RCVD_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_EXT_SCAN_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_EXT_SCAN_STOP_IND */
|
||||
sizeof(hciLeExtAdvReportEvt_t), /* DM_EXT_SCAN_REPORT_IND */
|
||||
sizeof(dmPerAdvSetStartEvt_t), /* DM_PER_ADV_SET_START_IND */
|
||||
sizeof(dmPerAdvSetStopEvt_t), /* DM_PER_ADV_SET_STOP_IND */
|
||||
sizeof(hciLePerAdvSyncEstEvt_t), /* DM_PER_ADV_SYNC_EST_IND */
|
||||
sizeof(hciLePerAdvSyncEstEvt_t), /* DM_PER_ADV_SYNC_EST_FAIL_IND */
|
||||
sizeof(hciLePerAdvSyncLostEvt_t), /* DM_PER_ADV_SYNC_LOST_IND */
|
||||
sizeof(HciLePerAdvSyncTrsfRcvdEvt_t), /* DM_PER_ADV_SYNC_TRSF_EST_IND */
|
||||
sizeof(HciLePerAdvSyncTrsfRcvdEvt_t), /* DM_PER_ADV_SYNC_TRSF_EST_FAIL_IND */
|
||||
sizeof(hciLePerAdvSyncTrsfCmdCmplEvt_t), /* DM_PER_ADV_SYNC_TRSF_IND */
|
||||
sizeof(hciLePerAdvSetInfoTrsfCmdCmplEvt_t), /* DM_PER_ADV_SET_INFO_TRSF_IND */
|
||||
sizeof(hciLePerAdvReportEvt_t), /* DM_PER_ADV_REPORT_IND */
|
||||
sizeof(hciLeReadRemoteFeatCmplEvt_t), /* DM_REMOTE_FEATURES_IND */
|
||||
sizeof(hciReadRemoteVerInfoCmplEvt_t), /* DM_READ_REMOTE_VER_INFO_IND */
|
||||
sizeof(hciLeConnIQReportEvt_t), /* DM_CONN_IQ_REPORT_IND */
|
||||
sizeof(hciLeCteReqFailedEvt_t), /* DM_CTE_REQ_FAIL_IND */
|
||||
sizeof(hciLeSetConnCteRxParamsCmdCmplEvt_t), /* DM_CONN_CTE_RX_SAMPLE_START_IND */
|
||||
sizeof(hciLeSetConnCteRxParamsCmdCmplEvt_t), /* DM_CONN_CTE_RX_SAMPLE_START_IND */
|
||||
sizeof(hciLeSetConnCteTxParamsCmdCmplEvt_t), /* DM_CONN_CTE_TX_CFG_IND */
|
||||
sizeof(hciLeConnCteReqEnableCmdCmplEvt_t), /* DM_CONN_CTE_REQ_START_IND */
|
||||
sizeof(hciLeConnCteReqEnableCmdCmplEvt_t), /* DM_CONN_CTE_REQ_STOP_IND */
|
||||
sizeof(hciLeConnCteRspEnableCmdCmplEvt_t), /* DM_CONN_CTE_RSP_START_IND */
|
||||
sizeof(hciLeConnCteRspEnableCmdCmplEvt_t), /* DM_CONN_CTE_RSP_STOP_IND */
|
||||
sizeof(hciLeReadAntennaInfoCmdCmplEvt_t), /* DM_READ_ANTENNA_INFO_IND */
|
||||
sizeof(dmL2cCmdRejEvt_t), /* DM_L2C_CMD_REJ_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ERROR_IND */
|
||||
sizeof(hciHwErrorEvt_t), /* DM_HW_ERROR_IND */
|
||||
sizeof(hciVendorSpecEvt_t) /* DM_VENDOR_SPEC_IND */
|
||||
};
|
||||
|
||||
/* Default component function inteface */
|
||||
static const dmFcnIf_t dmFcnDefault =
|
||||
{
|
||||
dmEmptyReset,
|
||||
(dmHciHandler_t) dmEmptyHandler,
|
||||
(dmMsgHandler_t) dmEmptyHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface table indexed DM component ID */
|
||||
dmFcnIf_t *dmFcnIfTbl[DM_NUM_IDS] =
|
||||
{
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_ADV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_DEV_PRIV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SCAN */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_CONN */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_CONN_2 */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SEC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PRIV */
|
||||
(dmFcnIf_t *) &dmDevFcnIf, /* DM_ID_DEV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_LESC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PHY */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_ADV_PER */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SYNC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PAST */
|
||||
(dmFcnIf_t *) &dmFcnDefault /* DM_ID_CONN_CTE */
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmCb_t dmCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI event callback function.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmHciEvtCback(hciEvt_t *pEvent)
|
||||
{
|
||||
WSF_ASSERT(pEvent->hdr.event <= HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT);
|
||||
|
||||
/* if DM not resetting or resetting but incoming event is HCI reset sequence complete event */
|
||||
if (!dmCb.resetting || (pEvent->hdr.event == HCI_RESET_SEQ_CMPL_CBACK_EVT))
|
||||
{
|
||||
/* route event to DM component handling function */
|
||||
(*(dmFcnIfTbl[dmHciToIdTbl[pEvent->hdr.event]]->hciHandler))(pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM empty reset handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmEmptyReset(void)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM empty event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmEmptyHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass an HCI event to the DM connection management module.
|
||||
*
|
||||
* \param pEvent HCI event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassHciEvtToConn(hciEvt_t *pEvent)
|
||||
{
|
||||
/* pass event to DM connection management module */
|
||||
(*(dmFcnIfTbl[DM_ID_CONN]->hciHandler))(pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a callback with DM for scan and advertising events.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmRegister(dmCback_t cback)
|
||||
{
|
||||
dmCb.cback = cback;
|
||||
|
||||
/* if LESC is enabled */
|
||||
if (dmFcnIfTbl[DM_ID_LESC] != &dmFcnDefault)
|
||||
{
|
||||
/* if largest LESC key length is larger than maximum RX PDU length */
|
||||
if (SMP_PUB_KEY_MSG_LEN > (HciGetMaxRxAclLen() - L2C_HDR_LEN))
|
||||
{
|
||||
dmEvt_t evt;
|
||||
|
||||
evt.hdr.param = 0;
|
||||
evt.hdr.event = DM_ERROR_IND;
|
||||
evt.hdr.status = DM_ERR_SMP_RX_PDU_LEN_EXCEEDED;
|
||||
|
||||
(*dmCb.cback)(&evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find an advertising data element in the given advertising or scan response data.
|
||||
*
|
||||
* \param adType Advertising data element type to find.
|
||||
* \param dataLen Data length.
|
||||
* \param pData Pointer to advertising or scan response data.
|
||||
*
|
||||
* \return Pointer to advertising data element byte array or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *DmFindAdType(uint8_t adType, uint16_t dataLen, uint8_t *pData)
|
||||
{
|
||||
/* while not at end of data and
|
||||
* data element length is not zero and
|
||||
* data element length is not erroneously more than the data length
|
||||
*/
|
||||
while ((dataLen != 0) && (pData[DM_AD_LEN_IDX] != 0) && (pData[DM_AD_LEN_IDX] < dataLen))
|
||||
{
|
||||
/* if found */
|
||||
if (pData[DM_AD_TYPE_IDX] == adType)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
/* else go to next element */
|
||||
dataLen = dataLen - pData[DM_AD_LEN_IDX] - 1;
|
||||
pData = pData + pData[DM_AD_LEN_IDX] + 1;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID for DM.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
/* store handler ID */
|
||||
dmCb.handlerId = handlerId;
|
||||
|
||||
dmCb.llPrivEnabled = FALSE;
|
||||
dmCb.resetting = FALSE;
|
||||
|
||||
/* register with the HCI event interface */
|
||||
HciEvtRegister(dmHciEvtCback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for DM.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
WSF_ASSERT(DM_ID_FROM_MSG(pMsg->event) < DM_NUM_IDS);
|
||||
|
||||
/* if DM not resetting */
|
||||
if (!dmCb.resetting)
|
||||
{
|
||||
/* route message to DM component handling function */
|
||||
(*(dmFcnIfTbl[DM_ID_FROM_MSG(pMsg->event)]->msgHandler))(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether LL Privacy is enabled.
|
||||
*
|
||||
* \return TRUE if LL Privacy is enabled. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmLlPrivEnabled(void)
|
||||
{
|
||||
return dmCb.llPrivEnabled;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Map an address type to a type used by LL.
|
||||
*
|
||||
* \param addrType Address type used by Host.
|
||||
*
|
||||
* \return Address type used by LL.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmLlAddrType(uint8_t addrType)
|
||||
{
|
||||
uint8_t llAddrType = addrType;
|
||||
|
||||
/* if LL Privacy is enabled */
|
||||
if (dmCb.llPrivEnabled)
|
||||
{
|
||||
if (addrType == DM_ADDR_PUBLIC)
|
||||
{
|
||||
llAddrType = DM_ADDR_PUBLIC_IDENTITY;
|
||||
}
|
||||
else if (addrType == DM_ADDR_RANDOM)
|
||||
{
|
||||
llAddrType = DM_ADDR_RANDOM_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
return llAddrType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Map an address type to a type used by Host.
|
||||
*
|
||||
* \param addrType Address type used by LL.
|
||||
*
|
||||
* \return Address type used by Host.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmHostAddrType(uint8_t addrType)
|
||||
{
|
||||
uint8_t hostAddrType = addrType;
|
||||
|
||||
/* if LL Privacy is enabled */
|
||||
if (dmCb.llPrivEnabled)
|
||||
{
|
||||
if (addrType == DM_ADDR_PUBLIC_IDENTITY)
|
||||
{
|
||||
hostAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
else if (addrType == DM_ADDR_RANDOM_IDENTITY)
|
||||
{
|
||||
hostAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
return hostAddrType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return size of a DM callback event.
|
||||
*
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return Size of DM callback event.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t DmSizeOfEvt(dmEvt_t *pDmEvt)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
/* if a valid DM event ID */
|
||||
if ((pDmEvt->hdr.event >= DM_CBACK_START) && (pDmEvt->hdr.event <= DM_CBACK_END))
|
||||
{
|
||||
len = dmEvtCbackLen[pDmEvt->hdr.event - DM_CBACK_START];
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sizeof(wsfMsgHdr_t);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given scanner PHY.
|
||||
*
|
||||
* \param numPhys Number of scanner PHYs.
|
||||
* \param scanPhy Scanner PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t dmScanPhyToIdx(uint8_t numPhys, uint8_t scanPhy)
|
||||
{
|
||||
/* if number of supported PHYs is 1 */
|
||||
if (numPhys == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if number of supported PHYs is 2 */
|
||||
if (numPhys == 2)
|
||||
{
|
||||
return (scanPhy == HCI_SCAN_PHY_LE_1M_BIT) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* all three PHYs are supported */
|
||||
return (scanPhy == HCI_SCAN_PHY_LE_1M_BIT) ? 0 : (scanPhy == HCI_SCAN_PHY_LE_2M_BIT) ? 1 : 2;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given scanner PHY.
|
||||
*
|
||||
* \param scanPhy Scanner PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmScanPhyToIdx(uint8_t scanPhy)
|
||||
{
|
||||
return dmScanPhyToIdx(DM_NUM_PHYS, scanPhy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given initiator PHY.
|
||||
*
|
||||
* \param numPhys Number of initiator PHYs.
|
||||
* \param initPhy Initiator PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t dmInitPhyToIdx(uint8_t numPhys, uint8_t initPhy)
|
||||
{
|
||||
/* if number of supported PHYs is 1 */
|
||||
if (numPhys == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if number of supported PHYs is 2 */
|
||||
if (numPhys == 2)
|
||||
{
|
||||
return (initPhy == HCI_INIT_PHY_LE_1M_BIT) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* all three PHYs are supported */
|
||||
return (initPhy == HCI_INIT_PHY_LE_1M_BIT) ? 0 : (initPhy == HCI_INIT_PHY_LE_2M_BIT) ? 1 : 2;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given initiator PHY.
|
||||
*
|
||||
* \param initPhy Initiator PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmInitPhyToIdx(uint8_t initPhy)
|
||||
{
|
||||
return dmInitPhyToIdx(DM_NUM_PHYS, initPhy);
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM main module.
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_MAIN_H
|
||||
#define DM_MAIN_H
|
||||
|
||||
#include "util/bda.h"
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM component IDs */
|
||||
#define DM_ID_ADV 0
|
||||
#define DM_ID_DEV_PRIV 1
|
||||
#define DM_ID_SCAN 2
|
||||
#define DM_ID_CONN 3
|
||||
#define DM_ID_CONN_2 4
|
||||
#define DM_ID_SEC 5
|
||||
#define DM_ID_PRIV 6
|
||||
#define DM_ID_DEV 7
|
||||
#define DM_ID_LESC 8
|
||||
#define DM_ID_PHY 9
|
||||
#define DM_ID_ADV_PER 10
|
||||
#define DM_ID_SYNC 11
|
||||
#define DM_ID_PAST 12
|
||||
#define DM_ID_CONN_CTE 13
|
||||
#define DM_NUM_IDS 14
|
||||
|
||||
/* Start of component message enumeration */
|
||||
#define DM_MSG_START(id) ((id) << 4)
|
||||
|
||||
/* Get the component ID from a message ID */
|
||||
#define DM_ID_FROM_MSG(msg) ((msg) >> 4)
|
||||
|
||||
/* Mask off the ID from the message ID */
|
||||
#define DM_MSG_MASK(msg) ((msg) & 0x0F)
|
||||
|
||||
/* Length of hash part of private resolvable address */
|
||||
#define DM_PRIV_HASH_LEN 3
|
||||
|
||||
/* Length of random part of private resolvable address */
|
||||
#define DM_PRIV_PRAND_LEN 3
|
||||
|
||||
/* Length of plaintext used for private resolvable address calculation */
|
||||
#define DM_PRIV_PLAINTEXT_LEN 16
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM reset function type */
|
||||
typedef void (*dmReset_t)(void);
|
||||
|
||||
/* DM message handling function types */
|
||||
typedef void (*dmMsgHandler_t)(wsfMsgHdr_t *pMsg);
|
||||
typedef void (*dmHciHandler_t)(hciEvt_t *pEvent);
|
||||
|
||||
/* DM component reset and handler function interface */
|
||||
typedef struct
|
||||
{
|
||||
dmReset_t reset;
|
||||
dmHciHandler_t hciHandler;
|
||||
dmMsgHandler_t msgHandler;
|
||||
} dmFcnIf_t;
|
||||
|
||||
/* Main control block of the DM subsystem */
|
||||
typedef struct
|
||||
{
|
||||
bdAddr_t localAddr;
|
||||
dmCback_t cback;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint8_t connAddrType;
|
||||
uint8_t advAddrType;
|
||||
uint8_t scanAddrType;
|
||||
bool_t resetting;
|
||||
|
||||
/* Filter policies for Advertising, Scanning, Initiator and Synchronization */
|
||||
uint8_t advFiltPolicy[DM_NUM_ADV_SETS];
|
||||
uint8_t scanFiltPolicy;
|
||||
uint8_t initFiltPolicy;
|
||||
|
||||
/* Options (filter policies and periodic advertising report enablement) for Synchronization */
|
||||
uint8_t syncOptions;
|
||||
|
||||
/* LL Privacy */
|
||||
bool_t llPrivEnabled;
|
||||
} dmCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface table indexed DM component ID */
|
||||
extern dmFcnIf_t *dmFcnIfTbl[DM_NUM_IDS];
|
||||
|
||||
/* Control block */
|
||||
extern dmCb_t dmCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void dmEmptyReset(void);
|
||||
void dmEmptyHandler(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/* utility functions */
|
||||
uint8_t DmScanPhyToIdx(uint8_t scanPhy);
|
||||
uint8_t DmInitPhyToIdx(uint8_t initPhy);
|
||||
void dmDevPassHciEvtToConn(hciEvt_t *pEvent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_MAIN_H */
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager periodic advertising sync transfer (PAST) module.
|
||||
*
|
||||
* Copyright (c) 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_scan.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM past event handler messages */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_PAST_MSG_API_RCV_ENABLE = DM_MSG_START(DM_ID_PAST), /*!< Enable receiving report */
|
||||
DM_PAST_MSG_API_SYNC_TRSF, /*!< Transfer sync */
|
||||
DM_PAST_MSG_API_SET_INFO_TRSF, /*!< Transfer set info */
|
||||
DM_PAST_MSG_API_CFG, /*!< Configure PAST parameters */
|
||||
DM_PAST_MSG_API_DEFAULT_CFG /*!< Configure PAST default parameters */
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmPastAct_t dmPastAct[] =
|
||||
{
|
||||
dmPastActRptRcvEnable,
|
||||
dmPastActSyncTsfr,
|
||||
dmPastActSetInfoTrsf,
|
||||
dmPastActConfig,
|
||||
dmPastActDefaultConfig
|
||||
};
|
||||
|
||||
/*! DM PAST component function interface */
|
||||
static const dmFcnIf_t dmPastFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmPastHciHandler,
|
||||
dmPastMsgHandler
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM Periodic Advertising Sync Transfer (PAST) module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastInit(void)
|
||||
{
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_PAST] = (dmFcnIf_t *) &dmPastFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb = dmConnCcbByHandle(pEvent->hdr.param);
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
/* set conn id */
|
||||
pEvent->hdr.param = pCcb->connId;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_PER_ADV_SYNC_TRSF_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_PER_ADV_SYNC_TRSF_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_PER_ADV_SET_INFO_TRSF_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_PER_ADV_SET_INFO_TRSF_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmPastAct[DM_MSG_MASK(pMsg->event)])((dmPastMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable receiving report action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActRptRcvEnable(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* look up scb from sync id */
|
||||
if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
HciLeSetPerAdvRcvEnableCmd(pScb->handle, (pMsg->hdr.status ? TRUE : FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transfer sync action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActSyncTsfr(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* look up scb from sync id */
|
||||
if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL)
|
||||
{
|
||||
HciLePerAdvSyncTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, pScb->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transfer set info action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActSetInfoTrsf(dmPastMsg_t *pMsg)
|
||||
{
|
||||
uint8_t advHandle = (uint8_t) pMsg->hdr.param;
|
||||
|
||||
/* if periodic advertising is currently in progress for the advertising set */
|
||||
if (dmPerAdvState(advHandle) == DM_ADV_PER_STATE_ADVERTISING)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL)
|
||||
{
|
||||
HciLePerAdvSetInfoTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, advHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure PAST action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActConfig(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById((dmConnId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
HciLeSetPerAdvSyncTrsfParamsCmd(pCcb->handle, pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip,
|
||||
pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure default PAST action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActDefaultConfig(dmPastMsg_t *pMsg)
|
||||
{
|
||||
HciLeSetDefaultPerAdvSyncTrsfParamsCmd(pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip,
|
||||
pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable or disable reports for the periodic advertising identified by the sync id.
|
||||
*
|
||||
* \param syncId Sync identifier.
|
||||
* \param enable TRUE to enable reporting, FALSE to disable reporting.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastRptRcvEnable(dmSyncId_t syncId, bool_t enable)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->param = syncId;
|
||||
pMsg->event = DM_PAST_MSG_API_RCV_ENABLE;
|
||||
pMsg->status = enable;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send synchronization information about the periodic advertising identified by the
|
||||
* sync id to a connected device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param serviceData Value provided by the Host.
|
||||
* \param syncId Sync identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastSyncTrsf(dmConnId_t connId, uint16_t serviceData, dmSyncId_t syncId)
|
||||
{
|
||||
dmPastApiTrsf_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = syncId;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_SYNC_TRSF;
|
||||
pMsg->serviceData = serviceData;
|
||||
pMsg->connId = connId;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send synchronization information about the periodic advertising in an advertising
|
||||
* set to a connected device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param serviceData Value provided by the Host.
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastSetInfoTrsf(dmConnId_t connId, uint16_t serviceData, uint8_t advHandle)
|
||||
{
|
||||
dmPastApiTrsf_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = advHandle;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_SET_INFO_TRSF;
|
||||
pMsg->serviceData = serviceData;
|
||||
pMsg->connId = connId;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Specify how the Controller should process periodic advertising synchronization
|
||||
* information received from the device identified by the connection handle.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param mode Action to be taken when periodic advertising info is received.
|
||||
* \param skip Number of consecutive periodic advertising packets that the receiver
|
||||
* may skip after successfully receiving a periodic advertising packet.
|
||||
* \param syncTimeout Maximum permitted time between successful receives. If this time is
|
||||
* exceeded, synchronization is lost.
|
||||
* \param cteType Whether to only synchronize to periodic advertising with certain
|
||||
* types of Constant Tone Extension.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastConfig(dmConnId_t connId, uint8_t mode, uint16_t skip, uint16_t syncTimeout,
|
||||
uint8_t cteType)
|
||||
{
|
||||
dmPastApiCfg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_CFG;
|
||||
pMsg->mode = mode;
|
||||
pMsg->skip = skip;
|
||||
pMsg->syncTimeout = syncTimeout;
|
||||
pMsg->cteType = cteType;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Specify the initial value for the mode, skip, timeout, and Constant Tone Extension type
|
||||
* to be used for all subsequent connections over the LE transport.
|
||||
*
|
||||
* \param mode Action to be taken when periodic advertising info is received.
|
||||
* \param skip Number of consecutive periodic advertising packets that the receiver
|
||||
* may skip after successfully receiving a periodic advertising packet.
|
||||
* \param syncTimeout Maximum permitted time between successful receives. If this time is
|
||||
* exceeded, synchronization is lost.
|
||||
* \param cteType Whether to only synchronize to periodic advertising with certain
|
||||
* types of Constant Tone Extension.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastDefaultConfig(uint8_t mode, uint16_t skip, uint16_t syncTimeout, uint8_t cteType)
|
||||
{
|
||||
dmPastApiCfg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_DEFAULT_CFG;
|
||||
pMsg->mode = mode;
|
||||
pMsg->skip = skip;
|
||||
pMsg->syncTimeout = syncTimeout;
|
||||
pMsg->cteType = cteType;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM PHY module.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_phy.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmPhyFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmPhyHciHandler,
|
||||
(dmMsgHandler_t)dmEmptyHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
static void dmPhyActDefPhySet(hciEvt_t *pEvent);
|
||||
static void dmPhyActPhyRead(dmConnCcb_t *pCcb, hciEvt_t *pEvent);
|
||||
static void dmPhyActPhyUpdate(dmConnCcb_t *pCcb, hciEvt_t *pEvent);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PHY HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPhyHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_SET_DEF_PHY_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmPhyActDefPhySet(pEvent);
|
||||
}
|
||||
/* look up ccb from conn handle */
|
||||
else if ((pCcb = dmConnCcbByHandle(pEvent->hdr.param)) != NULL)
|
||||
{
|
||||
/* handle incoming event */
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_READ_PHY_CMD_CMPL_CBACK_EVT:
|
||||
dmPhyActPhyRead(pCcb, pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_PHY_UPDATE_CMPL_CBACK_EVT:
|
||||
dmPhyActPhyUpdate(pCcb, pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never get here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a read PHY event from HCI.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActPhyRead(dmConnCcb_t *pCcb, hciEvt_t *pEvent)
|
||||
{
|
||||
hciLeReadPhyCmdCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_READ_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->leReadPhyCmdCmpl.status;
|
||||
evt.handle = pCcb->handle;
|
||||
evt.txPhy = pEvent->leReadPhyCmdCmpl.txPhy;
|
||||
evt.rxPhy = pEvent->leReadPhyCmdCmpl.rxPhy;
|
||||
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a set default PHY event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActDefPhySet(hciEvt_t *pEvent)
|
||||
{
|
||||
hciLeSetDefPhyCmdCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_SET_DEF_IND;
|
||||
evt.hdr.param = 0;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->leSetDefPhyCmdCmpl.status;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a PHY update event from HCI.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActPhyUpdate(dmConnCcb_t *pCcb, hciEvt_t *pEvent)
|
||||
{
|
||||
hciLePhyUpdateEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_UPDATE_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->lePhyUpdate.status;
|
||||
evt.handle = pCcb->handle;
|
||||
evt.txPhy = pEvent->lePhyUpdate.txPhy;
|
||||
evt.rxPhy = pEvent->lePhyUpdate.rxPhy;
|
||||
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the current transmitter PHY and receiver PHY for a given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmReadPhy(dmConnId_t connId)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
WsfTaskLock();
|
||||
/* look up ccb from conn id */
|
||||
pCcb = dmConnCcbById(connId);
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
HciLeReadPhyCmd(pCcb->handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the preferred values for the transmitter PHY and receiver PHY for all subsequent
|
||||
* connections.
|
||||
*
|
||||
* \param allPhys All PHYs preferences.
|
||||
* \param txPhys Preferred transmitter PHYs.
|
||||
* \param rxPhys Preferred receiver PHYs.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSetDefaultPhy(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys)
|
||||
{
|
||||
HciLeSetDefaultPhyCmd(allPhys, txPhys, rxPhys);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the PHY preferences for a given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param allPhys All PHYs preferences.
|
||||
* \param txPhys Preferred transmitter PHYs.
|
||||
* \param rxPhys Preferred receiver PHYs.
|
||||
* \param phyOptions PHY options.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSetPhy(dmConnId_t connId, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
WsfTaskLock();
|
||||
/* look up ccb from conn id */
|
||||
pCcb = dmConnCcbById(connId);
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
HciLeSetPhyCmd(pCcb->handle, allPhys, txPhys, rxPhys, phyOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM PHY.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPhyInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_PHY] = (dmFcnIf_t *) &dmPhyFcnIf;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM PHY module.
|
||||
*
|
||||
* Copyright (c) 2016-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_PHY_H
|
||||
#define DM_PHY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data types
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* component interface */
|
||||
void dmPhyHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_PHY_H */
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager privacy module.
|
||||
*
|
||||
* Copyright (c) 2011-2019 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_priv.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* progress (dmPrivCb.inProgress) bitmask bits */
|
||||
#define DM_PRIV_INPROGRESS_RES_ADDR (1 << 0) /* resolve address in progress */
|
||||
#define DM_PRIV_INPROGRESS_GEN_ADDR (1 << 1) /* generate address in progress */
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmPrivAct_t dmPrivAct[] =
|
||||
{
|
||||
dmPrivActResolveAddr,
|
||||
dmPrivActResAddrAesCmpl,
|
||||
dmPrivActAddDevToResList,
|
||||
dmPrivActRemDevFromResList,
|
||||
dmPrivActClearResList,
|
||||
dmPrivActSetAddrResEnable,
|
||||
dmPrivActSetPrivacyMode,
|
||||
dmPrivActGenAddr,
|
||||
dmPrivActGenAddrAesCmpl
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmPrivFcnIf =
|
||||
{
|
||||
dmPrivReset,
|
||||
dmPrivHciHandler,
|
||||
dmPrivMsgHandler
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmPrivCb_t dmPrivCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void dmPrivSetAddrResEnable(bool_t enable);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start address resolution procedure
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActResolveAddr(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
uint8_t buf[DM_PRIV_PLAINTEXT_LEN];
|
||||
|
||||
/* verify no resolution procedure currently in progress */
|
||||
if ((dmPrivCb.inProgress & DM_PRIV_INPROGRESS_RES_ADDR) == 0)
|
||||
{
|
||||
/* store hash */
|
||||
memcpy(dmPrivCb.hash, pMsg->apiResolveAddr.addr, DM_PRIV_HASH_LEN);
|
||||
|
||||
/* copy random part of address with padding for address resolution calculation */
|
||||
memcpy(buf, &pMsg->apiResolveAddr.addr[3], DM_PRIV_PRAND_LEN);
|
||||
memset(buf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* set in progress */
|
||||
dmPrivCb.inProgress |= DM_PRIV_INPROGRESS_RES_ADDR;
|
||||
|
||||
/* run calculation */
|
||||
SecAes(pMsg->apiResolveAddr.irk, buf, dmCb.handlerId,
|
||||
pMsg->hdr.param, DM_PRIV_MSG_RESOLVE_AES_CMPL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call callback with error (note hdr.param is already set) */
|
||||
pMsg->hdr.status = HCI_ERR_MEMORY_EXCEEDED;
|
||||
pMsg->hdr.event = DM_PRIV_RESOLVED_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Finish address resolution procedure upon completion of AES calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActResAddrAesCmpl(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
/* compare calculated value with hash */
|
||||
if (memcmp(dmPrivCb.hash, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN) == 0)
|
||||
{
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = HCI_ERR_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
/* clear in progress */
|
||||
dmPrivCb.inProgress &= ~DM_PRIV_INPROGRESS_RES_ADDR;
|
||||
|
||||
/* call client callback (note hdr.param is already set) */
|
||||
pMsg->hdr.event = DM_PRIV_RESOLVED_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add device to resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActAddDevToResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiAddDevToResList_t *pDev = &pMsg->apiAddDevToResList;
|
||||
|
||||
/* save whether asked to enable address resolution */
|
||||
dmPrivCb.enableLlPriv = pDev->enableLlPriv;
|
||||
|
||||
/* save client-defined parameter for callback event */
|
||||
dmPrivCb.addDevToResListParam = pMsg->hdr.param;
|
||||
|
||||
/* add device to resolving list */
|
||||
HciLeAddDeviceToResolvingListCmd(pDev->addrType, pDev->peerAddr, pDev->peerIrk, pDev->localIrk);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove device from resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActRemDevFromResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiRemDevFromResList_t *pDev = &pMsg->apiRemDevFromResList;
|
||||
|
||||
/* save client-defined parameter for callback event */
|
||||
dmPrivCb.remDevFromResListParam = pMsg->hdr.param;
|
||||
|
||||
/* remove device from resolving list */
|
||||
HciLeRemoveDeviceFromResolvingList(pDev->addrType, pDev->peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActClearResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
/* clear resolving list */
|
||||
HciLeClearResolvingList();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set address resolution enable command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActSetAddrResEnable(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiSetAddrResEnable_t *pAddrRes = &pMsg->apiSetAddrResEnable;
|
||||
|
||||
/* enable or disable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(pAddrRes->enable);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set privacy mode command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActSetPrivacyMode(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiSetPrivacyMode_t *pPrivacyMode = &pMsg->apiSetPrivacyMode;
|
||||
|
||||
/* set privacy mode */
|
||||
HciLeSetPrivacyModeCmd(pPrivacyMode->addrType, pPrivacyMode->peerAddr, pPrivacyMode->mode);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start address generation procedure.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActGenAddr(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
if ((dmPrivCb.inProgress & DM_PRIV_INPROGRESS_GEN_ADDR) == 0)
|
||||
{
|
||||
/* get random number */
|
||||
SecRand(dmPrivCb.genAddrBuf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set address type in random number */
|
||||
dmPrivCb.genAddrBuf[2] = (dmPrivCb.genAddrBuf[2] & 0x3F) | DM_RAND_ADDR_RESOLV;
|
||||
|
||||
/* pad buffer */
|
||||
memset(dmPrivCb.genAddrBuf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* set in progress */
|
||||
dmPrivCb.inProgress |= DM_PRIV_INPROGRESS_GEN_ADDR;
|
||||
|
||||
/* run calculation */
|
||||
SecAes(pMsg->apiGenerateAddr.irk, dmPrivCb.genAddrBuf, dmCb.handlerId,
|
||||
pMsg->hdr.param, DM_PRIV_MSG_GEN_ADDR_AES_CMPL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call callback with error (note hdr.param is already set) */
|
||||
pMsg->hdr.status = HCI_ERR_MEMORY_EXCEEDED;
|
||||
pMsg->hdr.event = DM_PRIV_GENERATE_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Finish generate RPA procedure upon completion of AES calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActGenAddrAesCmpl(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivGenAddrIndEvt_t *pAddrEvt = (dmPrivGenAddrIndEvt_t*) pMsg;
|
||||
|
||||
/* copy the hash and address to buffer */
|
||||
memcpy(pAddrEvt->addr, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN);
|
||||
memcpy(pAddrEvt->addr + DM_PRIV_HASH_LEN, dmPrivCb.genAddrBuf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* clear in progress */
|
||||
dmPrivCb.inProgress &= ~DM_PRIV_INPROGRESS_GEN_ADDR;
|
||||
|
||||
/* call client callback */
|
||||
pAddrEvt->hdr.event = DM_PRIV_GENERATE_ADDR_IND;
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
(*dmCb.cback)((dmEvt_t *) pAddrEvt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM priv HCI callback event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
/* handle incoming event */
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_ADD_DEV_TO_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_ADD_DEV_TO_RES_LIST_IND;
|
||||
pEvent->hdr.param = dmPrivCb.addDevToResListParam;
|
||||
|
||||
/* if LE add device to resolving list command succeeded and been asked to enable address
|
||||
* resolution in LL and it's not enabled yet
|
||||
*/
|
||||
if ((pEvent->hdr.status == HCI_SUCCESS) && dmPrivCb.enableLlPriv && !dmCb.llPrivEnabled)
|
||||
{
|
||||
/* enable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LE_REM_DEV_FROM_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_REM_DEV_FROM_RES_LIST_IND;
|
||||
pEvent->hdr.param = dmPrivCb.remDevFromResListParam;
|
||||
break;
|
||||
|
||||
case HCI_LE_CLEAR_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_CLEAR_RES_LIST_IND;
|
||||
|
||||
/* if LE clear resolving list command succeeded and address resolution's enabled in LL */
|
||||
if ((pEvent->hdr.status == HCI_SUCCESS) && dmCb.llPrivEnabled)
|
||||
{
|
||||
/* disable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LE_READ_PEER_RES_ADDR_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_READ_PEER_RES_ADDR_IND;
|
||||
break;
|
||||
|
||||
case HCI_LE_READ_LOCAL_RES_ADDR_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_READ_LOCAL_RES_ADDR_IND;
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_ADDR_RES_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_SET_ADDR_RES_ENABLE_IND;
|
||||
|
||||
/* if LE set address resoultion enable command succeeded */
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
/* update LL Privacy Enabled flag */
|
||||
dmCb.llPrivEnabled = dmPrivCb.addrResEnable;
|
||||
|
||||
/* pass LL Privacy enable/disable event to dev priv */
|
||||
dmDevPassEvtToDevPriv(dmCb.llPrivEnabled ? DM_DEV_PRIV_MSG_RPA_STOP : DM_DEV_PRIV_MSG_RPA_START,
|
||||
dmCb.llPrivEnabled ? TRUE : FALSE, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never get here */
|
||||
return;
|
||||
}
|
||||
|
||||
/* call callback (note hdr.status is already set) */
|
||||
(*dmCb.cback)((dmEvt_t *)pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set address resolution enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable address resolution or FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPrivSetAddrResEnable(bool_t enable)
|
||||
{
|
||||
/* save input parameter */
|
||||
dmPrivCb.addrResEnable = enable;
|
||||
|
||||
/* enable or disable address resolution in LL */
|
||||
HciLeSetAddrResolutionEnable(enable);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM priv event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmPrivAct[DM_MSG_MASK(pMsg->event)])((dmPrivMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivReset(void)
|
||||
{
|
||||
/* initialize control block */
|
||||
dmPrivCb.inProgress = 0;
|
||||
dmCb.llPrivEnabled = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_PRIV] = (dmFcnIf_t *) &dmPrivFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Resolve a private resolvable address. When complete the client's callback function
|
||||
* is called with a DM_PRIV_RESOLVED_ADDR_IND event. The client must wait to receive
|
||||
* this event before executing this function again.
|
||||
*
|
||||
* \param pAddr Peer device address.
|
||||
* \param pIrk The peer's identity resolving key.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivResolveAddr(uint8_t *pAddr, uint8_t *pIrk, uint16_t param)
|
||||
{
|
||||
dmPrivApiResolveAddr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiResolveAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_RESOLVE_ADDR;
|
||||
pMsg->hdr.param = param;
|
||||
Calc128Cpy(pMsg->irk, pIrk);
|
||||
BdaCpy(pMsg->addr, pAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add device to resolving list. When complete the client's callback function
|
||||
* is called with a DM_PRIV_ADD_DEV_TO_RES_LIST_IND event. The client must wait
|
||||
* to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param pPeerIrk The peer's identity resolving key.
|
||||
* \param pLocalIrk The local identity resolving key.
|
||||
* \param enableLlPriv Set to TRUE to enable address resolution in LL.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*
|
||||
* \Note If the local or peer IRK associated with the peer Identity Address is all zeros then
|
||||
* the Controller will use or accept the local or peer Identity Address respectively.
|
||||
*
|
||||
* \Note Parameter 'enableLlPriv' should be set to TRUE when the last device is being added
|
||||
* to resolving list to enable address resolution in the Controller.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivAddDevToResList(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t *pPeerIrk,
|
||||
uint8_t *pLocalIrk, bool_t enableLlPriv, uint16_t param)
|
||||
{
|
||||
dmPrivApiAddDevToResList_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiAddDevToResList_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
Calc128Cpy(pMsg->peerIrk, pPeerIrk);
|
||||
Calc128Cpy(pMsg->localIrk, pLocalIrk);
|
||||
pMsg->enableLlPriv = enableLlPriv;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove device from resolving list. When complete the client's callback function
|
||||
* is called with a DM_PRIV_REM_DEV_FROM_RES_LIST_IND event. The client must wait to
|
||||
* receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivRemDevFromResList(uint8_t addrType, const uint8_t *pIdentityAddr, uint16_t param)
|
||||
{
|
||||
dmPrivApiRemDevFromResList_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiRemDevFromResList_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear resolving list. When complete the client's callback function is called with a
|
||||
* DM_PRIV_CLEAR_RES_LIST_IND event. The client must wait to receive this event before
|
||||
* executing this function again.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*
|
||||
* \Note Address resolution in the Controller will be disabled when resolving list's cleared
|
||||
* successfully.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivClearResList(void)
|
||||
{
|
||||
dmPrivMsg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivMsg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_CLEAR_RES_LIST;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI read peer resolvable address command. When complete the client's callback
|
||||
* function is called with a DM_PRIV_READ_PEER_RES_ADDR_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivReadPeerResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr)
|
||||
{
|
||||
HciLeReadPeerResolvableAddr(addrType, pIdentityAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read local resolvable address command. When complete the client's callback
|
||||
* function is called with a DM_PRIV_READ_LOCAL_RES_ADDR_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivReadLocalResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr)
|
||||
{
|
||||
HciLeReadLocalResolvableAddr(addrType, pIdentityAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable or disable address resolution in LL. When complete the client's callback
|
||||
* function is called with a DM_PRIV_SET_ADDR_RES_ENABLE_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param enable Set to TRUE to enable address resolution or FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command can be used at any time except when:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetAddrResEnable(bool_t enable)
|
||||
{
|
||||
dmPrivApiSetAddrResEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivMsg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE;
|
||||
pMsg->hdr.param = 0;
|
||||
pMsg->enable = enable;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set resolvable private address timeout command.
|
||||
*
|
||||
* \param rpaTimeout Timeout measured in seconds.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetResolvablePrivateAddrTimeout(uint16_t rpaTimeout)
|
||||
{
|
||||
HciLeSetResolvablePrivateAddrTimeout(rpaTimeout);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set privacy mode for a given entry in the resolving list.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param mode Privacy mode (by default, network privacy mode is used).
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command can be used at any time except when:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetPrivacyMode(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t mode)
|
||||
{
|
||||
dmPrivApiSetPrivacyMode_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiSetPrivacyMode_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_SET_PRIVACY_MODE;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
pMsg->mode = mode;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a Resolvable Private Address (RPA).
|
||||
*
|
||||
* \param pIrk The identity resolving key.
|
||||
* \param param Client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivGenerateAddr(uint8_t *pIrk, uint16_t param)
|
||||
{
|
||||
dmPrivApiGenAddr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiGenAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_GEN_ADDR;
|
||||
pMsg->hdr.param = param;
|
||||
Calc128Cpy(pMsg->irk, pIrk);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM privacy module.
|
||||
*
|
||||
* Copyright (c) 2011-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_PRIV_H
|
||||
#define DM_PRIV_H
|
||||
|
||||
#include "util/bda.h"
|
||||
#include "wsf_os.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "sec_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "smp_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM priv event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_PRIV_MSG_API_RESOLVE_ADDR = DM_MSG_START(DM_ID_PRIV),
|
||||
DM_PRIV_MSG_RESOLVE_AES_CMPL,
|
||||
DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST,
|
||||
DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST,
|
||||
DM_PRIV_MSG_API_CLEAR_RES_LIST,
|
||||
DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE,
|
||||
DM_PRIV_MSG_API_SET_PRIVACY_MODE,
|
||||
DM_PRIV_MSG_API_GEN_ADDR,
|
||||
DM_PRIV_MSG_GEN_ADDR_AES_CMPL
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_RESOLVE_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t irk[SMP_KEY_LEN];
|
||||
bdAddr_t addr;
|
||||
} dmPrivApiResolveAddr_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_GEN_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t irk[SMP_KEY_LEN];
|
||||
} dmPrivApiGenAddr_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t peerIrk[SMP_KEY_LEN];
|
||||
uint8_t localIrk[SMP_KEY_LEN];
|
||||
bool_t enableLlPriv;
|
||||
} dmPrivApiAddDevToResList_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
} dmPrivApiRemDevFromResList_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
bool_t enable;
|
||||
} dmPrivApiSetAddrResEnable_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_SET_PRIVACY_MODE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t mode;
|
||||
} dmPrivApiSetPrivacyMode_t;
|
||||
|
||||
/* Union of all priv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmPrivApiResolveAddr_t apiResolveAddr;
|
||||
dmPrivApiAddDevToResList_t apiAddDevToResList;
|
||||
dmPrivApiRemDevFromResList_t apiRemDevFromResList;
|
||||
dmPrivApiSetAddrResEnable_t apiSetAddrResEnable;
|
||||
dmPrivApiSetPrivacyMode_t apiSetPrivacyMode;
|
||||
dmPrivApiGenAddr_t apiGenerateAddr;
|
||||
dmPrivGenAddrIndEvt_t genAddrInd;
|
||||
secAes_t aes;
|
||||
} dmPrivMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmPrivAct_t)(dmPrivMsg_t *pMsg);
|
||||
|
||||
/* Control block for privacy module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t hash[DM_PRIV_HASH_LEN]; /* Hash part of resolvable address */
|
||||
bool_t inProgress; /* Address resolution in progress */
|
||||
uint16_t addDevToResListParam; /* 'Add device to resolving list' callback param */
|
||||
uint16_t remDevFromResListParam; /* 'Remove device from resolving list' callback param */
|
||||
bool_t enableLlPriv; /* 'Add device to resolving list' input param */
|
||||
bool_t addrResEnable; /* 'Set address resolution enable' input param */
|
||||
uint8_t genAddrBuf[HCI_ENCRYPT_DATA_LEN]; /* Random value buffer for generating an RPA */
|
||||
} dmPrivCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* component inteface */
|
||||
void dmPrivMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPrivHciHandler(hciEvt_t *pEvent);
|
||||
void dmPrivReset(void);
|
||||
|
||||
/* action functions */
|
||||
void dmPrivActResolveAddr(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActResAddrAesCmpl(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActAddDevToResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActRemDevFromResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActSetAddrResEnable(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActClearResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActSetPrivacyMode(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActGenAddr(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActGenAddrAesCmpl(dmPrivMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_PRIV_H */
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager scan module.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
dmScanCb_t dmScanCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the scan module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_NUM_PHYS; i++)
|
||||
{
|
||||
dmScanCb.scanInterval[i] = DM_GAP_SCAN_FAST_INT_MIN;
|
||||
dmScanCb.scanWindow[i] = DM_GAP_SCAN_FAST_WINDOW;
|
||||
}
|
||||
|
||||
dmCb.scanFiltPolicy = HCI_FILT_NONE;
|
||||
dmScanCb.scanTimer.handlerId = dmCb.handlerId;
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
dmCb.scanAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start scanning on the given PHYs.
|
||||
*
|
||||
* \param scanPhys Scanner PHYs.
|
||||
* \param mode Discoverability mode.
|
||||
* \param pScanType Scan type array.
|
||||
* \param filterDup Filter duplicates. Set to TRUE to filter duplicate responses received
|
||||
* from the same device. Set to FALSE to receive all responses.
|
||||
* \param duration The scan duration, in milliseconds. If set to zero or both duration and
|
||||
* period set to non-zero, scanning will continue until DmScanStop() is called.
|
||||
* \param period The scan period, in 1.28 sec units (only applicable to AE). If set to zero,
|
||||
* periodic scanning is disabled.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanStart(uint8_t scanPhys, uint8_t mode, const uint8_t *pScanType, bool_t filterDup,
|
||||
uint16_t duration, uint16_t period)
|
||||
{
|
||||
uint8_t i; /* scanPhy bit position */
|
||||
uint8_t idx; /* param array index */
|
||||
dmScanApiStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmScanApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_SCAN_MSG_API_START;
|
||||
pMsg->scanPhys = scanPhys;
|
||||
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
/* scan type for this PHY */
|
||||
pMsg->scanType[idx] = pScanType[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
pMsg->mode = mode;
|
||||
pMsg->duration = duration;
|
||||
pMsg->period = period;
|
||||
pMsg->filterDup = filterDup;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop scanning.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanStop(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_SCAN_MSG_API_STOP;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the scan interval and window.
|
||||
*
|
||||
* \param phyIdx The scanning PHY.
|
||||
* \param scanInterval The scan interval.
|
||||
* \param scanWindow The scan window.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmScanSetInterval(uint8_t scanPhy, uint16_t scanInterval, uint16_t scanWindow)
|
||||
{
|
||||
uint8_t phyIdx;
|
||||
|
||||
WSF_ASSERT((scanPhy == HCI_INIT_PHY_LE_1M_BIT) || (scanPhy == HCI_INIT_PHY_LE_CODED_BIT));
|
||||
|
||||
WsfTaskLock();
|
||||
phyIdx = DmScanPhyToIdx(scanPhy);
|
||||
dmScanCb.scanInterval[phyIdx] = scanInterval;
|
||||
dmScanCb.scanWindow[phyIdx] = scanWindow;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the scan interval and window for the specified PHYs.
|
||||
*
|
||||
* \param scanPhys Scanning PHYs.
|
||||
* \param pScanInterval Scan interval array.
|
||||
* \param pScanWindow Scan window array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanSetInterval(uint8_t scanPhys, uint16_t *pScanInterval, uint16_t *pScanWindow)
|
||||
{
|
||||
uint8_t i; /* scanPhy bit position */
|
||||
uint8_t idx; /* param array index */
|
||||
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
dmScanSetInterval((1 << i), pScanInterval[idx], pScanWindow[idx]);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used while scanning. This function can be used to
|
||||
* configure scanning to use a random address.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.scanAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM scan module.
|
||||
*
|
||||
* Copyright (c) 2016-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_SCAN_H
|
||||
#define DM_SCAN_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM scan event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_SCAN_MSG_API_START = DM_MSG_START(DM_ID_SCAN),
|
||||
DM_SCAN_MSG_API_STOP,
|
||||
DM_SCAN_MSG_TIMEOUT
|
||||
};
|
||||
|
||||
/* DM scan states */
|
||||
enum
|
||||
{
|
||||
DM_SCAN_STATE_IDLE,
|
||||
DM_SCAN_STATE_STARTING,
|
||||
DM_SCAN_STATE_SCANNING,
|
||||
DM_SCAN_STATE_STOPPING
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_SCAN_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t scanPhys;
|
||||
uint8_t scanType[DM_NUM_PHYS];
|
||||
uint8_t mode;
|
||||
uint16_t duration;
|
||||
uint16_t period;
|
||||
bool_t filterDup;
|
||||
} dmScanApiStart_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advSid;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint16_t skip;
|
||||
uint16_t syncTimeout;
|
||||
uint8_t unused;
|
||||
} dmSyncApiStart_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_ADD_DEV_TO_PER_ADV_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint8_t advSid;
|
||||
} dmSyncApiAddDevToPerAdvList_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_REM_DEV_FROM_PER_ADV_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint8_t advSid;
|
||||
} dmSyncApiRemDevFromPerAdvList_t;
|
||||
|
||||
/* Union of all scan messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmScanApiStart_t apiStart;
|
||||
} dmScanMsg_t;
|
||||
|
||||
/* Union of all DM Sync state machine messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmSyncApiStart_t apiSyncStart;
|
||||
hciLePerAdvSyncEstEvt_t perAdvSyncEst;
|
||||
hciLePerAdvSyncLostEvt_t perAdvSyncLost;
|
||||
HciLePerAdvSyncTrsfRcvdEvt_t perAdvSyncTrsfEst;
|
||||
} dmSyncMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmScanAct_t)(dmScanMsg_t *pMsg);
|
||||
|
||||
/* Control block for scan module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t scanTimer;
|
||||
uint16_t scanInterval[DM_NUM_PHYS];
|
||||
uint16_t scanWindow[DM_NUM_PHYS];
|
||||
bool_t scanState;
|
||||
uint16_t scanDuration;
|
||||
bool_t filterNextScanRsp;
|
||||
uint8_t discFilter;
|
||||
} dmScanCb_t;
|
||||
|
||||
/* Control block for periodic advertising sync module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t advSid; /*!< advertising SID */
|
||||
bdAddr_t advAddr; /*!< advertiser address */
|
||||
uint8_t advAddrType; /*!< advertiser address type */
|
||||
uint16_t handle; /*!< sync handle */
|
||||
dmSyncId_t syncId; /*!< sync id */
|
||||
uint8_t state; /*!< sync state */
|
||||
uint8_t inUse; /*!< TRUE if entry in use */
|
||||
} dmSyncCb_t;
|
||||
|
||||
/* Data structure for DM_PAST_MSG_API_SYNC_TRSF and DM_PAST_MSG_API_INFO_TRSF */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
uint16_t serviceData; /*!< Value provided by the Host */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmPastApiTrsf_t;
|
||||
|
||||
/* Data structure for DM_PAST_MSG_API_CONFIG and DM_PAST_MSG_API_DEFAULT_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
uint8_t mode; /*!< Mode */
|
||||
uint16_t skip; /*!< Skip */
|
||||
uint16_t syncTimeout; /*!< Sync timeout */
|
||||
uint8_t cteType; /*!< CTE type */
|
||||
} dmPastApiCfg_t;
|
||||
|
||||
/* Union of all DM PAST API messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmPastApiTrsf_t apiPastTrsf;
|
||||
dmPastApiCfg_t apiPastCfg;
|
||||
} dmPastMsg_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmPastAct_t)(dmPastMsg_t *pMsg);
|
||||
|
||||
extern dmScanCb_t dmScanCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* common scanning component inteface */
|
||||
void dmScanInit(void);
|
||||
|
||||
/* legacy scanning component inteface */
|
||||
void dmScanReset(void);
|
||||
void dmScanMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmScanHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* legacy scanning action functions */
|
||||
void dmScanActStart(dmScanMsg_t *pMsg);
|
||||
void dmScanActStop(dmScanMsg_t *pMsg);
|
||||
void dmScanActTimeout(dmScanMsg_t *pMsg);
|
||||
|
||||
/* extended scanning component inteface */
|
||||
void dmExtScanReset(void);
|
||||
void dmExtScanMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmExtScanHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* extended scanning action functions */
|
||||
void dmExtScanActStart(dmScanMsg_t *pMsg);
|
||||
void dmExtScanActStop(dmScanMsg_t *pMsg);
|
||||
void dmExtScanActTimeout(dmScanMsg_t *pMsg);
|
||||
|
||||
/* sync and sync transfer action functions */
|
||||
void dmSyncSmActNone(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActStop(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActCancelStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncLost(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncTrsfEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncTrsfEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
|
||||
/* sync component inteface */
|
||||
void dmSyncInit(void);
|
||||
void dmSyncReset(void);
|
||||
void dmSyncMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmSyncHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* past action functions */
|
||||
void dmPastActRptRcvEnable(dmPastMsg_t *pMsg);
|
||||
void dmPastActSyncTsfr(dmPastMsg_t *pMsg);
|
||||
void dmPastActSetInfoTrsf(dmPastMsg_t *pMsg);
|
||||
void dmPastActConfig(dmPastMsg_t *pMsg);
|
||||
void dmPastActDefaultConfig(dmPastMsg_t *pMsg);
|
||||
|
||||
/* past component inteface */
|
||||
void dmPastMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPastHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* sync utility functions */
|
||||
dmSyncCb_t *dmSyncCbById(dmSyncId_t syncId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_SCAN_H */
|
||||
Vendored
+362
@@ -0,0 +1,362 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager extended scan module.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* extended scan action function table */
|
||||
static const dmScanAct_t dmScanAct[] =
|
||||
{
|
||||
dmExtScanActStart,
|
||||
dmExtScanActStop,
|
||||
dmExtScanActTimeout
|
||||
};
|
||||
|
||||
/* extended scan component function interface */
|
||||
static const dmFcnIf_t dmScanFcnIf =
|
||||
{
|
||||
dmExtScanReset,
|
||||
dmExtScanHciHandler,
|
||||
dmExtScanMsgHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* event being reported used for a legacy advertising PDU or a scan response */
|
||||
#define DM_ADV_RPT_SCAN_RSP(evtType) ((((evtType) == HCI_ADV_RPT_LEG_CONN_UNDIRECT_SCAN_RSP) || \
|
||||
((evtType) == HCI_ADV_RPT_LEG_SCAN_UNDIRECT_SCAN_RSP)) || \
|
||||
((((evtType) & HCI_ADV_RPT_LEG_ADV_BIT) == 0) && \
|
||||
((evtType) & HCI_ADV_RPT_SCAN_RSP_BIT)))
|
||||
|
||||
/* data status field of extended advertising report event type */
|
||||
#define DM_ADV_RPT_DATA_STATUS(evtType) (((evtType) & HCI_ADV_RPT_DATA_STATUS_BITS) >> 5)
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start extended scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActStart(dmScanMsg_t *pMsg)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t idx;
|
||||
uint8_t phyIdx;
|
||||
hciExtScanParam_t scanParam[DM_NUM_PHYS];
|
||||
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_IDLE)
|
||||
{
|
||||
/* see advertising packets to be received on which PHY */
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (pMsg->apiStart.scanPhys & (1 << i))
|
||||
{
|
||||
phyIdx = DmScanPhyToIdx(1 << i);
|
||||
|
||||
/* set extended scan parameters for this PHY */
|
||||
scanParam[idx].scanType = pMsg->apiStart.scanType[idx];
|
||||
scanParam[idx].scanInterval = dmScanCb.scanInterval[phyIdx];
|
||||
scanParam[idx].scanWindow = dmScanCb.scanWindow[phyIdx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* set extended scan parameters to be used on primary advertising channel */
|
||||
HciLeSetExtScanParamCmd(DmLlAddrType(dmCb.scanAddrType), dmCb.scanFiltPolicy,
|
||||
pMsg->apiStart.scanPhys, scanParam);
|
||||
|
||||
/* initialize scan result filtering */
|
||||
if (pMsg->apiStart.mode == DM_DISC_MODE_LIMITED)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC;
|
||||
}
|
||||
else if (pMsg->apiStart.mode == DM_DISC_MODE_GENERAL)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC | DM_FLAG_LE_GENERAL_DISC;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmScanCb.discFilter = 0;
|
||||
}
|
||||
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
|
||||
/* enable scan */
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STARTING;
|
||||
HciLeExtScanEnableCmd(TRUE, pMsg->apiStart.filterDup, (pMsg->apiStart.duration / 10), pMsg->apiStart.period);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop extended scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActStop(dmScanMsg_t *pMsg)
|
||||
{
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* disable scan */
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STOPPING;
|
||||
HciLeExtScanEnableCmd(FALSE, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an scan timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActTimeout(dmScanMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an extended advertising report event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmExtScanActHciReport(hciEvt_t *pEvent)
|
||||
{
|
||||
uint8_t *p;
|
||||
static bool_t filtered = FALSE;
|
||||
static bool_t firstFrag = TRUE;
|
||||
|
||||
/* ignore if not scanning */
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* if filtering results for limited or general discovery, and first fragment */
|
||||
if ((dmScanCb.discFilter != 0) && firstFrag)
|
||||
{
|
||||
/* if this is a scan response */
|
||||
if (DM_ADV_RPT_SCAN_RSP(pEvent->leExtAdvReport.eventType))
|
||||
{
|
||||
/* check if filtering next scan response */
|
||||
if (dmScanCb.filterNextScanRsp)
|
||||
{
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
}
|
||||
}
|
||||
/* else it's an advertising response */
|
||||
else
|
||||
{
|
||||
/* find flags in advertising data */
|
||||
p = DmFindAdType(DM_ADV_TYPE_FLAGS, pEvent->leExtAdvReport.len, pEvent->leExtAdvReport.pData);
|
||||
if (p == NULL)
|
||||
{
|
||||
/* flags not found */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
/* else flags found; check them */
|
||||
else if ((p[DM_AD_DATA_IDX] & dmScanCb.discFilter) == 0)
|
||||
{
|
||||
/* flags do not match discovery mode */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
firstFrag = FALSE;
|
||||
}
|
||||
|
||||
if (!filtered)
|
||||
{
|
||||
pEvent->hdr.event = DM_EXT_SCAN_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/* if filtering results for limited or general discovery, and no more fragmented data to come */
|
||||
if ((dmScanCb.discFilter != 0) &&
|
||||
(DM_ADV_RPT_DATA_STATUS(pEvent->leExtAdvReport.eventType) != HCI_ADV_RPT_DATA_INCMPL_MORE))
|
||||
{
|
||||
/* reset our flags */
|
||||
filtered = FALSE;
|
||||
firstFrag = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM extended scan reset function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanReset(void)
|
||||
{
|
||||
hciLeScanTimeoutEvt_t scanTimeout;
|
||||
|
||||
/* if stopping scan or scanning */
|
||||
if ((dmScanCb.scanState == DM_SCAN_STATE_STOPPING) ||
|
||||
(dmScanCb.scanState == DM_SCAN_STATE_SCANNING))
|
||||
{
|
||||
/* generate HCI scan timeout event */
|
||||
scanTimeout.hdr.event = HCI_LE_SCAN_TIMEOUT_CBACK_EVT;
|
||||
scanTimeout.hdr.status = HCI_SUCCESS;
|
||||
|
||||
/* handle the event */
|
||||
dmExtScanHciHandler((hciEvt_t *) &scanTimeout);
|
||||
}
|
||||
|
||||
/* reset scan module */
|
||||
dmScanInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM extended scan HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
DM_TRACE_INFO2("dmExtScanHciHandler: event: %d state: %d", pEvent->hdr.event, dmScanCb.scanState);
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_EXT_ADV_REPORT_CBACK_EVT)
|
||||
{
|
||||
dmExtScanActHciReport(pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_SCAN_TIMEOUT_CBACK_EVT)
|
||||
{
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
|
||||
/* pass scanning stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_EXT_SCAN_STOP_IND, 0, 0);
|
||||
|
||||
/* call callback */
|
||||
pEvent->hdr.event = DM_EXT_SCAN_STOP_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_EXT_SCAN_ENABLE_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
switch (dmScanCb.scanState)
|
||||
{
|
||||
case DM_SCAN_STATE_STARTING:
|
||||
pEvent->hdr.event = DM_EXT_SCAN_START_IND;
|
||||
dmScanCb.scanState = pEvent->hdr.status == HCI_SUCCESS? DM_SCAN_STATE_SCANNING : DM_SCAN_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case DM_SCAN_STATE_STOPPING:
|
||||
pEvent->hdr.event = DM_EXT_SCAN_STOP_IND;
|
||||
dmScanCb.scanState = pEvent->hdr.status == HCI_SUCCESS? DM_SCAN_STATE_IDLE : DM_SCAN_STATE_SCANNING;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should never happen */
|
||||
WSF_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* pass scanning start/stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv((pEvent->hdr.event == DM_EXT_SCAN_START_IND) ? \
|
||||
DM_DEV_PRIV_MSG_RPA_START : DM_DEV_PRIV_MSG_RPA_STOP, pEvent->hdr.event,
|
||||
0, 0);
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *)pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM scan event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmScanAct[DM_MSG_MASK(pMsg->event)])((dmScanMsg_t *)pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM extended scanning.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtScanInit(void)
|
||||
{
|
||||
WsfTaskLock();
|
||||
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_SCAN] = (dmFcnIf_t *) &dmScanFcnIf;
|
||||
|
||||
/* initialize scan/sync modules */
|
||||
dmScanInit();
|
||||
dmSyncInit();
|
||||
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether DM scanning is in extended mode.
|
||||
*
|
||||
* \return TRUE if DM scanning is in extended mode. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmScanModeExt(void)
|
||||
{
|
||||
return (dmFcnIfTbl[DM_ID_SCAN] == (dmFcnIf_t *) &dmScanFcnIf) ? TRUE : FALSE;
|
||||
}
|
||||
Vendored
+336
@@ -0,0 +1,336 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager scan module.
|
||||
*
|
||||
* Copyright (c) 2016-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 "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmScanAct_t dmScanAct[] =
|
||||
{
|
||||
dmScanActStart,
|
||||
dmScanActStop,
|
||||
dmScanActTimeout
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmScanFcnIf =
|
||||
{
|
||||
dmScanReset,
|
||||
dmScanHciHandler,
|
||||
dmScanMsgHandler
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanActStart(dmScanMsg_t *pMsg)
|
||||
{
|
||||
uint8_t phyIdx = DmScanPhyToIdx(HCI_SCAN_PHY_LE_1M_BIT);
|
||||
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_IDLE)
|
||||
{
|
||||
/* set scan parameters */
|
||||
HciLeSetScanParamCmd(pMsg->apiStart.scanType[phyIdx], dmScanCb.scanInterval[phyIdx],
|
||||
dmScanCb.scanWindow[phyIdx], DmLlAddrType(dmCb.scanAddrType),
|
||||
dmCb.scanFiltPolicy);
|
||||
|
||||
/* initialize scan result filtering */
|
||||
if (pMsg->apiStart.mode == DM_DISC_MODE_LIMITED)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC;
|
||||
}
|
||||
else if (pMsg->apiStart.mode == DM_DISC_MODE_GENERAL)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC | DM_FLAG_LE_GENERAL_DISC;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmScanCb.discFilter = 0;
|
||||
}
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
|
||||
/* enable scan */
|
||||
dmScanCb.scanDuration = pMsg->apiStart.duration;
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STARTING;
|
||||
HciLeSetScanEnableCmd(TRUE, pMsg->apiStart.filterDup);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanActStop(dmScanMsg_t *pMsg)
|
||||
{
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* disable scan */
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STOPPING;
|
||||
HciLeSetScanEnableCmd(FALSE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an scan timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanActTimeout(dmScanMsg_t *pMsg)
|
||||
{
|
||||
dmScanActStop(pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an advertising report event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmScanActHciReport(hciEvt_t *pEvent)
|
||||
{
|
||||
uint8_t *p;
|
||||
bool_t filtered = FALSE;
|
||||
|
||||
/* ignore if not scanning */
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* if filtering results for limited or general discovery */
|
||||
if (dmScanCb.discFilter != 0)
|
||||
{
|
||||
/* if this is a scan response */
|
||||
if (pEvent->leAdvReport.eventType == DM_RPT_SCAN_RESPONSE)
|
||||
{
|
||||
/* check if filtering next scan response */
|
||||
if (dmScanCb.filterNextScanRsp)
|
||||
{
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
}
|
||||
}
|
||||
/* else it's an advertising response */
|
||||
else
|
||||
{
|
||||
/* find flags in advertising data */
|
||||
p = DmFindAdType(DM_ADV_TYPE_FLAGS, pEvent->leAdvReport.len, pEvent->leAdvReport.pData);
|
||||
if (p == NULL)
|
||||
{
|
||||
/* flags not found */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
/* else flags found; check them */
|
||||
else if ((p[DM_AD_DATA_IDX] & dmScanCb.discFilter) == 0)
|
||||
{
|
||||
/* flags do not match discovery mode */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!filtered)
|
||||
{
|
||||
pEvent->hdr.event = DM_SCAN_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the scan module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanReset(void)
|
||||
{
|
||||
wsfMsgHdr_t scanStop;
|
||||
|
||||
/* if stopping scan or scanning */
|
||||
if ((dmScanCb.scanState == DM_SCAN_STATE_STOPPING) ||
|
||||
(dmScanCb.scanState == DM_SCAN_STATE_SCANNING))
|
||||
{
|
||||
/* stop scan timer */
|
||||
WsfTimerStop(&dmScanCb.scanTimer);
|
||||
|
||||
/* generate scan stop event */
|
||||
scanStop.event = DM_SCAN_STOP_IND;
|
||||
scanStop.status = HCI_SUCCESS;
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) &scanStop);
|
||||
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
}
|
||||
|
||||
/* reset scan module */
|
||||
dmScanInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM scan HCI event handler.
|
||||
*
|
||||
* \param pEvent WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
if (pEvent->hdr.event == HCI_LE_ADV_REPORT_CBACK_EVT)
|
||||
{
|
||||
dmScanActHciReport(pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_SCAN_ENABLE_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
switch (dmScanCb.scanState)
|
||||
{
|
||||
case DM_SCAN_STATE_STARTING:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
/* start scan timer if applicable */
|
||||
if (dmScanCb.scanDuration > 0)
|
||||
{
|
||||
dmScanCb.scanTimer.msg.event = DM_SCAN_MSG_TIMEOUT;
|
||||
WsfTimerStartMs(&dmScanCb.scanTimer, dmScanCb.scanDuration);
|
||||
}
|
||||
|
||||
dmScanCb.scanState = DM_SCAN_STATE_SCANNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_SCAN_START_IND;
|
||||
break;
|
||||
|
||||
case DM_SCAN_STATE_STOPPING:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
/* stop scan timer */
|
||||
WsfTimerStop(&dmScanCb.scanTimer);
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmScanCb.scanState = DM_SCAN_STATE_SCANNING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_SCAN_STOP_IND;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Should never happen */
|
||||
WSF_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* pass scanning start/stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv((pEvent->hdr.event == DM_SCAN_START_IND) ? \
|
||||
DM_DEV_PRIV_MSG_RPA_START : DM_DEV_PRIV_MSG_RPA_STOP, pEvent->hdr.event,
|
||||
0, 0);
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM scan event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmScanAct[DM_MSG_MASK(pMsg->event)])((dmScanMsg_t *)pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM legacy scanning.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanInit(void)
|
||||
{
|
||||
WsfTaskLock();
|
||||
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_SCAN] = (dmFcnIf_t *) &dmScanFcnIf;
|
||||
|
||||
/* initialize scan module */
|
||||
dmScanInit();
|
||||
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether DM scanning is in legacy mode.
|
||||
*
|
||||
* \return TRUE if DM scanning is in legacy mode. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmScanModeLeg(void)
|
||||
{
|
||||
return (dmFcnIfTbl[DM_ID_SCAN] == (dmFcnIf_t *) &dmScanFcnIf) ? TRUE : FALSE;
|
||||
}
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM security module.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/calc128.h"
|
||||
#include "smp_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_sec.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
dmSecCb_t dmSecCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmSecFcnIf =
|
||||
{
|
||||
dmSecReset,
|
||||
dmSecHciHandler,
|
||||
(dmMsgHandler_t) dmSecMsgHandler
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Utility function for API encrypt request or ltk response.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param status HCI_SUCCESS if LTK available.
|
||||
* \param *pLTK Pointer to LTK parameter structure.
|
||||
* \param event DM handler event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSecApiLtkMsg(dmConnId_t connId, uint8_t status, dmSecLtk_t *pLtk, uint8_t event)
|
||||
{
|
||||
dmSecApiEncryptReq_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmSecApiEncryptReq_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = event;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->hdr.status = status;
|
||||
memcpy(&pMsg->ltk, pLtk, sizeof(dmSecLtk_t));
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSecHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
uint8_t *pKey;
|
||||
dmSecEncryptIndEvt_t encryptInd;
|
||||
uint8_t secLevel;
|
||||
|
||||
if ((pCcb = dmConnCcbByHandle(pEvent->hdr.param)) != NULL)
|
||||
{
|
||||
if (pEvent->hdr.event == HCI_LE_LTK_REQ_CBACK_EVT)
|
||||
{
|
||||
/* if ediv and rand are zero then check if STK is available from SMP */
|
||||
if ((pEvent->leLtkReq.encDiversifier == 0) &&
|
||||
(memcmp(pEvent->leLtkReq.randNum, calc128Zeros, HCI_RAND_LEN) == 0))
|
||||
{
|
||||
if ((pKey = SmpDmGetStk(pCcb->connId, &secLevel)) != NULL)
|
||||
{
|
||||
/* store security level */
|
||||
pCcb->tmpSecLevel = secLevel;
|
||||
|
||||
/* not using LTK */
|
||||
pCcb->usingLtk = FALSE;
|
||||
|
||||
/* provide key to HCI */
|
||||
HciLeLtkReqReplCmd(pEvent->hdr.param, pKey);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* call callback to get key from app */
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_DM_ENC, DM_CONN_BUSY);
|
||||
|
||||
/* using LTK */
|
||||
pCcb->usingLtk = TRUE;
|
||||
|
||||
/* use the header from the encryptInd struct for efficiency */
|
||||
pEvent->hdr.param = pCcb->connId;
|
||||
pEvent->hdr.event = DM_SEC_LTK_REQ_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_ENC_KEY_REFRESH_CMPL_CBACK_EVT ||
|
||||
pEvent->hdr.event == HCI_ENC_CHANGE_CBACK_EVT)
|
||||
{
|
||||
/* set connection idle */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_DM_ENC, DM_CONN_IDLE);
|
||||
|
||||
encryptInd.hdr.param = pCcb->connId;
|
||||
encryptInd.hdr.status = pEvent->hdr.status;
|
||||
if (encryptInd.hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
encryptInd.hdr.event = DM_SEC_ENCRYPT_IND;
|
||||
|
||||
/* update security level of connection */
|
||||
pCcb->secLevel = pCcb->tmpSecLevel;
|
||||
|
||||
/* set LTK flag */
|
||||
encryptInd.usingLtk = pCcb->usingLtk;
|
||||
}
|
||||
else
|
||||
{
|
||||
encryptInd.hdr.event = DM_SEC_ENCRYPT_FAIL_IND;
|
||||
}
|
||||
|
||||
/* call callback before passing to SMP */
|
||||
DmSmpCbackExec((dmEvt_t *) &encryptInd);
|
||||
|
||||
/* pass to SMP */
|
||||
encryptInd.hdr.param = pCcb->connId;
|
||||
encryptInd.hdr.status = pEvent->hdr.status;
|
||||
SmpDmEncryptInd((wsfMsgHdr_t *) &encryptInd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSecMsgHandler(dmSecMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb */
|
||||
if ((pCcb = dmConnCcbById((dmConnId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
/* process API encrypt req */
|
||||
switch (pMsg->hdr.event)
|
||||
{
|
||||
case DM_SEC_MSG_API_ENCRYPT_REQ:
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_DM_ENC, DM_CONN_BUSY);
|
||||
|
||||
/* store security level */
|
||||
pCcb->tmpSecLevel = pMsg->encryptReq.secLevel;
|
||||
|
||||
/* using LTK */
|
||||
pCcb->usingLtk = TRUE;
|
||||
|
||||
/* start encryption */
|
||||
HciLeStartEncryptionCmd(pCcb->handle, pMsg->encryptReq.ltk.rand,
|
||||
pMsg->encryptReq.ltk.ediv, pMsg->encryptReq.ltk.key);
|
||||
|
||||
break;
|
||||
|
||||
case DM_SEC_MSG_API_LTK_RSP:
|
||||
/* if key found */
|
||||
if (pMsg->ltkRsp.keyFound)
|
||||
{
|
||||
/* store security level */
|
||||
pCcb->tmpSecLevel = pMsg->ltkRsp.secLevel;
|
||||
|
||||
/* provide key to HCI */
|
||||
HciLeLtkReqReplCmd(pCcb->handle, pMsg->ltkRsp.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* key not found; set connection idle */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_DM_ENC, DM_CONN_IDLE);
|
||||
|
||||
HciLeLtkReqNegReplCmd(pCcb->handle);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. Execute DM callback from SMP procedures.
|
||||
*
|
||||
* \param pDmEvt Pointer to callback event data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSmpCbackExec(dmEvt_t *pDmEvt)
|
||||
{
|
||||
/* certain messages need to get to ATT */
|
||||
if (pDmEvt->hdr.event == DM_SEC_PAIR_CMPL_IND ||
|
||||
pDmEvt->hdr.event == DM_SEC_ENCRYPT_IND)
|
||||
{
|
||||
if (dmConnCb.connCback[DM_CLIENT_ID_ATT] != NULL)
|
||||
{
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_ATT])(pDmEvt);
|
||||
}
|
||||
}
|
||||
|
||||
/* execute DM client callback */
|
||||
(*dmCb.cback)(pDmEvt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called to cancel the pairing process.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param reason Failure reason.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecCancelReq(dmConnId_t connId, uint8_t reason)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = SMP_MSG_API_CANCEL_REQ;
|
||||
pMsg->param = connId;
|
||||
pMsg->status = reason;
|
||||
|
||||
/* note we're sending this to SMP */
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called in response to a DM_SEC_AUTH_REQ_IND event to provide
|
||||
* PIN or OOB data during pairing.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param authDataLen Length of PIN or OOB data.
|
||||
* \param pAuthData pointer to PIN or OOB data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecAuthRsp(dmConnId_t connId, uint8_t authDataLen, uint8_t *pAuthData)
|
||||
{
|
||||
smpDmAuthRsp_t *pMsg;
|
||||
|
||||
WSF_ASSERT(authDataLen <= SMP_OOB_LEN);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmAuthRsp_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = SMP_MSG_API_AUTH_RSP;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->authDataLen = authDataLen;
|
||||
|
||||
if (pAuthData != NULL)
|
||||
{
|
||||
memcpy(pMsg->authData, pAuthData, authDataLen);
|
||||
}
|
||||
|
||||
/* note we're sending this to SMP */
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM security.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_SEC] = (dmFcnIf_t *) &dmSecFcnIf;
|
||||
|
||||
dmSecCb.pCsrk = dmSecCb.pIrk = (uint8_t *) calc128Zeros;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function sets the local CSRK used by the device.
|
||||
*
|
||||
* \param pCsrk Pointer to CSRK.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSetLocalCsrk(uint8_t *pCsrk)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmSecCb.pCsrk = pCsrk;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function sets the local IRK used by the device.
|
||||
*
|
||||
* \param pCsrk Pointer to IRK.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSetLocalIrk(uint8_t *pIrk)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmSecCb.pIrk = pIrk;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function gets the local CSRK used by the device.
|
||||
*
|
||||
* \return Pointer to CSRK.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *DmSecGetLocalCsrk(void)
|
||||
{
|
||||
return dmSecCb.pCsrk;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function gets the local IRK used by the device.
|
||||
*
|
||||
* \return Pointer to IRK.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *DmSecGetLocalIrk(void)
|
||||
{
|
||||
return dmSecCb.pIrk;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the sec module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSecReset(void)
|
||||
{
|
||||
/* initialize smp database */
|
||||
SmpDbInit();
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM security module.
|
||||
*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_SEC_H
|
||||
#define DM_SEC_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
#include "smp_api.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM sec event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_SEC_MSG_API_ENCRYPT_REQ = DM_MSG_START(DM_ID_SEC),
|
||||
DM_SEC_MSG_API_LTK_RSP
|
||||
};
|
||||
|
||||
/* DM lesc sec event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_SEC_MSG_CALC_OOB_CNF = DM_MSG_START(DM_ID_LESC),
|
||||
DM_SEC_MSG_ECC_KEY_CNF
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data type for DM_SEC_MSG_API_ENCRYPT_REQ */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmSecLtk_t ltk;
|
||||
uint8_t secLevel;
|
||||
} dmSecApiEncryptReq_t;
|
||||
|
||||
/* Data type for DM_SEC_MSG_API_LTK_RSP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t key[SMP_KEY_LEN];
|
||||
bool_t keyFound;
|
||||
uint8_t secLevel;
|
||||
} dmSecApiLtkRsp_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmSecApiEncryptReq_t encryptReq;
|
||||
dmSecApiLtkRsp_t ltkRsp;
|
||||
} dmSecMsg_t;
|
||||
|
||||
/* Security control block type */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *pIrk;
|
||||
uint8_t *pCsrk;
|
||||
} dmSecCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
extern dmSecCb_t dmSecCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* component interface */
|
||||
void dmSecHciHandler(hciEvt_t *pEvent);
|
||||
void dmSecMsgHandler(dmSecMsg_t *pMsg);
|
||||
void dmSecReset(void);
|
||||
|
||||
/* component interface */
|
||||
void dmSecLescMsgHandler(dmSecMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_SEC_H */
|
||||
Vendored
+328
@@ -0,0 +1,328 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM security module for LE Secure Connections.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/calc128.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_sc_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_sec.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmSecLescFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
(dmHciHandler_t) dmEmptyHandler,
|
||||
(dmMsgHandler_t) dmSecLescMsgHandler
|
||||
};
|
||||
|
||||
/* OOB random value */
|
||||
static uint8_t *dmSecOobRand;
|
||||
|
||||
/* Local device's ECC Key */
|
||||
static secEccKey_t localEccKey;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSecLescMsgHandler(dmSecMsg_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.event == DM_SEC_MSG_ECC_KEY_CNF)
|
||||
{
|
||||
pMsg->hdr.event = DM_SEC_ECC_KEY_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
else if (pMsg->hdr.event == DM_SEC_MSG_CALC_OOB_CNF)
|
||||
{
|
||||
dmSecOobCalcIndEvt_t oobEvt;
|
||||
secCmacMsg_t *pCmacMsg = (secCmacMsg_t *) pMsg;
|
||||
|
||||
WsfBufFree(pCmacMsg->pPlainText);
|
||||
|
||||
/* Notify the application of the local confirm and random values */
|
||||
oobEvt.hdr.event = DM_SEC_CALC_OOB_IND;
|
||||
oobEvt.hdr.status = HCI_SUCCESS;
|
||||
|
||||
Calc128Cpy(oobEvt.confirm, ((secAes_t *) pMsg)->pCiphertext);
|
||||
Calc128Cpy(oobEvt.random, dmSecOobRand);
|
||||
|
||||
WsfBufFree(dmSecOobRand);
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) &oobEvt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function sends keypress cmd messages to the peer.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecKeypressReq(dmConnId_t connId, uint8_t keypressType)
|
||||
{
|
||||
smpDmKeypress_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmKeypress_t))) != NULL)
|
||||
{
|
||||
/* Execution an an SMP state machine event to send the keypress to the peer device */
|
||||
pMsg->keypress = keypressType;
|
||||
pMsg->hdr.param = connId;
|
||||
|
||||
pMsg->hdr.event = SMP_MSG_API_USER_KEYPRESS;
|
||||
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function records the peer random value and peer confirm value exchanged via
|
||||
* out-of-band (OOB) methods.
|
||||
*
|
||||
* \param connId ID of the connection
|
||||
* \param pCfg OOB Configuration
|
||||
*
|
||||
* \return Pointer to IRK.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSetOob(dmConnId_t connId, dmSecLescOobCfg_t *pCfg)
|
||||
{
|
||||
/* Update the Security Manager control structure with random and confirm values from the peer */
|
||||
SmpScSetOobCfg(connId, pCfg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function calcualtes the local random and confirm values used in LESC OOB pairing.
|
||||
* The operation's result is posted as a DM_SEC_CALC_OOB_IND event to the application's DM
|
||||
* callback handler. The local rand and confirm values are exchanged with the peer via
|
||||
* out-of-band (OOB) methods and passed into the DmSecSetOob after DM_CONN_OPEN_IND.
|
||||
*
|
||||
* \param pRand Random value used in calculation.
|
||||
* \param pPubKeyX X component of the local public key.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecCalcOobReq(uint8_t *pRand, uint8_t *pPubKeyX)
|
||||
{
|
||||
uint8_t *pCmacText;
|
||||
dmSecOobCalcIndEvt_t pEvt;
|
||||
|
||||
SMP_TRACE_256("DmSecCalcOobReq Key", pPubKeyX);
|
||||
SMP_TRACE_128("DmSecCalcOobReq Rand", pRand);
|
||||
|
||||
if ((dmSecOobRand = WsfBufAlloc(SMP_RAND_LEN)) != NULL)
|
||||
{
|
||||
/* Store the random value */
|
||||
Calc128Cpy(dmSecOobRand, pRand);
|
||||
|
||||
/* Cnf = f4(PKx, PKx, rand, 0x00) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
if ((pCmacText = (uint8_t*) WsfBufAlloc(SMP_F4_TEXT_LEN)) != NULL)
|
||||
{
|
||||
uint8_t *pCatBuf = pCmacText;
|
||||
|
||||
/* Concatinate PKx, PKx, 0x00 */
|
||||
pCatBuf = SmpScCat(pCatBuf, pPubKeyX, SMP_PUB_KEY_LEN);
|
||||
pCatBuf = SmpScCat(pCatBuf, pPubKeyX, SMP_PUB_KEY_LEN);
|
||||
*pCatBuf = 0;
|
||||
|
||||
/* Execute CMAC with rand as the key */
|
||||
if (SecCmac(dmSecOobRand, pCmacText, SMP_F4_TEXT_LEN, dmCb.handlerId, 0, DM_SEC_MSG_CALC_OOB_CNF))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WsfBufFree(pCmacText);
|
||||
}
|
||||
|
||||
WsfBufFree(dmSecOobRand);
|
||||
}
|
||||
|
||||
/* Notify the application of a failure */
|
||||
memset(&pEvt, 0, sizeof(dmSecOobCalcIndEvt_t));
|
||||
|
||||
pEvt.hdr.event = DM_SEC_CALC_OOB_IND;
|
||||
pEvt.hdr.status = HCI_ERR_MEMORY_EXCEEDED;
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) &pEvt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function generates an ECC key for use with LESC security. When the calculation
|
||||
* completes, the result is posted as a DM_SEC_ECC_KEY_IND event to the application's
|
||||
* DM callback handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecGenerateEccKeyReq()
|
||||
{
|
||||
SecEccGenKey(dmCb.handlerId, 0, DM_SEC_MSG_ECC_KEY_CNF);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function sets the ECC key for use with LESC security to standard debug keys values.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSetDebugEccKey()
|
||||
{
|
||||
const uint8_t privateKey[] = {0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38,
|
||||
0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
|
||||
0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99,
|
||||
0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd};
|
||||
|
||||
const uint8_t publicKeyX[] = {0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
|
||||
0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
|
||||
0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
|
||||
0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
|
||||
|
||||
const uint8_t publicKeyY[] = {0xdc, 0x80, 0x9c, 0x49, 0x65, 0x2a, 0xeb, 0x6d,
|
||||
0x63, 0x32, 0x9a, 0xbf, 0x5a, 0x52, 0x15, 0x5c,
|
||||
0x76, 0x63, 0x45, 0xc2, 0x8f, 0xed, 0x30, 0x24,
|
||||
0x74, 0x1c, 0x8e, 0xd0, 0x15, 0x89, 0xd2, 0x8b};
|
||||
|
||||
SMP_TRACE_INFO0("Debug LESC Keys Enabled");
|
||||
|
||||
memcpy(localEccKey.privKey, privateKey, SEC_ECC_KEY_LEN);
|
||||
memcpy(localEccKey.pubKey_x, publicKeyX, SEC_ECC_KEY_LEN);
|
||||
memcpy(localEccKey.pubKey_y, publicKeyY, SEC_ECC_KEY_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function sets the local ECC key for use with LESC security. The key can be
|
||||
* generated using DmSecGenerateEccKeyReq or the key could originate from an application
|
||||
* specific source (e.g. prestored in non-volatile memory, generated with specialized
|
||||
* hardware, etc).
|
||||
*
|
||||
* \param pKey Pointer to local ECC key
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSetEccKey(secEccKey_t *pKey)
|
||||
{
|
||||
memcpy(&localEccKey, pKey, sizeof(secEccKey_t));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function gets the local ECC key for use with LESC security.
|
||||
*
|
||||
* \return Pointer to local ECC key.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
secEccKey_t *DmSecGetEccKey(void)
|
||||
{
|
||||
return &localEccKey;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application in response to a DM_SEC_COMPARE_IND event.
|
||||
* The valid parameter indicates if the compare value of the DM_SEC_COMPARE_IND was valid.
|
||||
*
|
||||
* \param connId ID of the connection
|
||||
* \param valid TRUE if compare value was valid
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecCompareRsp(dmConnId_t connId, bool_t valid)
|
||||
{
|
||||
smpDmMsg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmMsg_t))) != NULL)
|
||||
{
|
||||
/* Execution an an SMP state machine event to send the compare response */
|
||||
pMsg->hdr.param = connId;
|
||||
|
||||
if (valid)
|
||||
{
|
||||
pMsg->hdr.event = SMP_MSG_API_USER_CONFIRM;
|
||||
}
|
||||
else
|
||||
{
|
||||
SmpScGetCancelMsgWithReattempt(connId, (wsfMsgHdr_t *) pMsg, SMP_ERR_NUMERIC_COMPARISON);
|
||||
}
|
||||
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function returns the 6-digit compare value for the specified 128-bit confirm value.
|
||||
*
|
||||
* \param pConfirm Pointer to 128-bit comfirm value.
|
||||
*
|
||||
* \return Six-digit compare value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t DmSecGetCompareValue(uint8_t *pConfirm)
|
||||
{
|
||||
uint32_t compare = ((uint32_t) pConfirm[15] +
|
||||
((uint32_t) pConfirm[14] << 8) +
|
||||
((uint32_t) pConfirm[13] << 16) +
|
||||
((uint32_t) pConfirm[12] << 24));
|
||||
|
||||
/* return the least significant six digits */
|
||||
return compare % 1000000;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM LE Secure Connections security.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecLescInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_LESC] = (dmFcnIf_t *) &dmSecLescFcnIf;
|
||||
}
|
||||
Vendored
+121
@@ -0,0 +1,121 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM security module for master.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/calc128.h"
|
||||
#include "smp_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_sec.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. This function is called by SMP to request encryption.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param secLevel Security level of pairing when key was exchanged.
|
||||
* \param pKey Pointer to key.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSmpEncryptReq(dmConnId_t connId, uint8_t secLevel, uint8_t *pKey)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if ((pCcb = dmConnCcbById(connId)) != NULL)
|
||||
{
|
||||
/* store security level */
|
||||
pCcb->tmpSecLevel = secLevel;
|
||||
|
||||
/* not using LTK */
|
||||
pCcb->usingLtk = FALSE;
|
||||
|
||||
/* start encryption; note EDIV and RAND are zero */
|
||||
HciLeStartEncryptionCmd(pCcb->handle, (uint8_t *) calc128Zeros, 0, pKey);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by a master device to initiate pairing.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param oob Out-of-band pairing data present or not present.
|
||||
* \param auth Authentication and bonding flags.
|
||||
* \param iKeyDist Initiator key distribution flags.
|
||||
* \param rKeyDist Responder key distribution flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecPairReq(dmConnId_t connId, uint8_t oob, uint8_t auth, uint8_t iKeyDist, uint8_t rKeyDist)
|
||||
{
|
||||
smpDmPair_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmPair_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = SMP_MSG_API_PAIR_REQ;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->oob = oob;
|
||||
pMsg->auth = auth;
|
||||
|
||||
/* clear any erroneous key dist bits set by app */
|
||||
pMsg->iKeyDist = iKeyDist & SMP_KEY_DIST_MASK;
|
||||
pMsg->rKeyDist = rKeyDist & SMP_KEY_DIST_MASK;
|
||||
|
||||
/* note we're sending this to SMP */
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by a master device to initiate link encryption.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param secLevel Security level of pairing when key was exchanged.
|
||||
* \param pLtk Pointer to LTK parameter structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecEncryptReq(dmConnId_t connId, uint8_t secLevel, dmSecLtk_t *pLtk)
|
||||
{
|
||||
dmSecApiEncryptReq_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmSecApiEncryptReq_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_SEC_MSG_API_ENCRYPT_REQ;
|
||||
pMsg->hdr.param = connId;
|
||||
memcpy(&pMsg->ltk, pLtk, sizeof(dmSecLtk_t));
|
||||
pMsg->secLevel = secLevel;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+122
@@ -0,0 +1,122 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM security module for slave.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/calc128.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_sec.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by a slave device to proceed with pairing after a
|
||||
* DM_SEC_PAIR_IND event is received.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param oob Out-of-band pairing data present or not present.
|
||||
* \param auth Authentication and bonding flags.
|
||||
* \param iKeyDist Initiator key distribution flags.
|
||||
* \param rKeyDist Responder key distribution flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecPairRsp(dmConnId_t connId, uint8_t oob, uint8_t auth, uint8_t iKeyDist, uint8_t rKeyDist)
|
||||
{
|
||||
smpDmPair_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmPair_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = SMP_MSG_API_PAIR_RSP;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->oob = oob;
|
||||
pMsg->auth = auth;
|
||||
|
||||
/* clear any erroneous key dist bits set by app */
|
||||
pMsg->iKeyDist = iKeyDist & SMP_KEY_DIST_MASK;
|
||||
pMsg->rKeyDist = rKeyDist & SMP_KEY_DIST_MASK;
|
||||
|
||||
/* note we're sending this to SMP */
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by a slave device to request that the master initiates
|
||||
* pairing or link encryption.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param auth Authentication flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecSlaveReq(dmConnId_t connId, uint8_t auth)
|
||||
{
|
||||
smpDmSecurityReq_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(smpDmSecurityReq_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = SMP_MSG_API_SECURITY_REQ;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->auth = auth;
|
||||
|
||||
/* note we're sending this to SMP */
|
||||
SmpDmMsgSend((smpDmMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by a slave in response to a DM_SEC_LTK_REQ_IND event
|
||||
* to provide the key used for encryption.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param keyFound TRUE if key found.
|
||||
* \param secLevel Security level of pairing when key was exchanged.
|
||||
* \param *pKey Pointer to the key, if found.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSecLtkRsp(dmConnId_t connId, bool_t keyFound, uint8_t secLevel, uint8_t *pKey)
|
||||
{
|
||||
dmSecApiLtkRsp_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmSecApiLtkRsp_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_SEC_MSG_API_LTK_RSP;
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->keyFound = keyFound;
|
||||
pMsg->secLevel = secLevel;
|
||||
if (keyFound)
|
||||
{
|
||||
Calc128Cpy(pMsg->key, pKey);
|
||||
}
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
Vendored
+835
@@ -0,0 +1,835 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager periodic advertising synchronization management and state machine
|
||||
* module.
|
||||
*
|
||||
* Copyright (c) 2016-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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_scan.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM sync event handler messages for state machine */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_SYNC_MSG_API_START = DM_MSG_START(DM_ID_SYNC), /*!< Start Sync */
|
||||
DM_SYNC_MSG_API_STOP, /*!< Stop Sync */
|
||||
|
||||
/* messages from HCI */
|
||||
DM_SYNC_MSG_HCI_LE_SYNC_EST_FAIL, /*!< HCI LE Sync Establishment Failed */
|
||||
DM_SYNC_MSG_HCI_LE_SYNC_EST, /*!< HCI LE Sync Established */
|
||||
DM_SYNC_MSG_HCI_LE_SYNC_LOST, /*!< HCI LE Sync Lost */
|
||||
DM_SYNC_MSG_HCI_LE_SYNC_TRSF_EST_FAIL, /*!< HCI LE Sync Transfer Establishment Failed */
|
||||
DM_SYNC_MSG_HCI_LE_SYNC_TRSF_EST /*!< HCI LE Sync Transfer Established */
|
||||
};
|
||||
|
||||
/*! State machine states */
|
||||
enum
|
||||
{
|
||||
DM_SYNC_SM_ST_IDLE, /*!< Idle State */
|
||||
DM_SYNC_SM_ST_SYNCING, /*!< Synchronizing State */
|
||||
DM_SYNC_SM_ST_SYNCED, /*!< Synced State */
|
||||
DM_SYNC_SM_ST_DESYNCING, /*!< Desynchronizing State */
|
||||
|
||||
DM_SYNC_SM_NUM_STATES
|
||||
};
|
||||
|
||||
/*! State machine actions */
|
||||
enum
|
||||
{
|
||||
DM_SYNC_SM_ACT_NONE, /*!< No Action */
|
||||
DM_SYNC_SM_ACT_START, /*!< Process Start Sync */
|
||||
DM_SYNC_SM_ACT_STOP, /*!< Process Stop Sync */
|
||||
DM_SYNC_SM_ACT_CANCEL_START, /*!< Process Cancel Start Sync */
|
||||
DM_SYNC_SM_ACT_SYNC_EST, /*!< Process Sync Established */
|
||||
DM_SYNC_SM_ACT_SYNC_EST_FAILED, /*!< Process Sync Establishment Failed */
|
||||
DM_SYNC_SM_ACT_SYNC_LOST, /*!< Process Sync Lost */
|
||||
DM_SYNC_SM_ACT_SYNC_TRSF_EST, /*!< Process Sync Transfer Established */
|
||||
DM_SYNC_SM_ACT_SYNC_TRSF_EST_FAILED /*!< Process Sync Transfer Establishment Failed */
|
||||
};
|
||||
|
||||
/*! Column position of next state */
|
||||
#define DM_SYNC_NEXT_STATE 0
|
||||
|
||||
/*! Column position of action */
|
||||
#define DM_SYNC_ACTION 1
|
||||
|
||||
/*! Number of columns in the state machine state tables */
|
||||
#define DM_SYNC_NUM_COLS 2
|
||||
|
||||
/*! Number of messages */
|
||||
#define DM_SYNC_NUM_MSGS (DM_SYNC_MSG_HCI_LE_SYNC_TRSF_EST - DM_SYNC_MSG_API_START + 1)
|
||||
|
||||
/*! Translate HCI event to state machine message */
|
||||
#define DM_SYNC_HCI_EVT_2_MSG(evt) (DM_SYNC_MSG_HCI_LE_SYNC_LOST - HCI_LE_PER_ADV_SYNC_LOST_CBACK_EVT + (evt))
|
||||
|
||||
/*! Uninitialized HCI sync handle */
|
||||
#define DM_SYNC_HCI_HANDLE_NONE 0xFFFF
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmSyncAct_t)(dmSyncCb_t *pCcb, dmSyncMsg_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM Sync state machine state tables */
|
||||
static const uint8_t dmSyncStateTbl[DM_SYNC_SM_NUM_STATES][DM_SYNC_NUM_MSGS][DM_SYNC_NUM_COLS] =
|
||||
{
|
||||
/* Idle state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_START */ {DM_SYNC_SM_ST_SYNCING, DM_SYNC_SM_ACT_START},
|
||||
/* API_STOP */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_EST */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_LOST */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_TRSF_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_TRSF_EST_FAILED},
|
||||
/* HCI_LE_SYNC_TRSF_EST */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_SYNC_TRSF_EST}
|
||||
},
|
||||
/* Syncing state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_START */ {DM_SYNC_SM_ST_SYNCING, DM_SYNC_SM_ACT_NONE},
|
||||
/* API_STOP */ {DM_SYNC_SM_ST_DESYNCING, DM_SYNC_SM_ACT_CANCEL_START},
|
||||
/* HCI_LE_SYNC_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_EST_FAILED},
|
||||
/* HCI_LE_SYNC_EST */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_SYNC_EST},
|
||||
/* HCI_LE_SYNC_LOST */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_EST_FAILED},
|
||||
/* HCI_LE_SYNC_TRSF_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_TRSF_EST_FAILED},
|
||||
/* HCI_LE_SYNC_TRSF_EST */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_SYNC_TRSF_EST},
|
||||
},
|
||||
/* Synced state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_START */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_NONE},
|
||||
/* API_STOP */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_STOP},
|
||||
/* HCI_LE_SYNC_EST_FAIL */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_EST */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_LOST */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_LOST},
|
||||
/* HCI_LE_SYNC_TRSF_EST_FAIL */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_TRSF_EST */ {DM_SYNC_SM_ST_SYNCED, DM_SYNC_SM_ACT_NONE},
|
||||
},
|
||||
/* Desyncing state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_START */ {DM_SYNC_SM_ST_DESYNCING, DM_SYNC_SM_ACT_NONE},
|
||||
/* API_STOP */ {DM_SYNC_SM_ST_DESYNCING, DM_SYNC_SM_ACT_NONE},
|
||||
/* HCI_LE_SYNC_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_EST_FAILED},
|
||||
/* HCI_LE_SYNC_EST */ {DM_SYNC_SM_ST_DESYNCING, DM_SYNC_SM_ACT_STOP},
|
||||
/* HCI_LE_SYNC_LOST */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_LOST},
|
||||
/* HCI_LE_SYNC_TRSF_EST_FAIL */ {DM_SYNC_SM_ST_IDLE, DM_SYNC_SM_ACT_SYNC_TRSF_EST_FAILED},
|
||||
/* HCI_LE_SYNC_TRSF_EST */ {DM_SYNC_SM_ST_DESYNCING, DM_SYNC_SM_ACT_STOP},
|
||||
}
|
||||
};
|
||||
|
||||
/*! DM Sync action function table */
|
||||
static const dmSyncAct_t dmSyncAct[] =
|
||||
{
|
||||
dmSyncSmActNone,
|
||||
dmSyncSmActStart,
|
||||
dmSyncSmActStop,
|
||||
dmSyncSmActCancelStart,
|
||||
dmSyncSmActSyncEst,
|
||||
dmSyncSmActSyncEstFailed,
|
||||
dmSyncSmActSyncLost,
|
||||
dmSyncSmActSyncTrsfEst,
|
||||
dmSyncSmActSyncTrsfEstFailed
|
||||
};
|
||||
|
||||
/*! DM Sync component function interface */
|
||||
static const dmFcnIf_t dmSyncFcnIf =
|
||||
{
|
||||
dmSyncReset,
|
||||
dmSyncHciHandler,
|
||||
dmSyncMsgHandler
|
||||
};
|
||||
|
||||
/*! DM Periodic advertising sync control block */
|
||||
static dmSyncCb_t dmSyncCb[DM_SYNC_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the SCB with particular state conditions.
|
||||
*
|
||||
* \return Pointer to SCB or NULL if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static dmSyncCb_t *dmSyncCmplState(void)
|
||||
{
|
||||
dmSyncCb_t *pScb = dmSyncCb;
|
||||
uint8_t i;
|
||||
|
||||
/* if there's a scb in accepting state */
|
||||
for (i = DM_SYNC_MAX; i > 0; i--, pScb++)
|
||||
{
|
||||
/* look for sync in desyncing state, cancelled sync */
|
||||
if (pScb->inUse &&
|
||||
(pScb->state == DM_SYNC_SM_ST_DESYNCING) &&
|
||||
(pScb->handle == DM_SYNC_HCI_HANDLE_NONE))
|
||||
{
|
||||
DM_TRACE_INFO1("dmSyncCmplState %d", pScb->syncId);
|
||||
return pScb;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate a DM sync control block.
|
||||
*
|
||||
* \param sid Advertising Sid.
|
||||
* \param pAddr Advertiser BD address.
|
||||
*
|
||||
* \return Pointer to sync CB or NULL if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static dmSyncCb_t *dmSyncCbAlloc(uint8_t sid, const uint8_t *pAddr)
|
||||
{
|
||||
dmSyncCb_t *pScb = dmSyncCb;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_SYNC_MAX; i++, pScb++)
|
||||
{
|
||||
if (pScb->inUse == FALSE)
|
||||
{
|
||||
memset(pScb, 0, sizeof(dmSyncCb_t));
|
||||
|
||||
pScb->advSid = sid;
|
||||
BdaCpy(pScb->advAddr, pAddr);
|
||||
pScb->handle = DM_SYNC_HCI_HANDLE_NONE;
|
||||
pScb->syncId = i + 1;
|
||||
pScb->inUse = TRUE;
|
||||
|
||||
DM_TRACE_ALLOC1("dmSyncCbAlloc %d", pScb->syncId);
|
||||
|
||||
return pScb;
|
||||
}
|
||||
}
|
||||
|
||||
DM_TRACE_ERR0("dmSyncCbAlloc failed");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Deallocate a DM sync control block.
|
||||
*
|
||||
* \param pCb Sync control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmSyncCbDealloc(dmSyncCb_t *pCb)
|
||||
{
|
||||
DM_TRACE_FREE1("dmSyncCbDealloc %d", pCb->syncId);
|
||||
|
||||
pCb->inUse = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find a sync control block with matching handle.
|
||||
*
|
||||
* \param handle Handle to find.
|
||||
*
|
||||
* \return Pointer to sync CB or NULL if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static dmSyncCb_t *dmSyncCbByHandle(uint16_t handle)
|
||||
{
|
||||
dmSyncCb_t *pScb = dmSyncCb;
|
||||
uint8_t i;
|
||||
|
||||
for (i = DM_SYNC_MAX; i > 0; i--, pScb++)
|
||||
{
|
||||
if (pScb->inUse && (pScb->handle == handle))
|
||||
{
|
||||
return pScb;
|
||||
}
|
||||
}
|
||||
|
||||
DM_TRACE_WARN1("dmSyncCbByHandle not found 0x%04x", handle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find a sync control block with advertising SID and advertiser BD address.
|
||||
*
|
||||
* \param sid Sid to find.
|
||||
* \param pAddr BD address to find.
|
||||
*
|
||||
* \return Pointer to CB or NULL if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmSyncCb_t *dmSyncCbBySidBdAddr(uint8_t sid, const uint8_t *pAddr)
|
||||
{
|
||||
dmSyncCb_t *pScb = dmSyncCb;
|
||||
uint8_t i;
|
||||
|
||||
for (i = DM_SYNC_MAX; i > 0; i--, pScb++)
|
||||
{
|
||||
if (pScb->inUse && (pScb->advSid == sid) && BdaCmp(pScb->advAddr, pAddr))
|
||||
{
|
||||
return pScb;
|
||||
}
|
||||
}
|
||||
|
||||
DM_TRACE_INFO0("dmSyncCbBySidBdAddr not found");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the sync control block for the given sync ID.
|
||||
*
|
||||
* \param syncId Sync ID.
|
||||
*
|
||||
* \return Pointer to CB or NULL if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmSyncCb_t *dmSyncCbById(dmSyncId_t syncId)
|
||||
{
|
||||
WSF_ASSERT((syncId > 0) && (syncId <= DM_SYNC_MAX));
|
||||
|
||||
syncId--;
|
||||
if (dmSyncCb[syncId].inUse)
|
||||
{
|
||||
return &dmSyncCb[syncId];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Empty action.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActNone(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Synchronize with periodic advertising from the given advertiser.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
HciLePerAdvCreateSyncCmd(dmCb.syncOptions, pMsg->apiSyncStart.advSid,
|
||||
pMsg->apiSyncStart.advAddrType, pMsg->apiSyncStart.advAddr,
|
||||
pMsg->apiSyncStart.skip, pMsg->apiSyncStart.syncTimeout,
|
||||
pMsg->apiSyncStart.unused);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop reception of the periodic advertising identified by the given sync handle.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActStop(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
HciLePerAdvTerminateSyncCmd(pScb->handle);
|
||||
|
||||
dmSyncSmActSyncLost(pScb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel creation of a sync while it's pending.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActCancelStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
HciLePerAdvCreateSyncCancelCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a sync established event from HCI.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActSyncEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
/* store adv sid, adv address and sync handle */
|
||||
pScb->advSid = pMsg->perAdvSyncEst.advSid;
|
||||
BdaCpy(pScb->advAddr, pMsg->perAdvSyncEst.advAddr);
|
||||
pScb->advAddrType = DmHostAddrType(pMsg->perAdvSyncEst.advAddrType);
|
||||
pScb->handle = pMsg->perAdvSyncEst.syncHandle;
|
||||
|
||||
pMsg->hdr.event = DM_PER_ADV_SYNC_EST_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a sync established failure event from HCI.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActSyncEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
/* deallocate scb */
|
||||
dmSyncCbDealloc(pScb);
|
||||
|
||||
pMsg->hdr.event = DM_PER_ADV_SYNC_EST_FAIL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a sync lost event from HCI.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActSyncLost(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
/* deallocate scb */
|
||||
dmSyncCbDealloc(pScb);
|
||||
|
||||
pMsg->hdr.event = DM_PER_ADV_SYNC_LOST_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a sync transfer established event from HCI.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActSyncTrsfEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
/* store adv sid, adv address and sync handle */
|
||||
pScb->advSid = pMsg->perAdvSyncTrsfEst.advSid;
|
||||
BdaCpy(pScb->advAddr, pMsg->perAdvSyncTrsfEst.advAddr);
|
||||
pScb->advAddrType = DmHostAddrType(pMsg->perAdvSyncTrsfEst.advAddrType);
|
||||
pScb->handle = pMsg->perAdvSyncTrsfEst.syncHandle;
|
||||
|
||||
pMsg->hdr.event = DM_PER_ADV_SYNC_TRSF_EST_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a sync transfer established failure event from HCI.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmActSyncTrsfEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
/* deallocate scb */
|
||||
dmSyncCbDealloc(pScb);
|
||||
|
||||
pMsg->hdr.event = DM_PER_ADV_SYNC_TRSF_EST_FAIL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the DM sync state machine.
|
||||
*
|
||||
* \param pScb Sync control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncSmExecute(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg)
|
||||
{
|
||||
uint8_t action;
|
||||
uint8_t event;
|
||||
|
||||
DM_TRACE_INFO2("dmSyncSmExecute event=%d state=%d", pMsg->hdr.event, pScb->state);
|
||||
|
||||
/* get the event */
|
||||
event = DM_MSG_MASK(pMsg->hdr.event);
|
||||
|
||||
/* get action */
|
||||
action = dmSyncStateTbl[pScb->state][event][DM_SYNC_ACTION];
|
||||
|
||||
/* set next state */
|
||||
pScb->state = dmSyncStateTbl[pScb->state][event][DM_SYNC_NEXT_STATE];
|
||||
|
||||
/* execute action function */
|
||||
(*dmSyncAct[action])(pScb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the sync module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_SYNC] = (dmFcnIf_t *) &dmSyncFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the sync module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncReset(void)
|
||||
{
|
||||
dmSyncCb_t *pScb = dmSyncCb;
|
||||
hciLePerAdvSyncLostEvt_t syncLost;
|
||||
uint8_t i;
|
||||
|
||||
/* generate HCI sync lost event */
|
||||
syncLost.hdr.event = HCI_LE_PER_ADV_SYNC_LOST_CBACK_EVT;
|
||||
syncLost.hdr.status = HCI_SUCCESS;
|
||||
|
||||
for (i = DM_SYNC_MAX; i > 0; i--, pScb++)
|
||||
{
|
||||
if (pScb->inUse)
|
||||
{
|
||||
/* set sync handle */
|
||||
syncLost.hdr.param = syncLost.syncHandle = pScb->handle;
|
||||
|
||||
/* handle the event */
|
||||
dmSyncHciHandler((hciEvt_t *) &syncLost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM sync HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* handle special case for periodic advertising report event */
|
||||
if (pEvent->hdr.event == HCI_LE_PER_ADV_REPORT_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_PER_ADV_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle special cases for sync established event */
|
||||
if (pEvent->hdr.event == HCI_LE_PER_ADV_SYNC_EST_CBACK_EVT)
|
||||
{
|
||||
/* first check if scb exists for this sid and bd addr */
|
||||
pScb = dmSyncCbBySidBdAddr(pEvent->lePerAdvSyncEst.advSid, pEvent->lePerAdvSyncEst.advAddr);
|
||||
|
||||
/* if scb not found */
|
||||
if (pScb == NULL)
|
||||
{
|
||||
/* check for special case state */
|
||||
pScb = dmSyncCmplState();
|
||||
}
|
||||
|
||||
/* translate HCI event to state machine event */
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pEvent->hdr.event = DM_SYNC_MSG_HCI_LE_SYNC_EST;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEvent->hdr.event = DM_SYNC_MSG_HCI_LE_SYNC_EST_FAIL;
|
||||
}
|
||||
}
|
||||
/* handle special cases for past received event */
|
||||
else if (pEvent->hdr.event == HCI_LE_PER_SYNC_TRSF_RCVD_CBACK_EVT)
|
||||
{
|
||||
/* first check if scb exists for this sid and bd addr */
|
||||
pScb = dmSyncCbBySidBdAddr(pEvent->lePerAdvSyncTrsfRcvd.advSid, pEvent->lePerAdvSyncTrsfRcvd.advAddr);
|
||||
|
||||
/* if scb not found */
|
||||
if (pScb == NULL)
|
||||
{
|
||||
/* allocate scb */
|
||||
pScb = dmSyncCbAlloc(pEvent->lePerAdvSyncTrsfRcvd.advSid, pEvent->lePerAdvSyncTrsfRcvd.advAddr);
|
||||
}
|
||||
|
||||
/* translate HCI event to state machine event */
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pEvent->hdr.event = DM_SYNC_MSG_HCI_LE_SYNC_TRSF_EST;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEvent->hdr.event = DM_SYNC_MSG_HCI_LE_SYNC_TRSF_EST_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pScb = dmSyncCbByHandle(pEvent->hdr.param);
|
||||
|
||||
/* translate HCI event to state machine message */
|
||||
pEvent->hdr.event = DM_SYNC_HCI_EVT_2_MSG(pEvent->hdr.event);
|
||||
}
|
||||
|
||||
/* if scb found */
|
||||
if (pScb != NULL)
|
||||
{
|
||||
/* set sync id */
|
||||
pEvent->hdr.param = pScb->syncId;
|
||||
|
||||
/* execute state machine */
|
||||
dmSyncSmExecute(pScb, (dmSyncMsg_t *) pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM sync event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmSyncMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* look up scb from sync id */
|
||||
if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->param)) != NULL)
|
||||
{
|
||||
/* execute state machine */
|
||||
dmSyncSmExecute(pScb, (dmSyncMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Synchronize with periodic advertising from the given advertiser, and start receiving
|
||||
* periodic advertising packets.
|
||||
*
|
||||
* Note: The synchronization filter policy is used to determine whether the periodic
|
||||
* advertiser list is used. If the periodic advertiser list is not used, the
|
||||
* advertising SID, advertiser address type, and advertiser address parameters
|
||||
* specify the periodic advertising device to listen to; otherwise these parameters
|
||||
* are ignored.
|
||||
*
|
||||
* \param advSid Advertising SID.
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param skip Number of periodic advertising packets that can be skipped after
|
||||
* successful receive.
|
||||
* \param syncTimeout Synchronization timeout.
|
||||
*
|
||||
* \return Sync identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmSyncId_t DmSyncStart(uint8_t advSid, uint8_t advAddrType, const uint8_t *pAdvAddr, uint16_t skip,
|
||||
uint16_t syncTimeout)
|
||||
{
|
||||
dmSyncCb_t *pScb = NULL;
|
||||
dmSyncApiStart_t *pMsg;
|
||||
|
||||
/* make sure scb not already allocated */
|
||||
WsfTaskLock();
|
||||
if ((pScb = dmSyncCbBySidBdAddr(advSid, pAdvAddr)) == NULL)
|
||||
{
|
||||
/* allocate scb */
|
||||
pScb = dmSyncCbAlloc(advSid, pAdvAddr);
|
||||
}
|
||||
WsfTaskUnlock();
|
||||
|
||||
if (pScb != NULL)
|
||||
{
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmSyncApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = pScb->syncId;
|
||||
pMsg->hdr.event = DM_SYNC_MSG_API_START;
|
||||
pMsg->advSid = advSid;
|
||||
pMsg->advAddrType = advAddrType;
|
||||
BdaCpy(pMsg->advAddr, pAdvAddr);
|
||||
pMsg->skip = skip;
|
||||
pMsg->syncTimeout = syncTimeout;
|
||||
pMsg->unused = 0;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
|
||||
/* return sync id */
|
||||
return pScb->syncId;
|
||||
}
|
||||
else
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmSyncCbDealloc(pScb);
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/* open failed */
|
||||
return DM_SYNC_ID_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop reception of the periodic advertising identified by the given sync identifier.
|
||||
*
|
||||
* \param syncId Sync identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSyncStop(dmSyncId_t syncId)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->param = syncId;
|
||||
pMsg->event = DM_SYNC_MSG_API_STOP;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add device to periodic advertiser list.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAddDeviceToPerAdvList(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
HciLeAddDeviceToPerAdvListCmd(advAddrType, pAdvAddr, advSid);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM remove device from periodic advertiser list.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmRemoveDeviceFromPerAdvList(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
HciLeRemoveDeviceFromPerAdvListCmd(advAddrType, pAdvAddr, advSid);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM clear periodic advertiser list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmClearPerAdvList(void)
|
||||
{
|
||||
HciLeClearPerAdvListCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM enable or disable initial periodic advertising reports once synchronized.
|
||||
*
|
||||
* \param enable TRUE to enable initial reporting, FALSE to disable initial reporting.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSyncInitialRptEnable(bool_t enable)
|
||||
{
|
||||
WsfTaskLock();
|
||||
if (enable)
|
||||
{
|
||||
/* Enable initial periodic advertisement reporting */
|
||||
dmCb.syncOptions &= ~HCI_OPTIONS_INIT_RPT_ENABLE_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable initial periodic advertisement reporting */
|
||||
dmCb.syncOptions |= HCI_OPTIONS_INIT_RPT_ENABLE_BIT;
|
||||
}
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
Reference in New Issue
Block a user