initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
@@ -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;
}
@@ -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 */
File diff suppressed because it is too large Load Diff
@@ -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;
}
File diff suppressed because it is too large Load Diff
@@ -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 */
@@ -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();
}
@@ -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();
}
@@ -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;
}
@@ -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;
}
@@ -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);
}
@@ -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;
}
@@ -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;
}
@@ -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);
}
}
@@ -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);
}
@@ -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 */
@@ -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);
}
}
@@ -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);
}
@@ -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 */
@@ -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);
}
}
@@ -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;
}
@@ -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 */
@@ -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);
}
}
@@ -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 */
@@ -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();
}
@@ -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 */
@@ -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;
}
@@ -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;
}
@@ -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();
}
@@ -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 */
@@ -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;
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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();
}