initial commit
This commit is contained in:
+1365
File diff suppressed because it is too large
Load Diff
+334
@@ -0,0 +1,334 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Attribute protocol constants and definitions from the Bluetooth specification.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef ATT_DEFS_H
|
||||
#define ATT_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_ATT_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name ATT PDU Format
|
||||
* ATT PDU defaults and constants
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_HDR_LEN 1 /*!< \brief Attribute PDU header length */
|
||||
#define ATT_AUTH_SIG_LEN 12 /*!< \brief Authentication signature length */
|
||||
#define ATT_DEFAULT_MTU 23 /*!< \brief Default value of ATT_MTU */
|
||||
#define ATT_MAX_MTU 517 /*!< \brief Maximum value of ATT_MTU */
|
||||
#define ATT_DEFAULT_PAYLOAD_LEN 20 /*!< \brief Default maximum payload length for most PDUs */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Maximum Value Parameters
|
||||
* maximum values for ATT attribute length and offset
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_VALUE_MAX_LEN 512 /*!< \brief Maximum attribute value length */
|
||||
#define ATT_VALUE_MAX_OFFSET 511 /*!< \brief Maximum attribute value offset */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Transaction Timeout
|
||||
* Maximum time allowed between transaction request and response.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_MAX_TRANS_TIMEOUT 30 /*!< \brief Maximum transaction timeout in seconds */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Error Codes
|
||||
* ATT Protocol operation status codes found in PDUs
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_SUCCESS 0x00 /*!< \brief Operation successful */
|
||||
#define ATT_ERR_HANDLE 0x01 /*!< \brief Invalid handle */
|
||||
#define ATT_ERR_READ 0x02 /*!< \brief Read not permitted */
|
||||
#define ATT_ERR_WRITE 0x03 /*!< \brief Write not permitted */
|
||||
#define ATT_ERR_INVALID_PDU 0x04 /*!< \brief Invalid pdu */
|
||||
#define ATT_ERR_AUTH 0x05 /*!< \brief Insufficient authentication */
|
||||
#define ATT_ERR_NOT_SUP 0x06 /*!< \brief Request not supported */
|
||||
#define ATT_ERR_OFFSET 0x07 /*!< \brief Invalid offset */
|
||||
#define ATT_ERR_AUTHOR 0x08 /*!< \brief Insufficient authorization */
|
||||
#define ATT_ERR_QUEUE_FULL 0x09 /*!< \brief Prepare queue full */
|
||||
#define ATT_ERR_NOT_FOUND 0x0A /*!< \brief Attribute not found */
|
||||
#define ATT_ERR_NOT_LONG 0x0B /*!< \brief Attribute not long */
|
||||
#define ATT_ERR_KEY_SIZE 0x0C /*!< \brief Insufficient encryption key size */
|
||||
#define ATT_ERR_LENGTH 0x0D /*!< \brief Invalid attribute value length */
|
||||
#define ATT_ERR_UNLIKELY 0x0E /*!< \brief Other unlikely error */
|
||||
#define ATT_ERR_ENC 0x0F /*!< \brief Insufficient encryption */
|
||||
#define ATT_ERR_GROUP_TYPE 0x10 /*!< \brief Unsupported group type */
|
||||
#define ATT_ERR_RESOURCES 0x11 /*!< \brief Insufficient resources */
|
||||
#define ATT_ERR_DATABASE_OUT_OF_SYNC 0x12 /*!< \brief Client out of synch with database */
|
||||
#define ATT_ERR_VALUE_NOT_ALLOWED 0x13 /*!< \brief Value not allowed */
|
||||
#define ATT_ERR_WRITE_REJ 0xFC /*!< \brief Write request rejected */
|
||||
#define ATT_ERR_CCCD 0xFD /*!< \brief CCCD improperly configured */
|
||||
#define ATT_ERR_IN_PROGRESS 0xFE /*!< \brief Procedure already in progress */
|
||||
#define ATT_ERR_RANGE 0xFF /*!< \brief Value out of range */
|
||||
/**@}*/
|
||||
|
||||
/** \name Proprietary Internal Error Codes
|
||||
* These codes may be sent to application but are not present in any ATT PDU.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_ERR_MEMORY 0x70 /*!< \brief Out of memory */
|
||||
#define ATT_ERR_TIMEOUT 0x71 /*!< \brief Transaction timeout */
|
||||
#define ATT_ERR_OVERFLOW 0x72 /*!< \brief Transaction overflow */
|
||||
#define ATT_ERR_INVALID_RSP 0x73 /*!< \brief Invalid response PDU */
|
||||
#define ATT_ERR_CANCELLED 0x74 /*!< \brief Request cancelled */
|
||||
#define ATT_ERR_UNDEFINED 0x75 /*!< \brief Other undefined error */
|
||||
#define ATT_ERR_REQ_NOT_FOUND 0x76 /*!< \brief Required characteristic not found */
|
||||
#define ATT_ERR_MTU_EXCEEDED 0x77 /*!< \brief Attribute PDU length exceeded MTU size */
|
||||
#define ATT_CONTINUING 0x78 /*!< \brief Procedure continuing */
|
||||
#define ATT_RSP_PENDING 0x79 /*!< \brief Responsed delayed pending higher layer */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Application Error Codes
|
||||
* These codes may be sent to application but are not present in any ATT PDU.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_ERR_VALUE_RANGE 0x80 /*!< \brief Value out of range */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT HCI Error Status
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Base value for HCI error status values passed through ATT.
|
||||
* Since the values of HCI and ATT error codes overlap, the constant
|
||||
* \ref ATT_HCI_ERR_BASE is added to HCI error codes before being passed through ATT.
|
||||
* See \ref HCI_SUCCESS for HCI error code values.
|
||||
*/
|
||||
#define ATT_HCI_ERR_BASE 0x20
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT PDU Types
|
||||
* PDU Types for all possible over-the-air ATT operations.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_PDU_ERR_RSP 0x01 /*!< \brief Error response */
|
||||
#define ATT_PDU_MTU_REQ 0x02 /*!< \brief Exchange mtu request */
|
||||
#define ATT_PDU_MTU_RSP 0x03 /*!< \brief Exchange mtu response */
|
||||
#define ATT_PDU_FIND_INFO_REQ 0x04 /*!< \brief Find information request */
|
||||
#define ATT_PDU_FIND_INFO_RSP 0x05 /*!< \brief Find information response */
|
||||
#define ATT_PDU_FIND_TYPE_REQ 0x06 /*!< \brief Find by type value request */
|
||||
#define ATT_PDU_FIND_TYPE_RSP 0x07 /*!< \brief Find by type value response */
|
||||
#define ATT_PDU_READ_TYPE_REQ 0x08 /*!< \brief Read by type request */
|
||||
#define ATT_PDU_READ_TYPE_RSP 0x09 /*!< \brief Read by type response */
|
||||
#define ATT_PDU_READ_REQ 0x0A /*!< \brief Read request */
|
||||
#define ATT_PDU_READ_RSP 0x0B /*!< \brief Read response */
|
||||
#define ATT_PDU_READ_BLOB_REQ 0x0C /*!< \brief Read blob request */
|
||||
#define ATT_PDU_READ_BLOB_RSP 0x0D /*!< \brief Read blob response */
|
||||
#define ATT_PDU_READ_MULT_REQ 0x0E /*!< \brief Read multiple request */
|
||||
#define ATT_PDU_READ_MULT_RSP 0x0F /*!< \brief Read multiple response */
|
||||
#define ATT_PDU_READ_GROUP_TYPE_REQ 0x10 /*!< \brief Read by group type request */
|
||||
#define ATT_PDU_READ_GROUP_TYPE_RSP 0x11 /*!< \brief Read by group type response */
|
||||
#define ATT_PDU_WRITE_REQ 0x12 /*!< \brief Write request */
|
||||
#define ATT_PDU_WRITE_RSP 0x13 /*!< \brief Write response */
|
||||
#define ATT_PDU_WRITE_CMD 0x52 /*!< \brief Write command */
|
||||
#define ATT_PDU_SIGNED_WRITE_CMD 0xD2 /*!< \brief Signed write command */
|
||||
#define ATT_PDU_PREP_WRITE_REQ 0x16 /*!< \brief Prepare write request */
|
||||
#define ATT_PDU_PREP_WRITE_RSP 0x17 /*!< \brief Prepare write response */
|
||||
#define ATT_PDU_EXEC_WRITE_REQ 0x18 /*!< \brief Execute write request */
|
||||
#define ATT_PDU_EXEC_WRITE_RSP 0x19 /*!< \brief Execute write response */
|
||||
#define ATT_PDU_VALUE_NTF 0x1B /*!< \brief Handle value notification */
|
||||
#define ATT_PDU_VALUE_IND 0x1D /*!< \brief Handle value indication */
|
||||
#define ATT_PDU_VALUE_CNF 0x1E /*!< \brief Handle value confirmation */
|
||||
#define ATT_PDU_MAX 0x1F /*!< \brief PDU Maximum */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT PDU Length Fields
|
||||
* Length constants of PDU fixed length fields
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_ERR_RSP_LEN 5 /*!< \brief Error response length. */
|
||||
#define ATT_MTU_REQ_LEN 3 /*!< \brief MTU request length. */
|
||||
#define ATT_MTU_RSP_LEN 3 /*!< \brief MTU response length. */
|
||||
#define ATT_FIND_INFO_REQ_LEN 5 /*!< \brief Find information request length. */
|
||||
#define ATT_FIND_INFO_RSP_LEN 2 /*!< \brief Find information response length. */
|
||||
#define ATT_FIND_TYPE_REQ_LEN 7 /*!< \brief Find type request length. */
|
||||
#define ATT_FIND_TYPE_RSP_LEN 1 /*!< \brief Find type response length. */
|
||||
#define ATT_READ_TYPE_REQ_LEN 5 /*!< \brief Read type request length. */
|
||||
#define ATT_READ_TYPE_RSP_LEN 2 /*!< \brief Read type response length. */
|
||||
#define ATT_READ_REQ_LEN 3 /*!< \brief Read request length. */
|
||||
#define ATT_READ_RSP_LEN 1 /*!< \brief Read response length. */
|
||||
#define ATT_READ_BLOB_REQ_LEN 5 /*!< \brief Read blob request legnth. */
|
||||
#define ATT_READ_BLOB_RSP_LEN 1 /*!< \brief Read blob response length. */
|
||||
#define ATT_READ_MULT_REQ_LEN 1 /*!< \brief Read multiple request length. */
|
||||
#define ATT_READ_MULT_RSP_LEN 1 /*!< \brief Read multiple response length. */
|
||||
#define ATT_READ_GROUP_TYPE_REQ_LEN 5 /*!< \brief Read group type request length. */
|
||||
#define ATT_READ_GROUP_TYPE_RSP_LEN 2 /*!< \brief Read group type response length. */
|
||||
#define ATT_WRITE_REQ_LEN 3 /*!< \brief Write request length. */
|
||||
#define ATT_WRITE_RSP_LEN 1 /*!< \brief Write response length. */
|
||||
#define ATT_WRITE_CMD_LEN 3 /*!< \brief Write command length. */
|
||||
#define ATT_SIGNED_WRITE_CMD_LEN (ATT_WRITE_CMD_LEN + ATT_AUTH_SIG_LEN) /*!< \brief Signed write command length. */
|
||||
#define ATT_PREP_WRITE_REQ_LEN 5 /*!< \brief Prepared write command length. */
|
||||
#define ATT_PREP_WRITE_RSP_LEN 5 /*!< \brief Prepared write response length. */
|
||||
#define ATT_EXEC_WRITE_REQ_LEN 2 /*!< \brief Execute write request length. */
|
||||
#define ATT_EXEC_WRITE_RSP_LEN 1 /*!< \brief Execute write response length. */
|
||||
#define ATT_VALUE_NTF_LEN 3 /*!< \brief Value notification length. */
|
||||
#define ATT_VALUE_IND_LEN 3 /*!< \brief Value indication length. */
|
||||
#define ATT_VALUE_CNF_LEN 1 /*!< \brief Value confirmation length. */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Find Information Response Format
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_FIND_HANDLE_16_UUID 0x01 /*!< \brief Handle and 16 bit UUID */
|
||||
#define ATT_FIND_HANDLE_128_UUID 0x02 /*!< \brief Handle and 128 bit UUID */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Execute Write Request Flags
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_EXEC_WRITE_CANCEL 0x00 /*!< \brief Cancel all prepared writes */
|
||||
#define ATT_EXEC_WRITE_ALL 0x01 /*!< \brief Write all pending prepared writes */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT PDU Masks
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_PDU_MASK_SERVER 0x01 /*!< \brief Server bit mask */
|
||||
#define ATT_PDU_MASK_COMMAND 0x40 /*!< \brief Command bit mask */
|
||||
#define ATT_PDU_MASK_SIGNED 0x80 /*!< \brief Auth signature bit mask */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT Handle Constants
|
||||
* Invalid, minimum and maximum handle values.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_HANDLE_NONE 0x0000 /*!< \brief Handle none. */
|
||||
#define ATT_HANDLE_START 0x0001 /*!< \brief Handle start. */
|
||||
#define ATT_HANDLE_MAX 0xFFFF /*!< \brief Handle max. */
|
||||
/**@}*/
|
||||
|
||||
/** \name ATT UUID Lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_NO_UUID_LEN 0 /*!< \brief Length when no UUID is present ;-) */
|
||||
#define ATT_16_UUID_LEN 2 /*!< \brief Length in bytes of a 16 bit UUID */
|
||||
#define ATT_128_UUID_LEN 16 /*!< \brief Length in bytes of a 128 bit UUID */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic Properties
|
||||
* Properties for how a characteristic may be interacted with through the ATT Protocol.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_PROP_BROADCAST 0x01 /*!< \brief Permit broadcasts */
|
||||
#define ATT_PROP_READ 0x02 /*!< \brief Permit reads */
|
||||
#define ATT_PROP_WRITE_NO_RSP 0x04 /*!< \brief Permit writes without response */
|
||||
#define ATT_PROP_WRITE 0x08 /*!< \brief Permit writes with response */
|
||||
#define ATT_PROP_NOTIFY 0x10 /*!< \brief Permit notifications */
|
||||
#define ATT_PROP_INDICATE 0x20 /*!< \brief Permit indications */
|
||||
#define ATT_PROP_AUTHENTICATED 0x40 /*!< \brief Permit signed writes */
|
||||
#define ATT_PROP_EXTENDED 0x80 /*!< \brief More properties defined in extended properties */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic Extended Properties
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_EXT_PROP_RELIABLE_WRITE 0x0001 /*!< \brief Permit reliable writes */
|
||||
#define ATT_EXT_PROP_WRITEABLE_AUX 0x0002 /*!< \brief Permit write to characteristic descriptor */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Client Charactertic Configuration
|
||||
* Configures a characteristic to send notifications or indications, if applicable.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_CLIENT_CFG_NOTIFY 0x0001 /*!< \brief Notify the value */
|
||||
#define ATT_CLIENT_CFG_INDICATE 0x0002 /*!< \brief Indicate the value */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Server Characteristic Configuration
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_SERVER_CFG_BROADCAST 0x0001 /*!< \brief Broadcast the value */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic Format
|
||||
* GATT Format descriptor values
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_FORMAT_BOOLEAN 0x01 /*!< \brief Boolean */
|
||||
#define ATT_FORMAT_2BIT 0x02 /*!< \brief Unsigned 2 bit integer */
|
||||
#define ATT_FORMAT_NIBBLE 0x03 /*!< \brief Unsigned 4 bit integer */
|
||||
#define ATT_FORMAT_UINT8 0x04 /*!< \brief Unsigned 8 bit integer */
|
||||
#define ATT_FORMAT_UINT12 0x05 /*!< \brief Unsigned 12 bit integer */
|
||||
#define ATT_FORMAT_UINT16 0x06 /*!< \brief Unsigned 16 bit integer */
|
||||
#define ATT_FORMAT_UINT24 0x07 /*!< \brief Unsigned 24 bit integer */
|
||||
#define ATT_FORMAT_UINT32 0x08 /*!< \brief Unsigned 32 bit integer */
|
||||
#define ATT_FORMAT_UINT48 0x09 /*!< \brief Unsigned 48 bit integer */
|
||||
#define ATT_FORMAT_UINT64 0x0A /*!< \brief Unsigned 64 bit integer */
|
||||
#define ATT_FORMAT_UINT128 0x0B /*!< \brief Unsigned 128 bit integer */
|
||||
#define ATT_FORMAT_SINT8 0x0C /*!< \brief Signed 8 bit integer */
|
||||
#define ATT_FORMAT_SINT12 0x0D /*!< \brief Signed 12 bit integer */
|
||||
#define ATT_FORMAT_SINT16 0x0E /*!< \brief Signed 16 bit integer */
|
||||
#define ATT_FORMAT_SINT24 0x0F /*!< \brief Signed 24 bit integer */
|
||||
#define ATT_FORMAT_SINT32 0x10 /*!< \brief Signed 32 bit integer */
|
||||
#define ATT_FORMAT_SINT48 0x11 /*!< \brief Signed 48 bit integer */
|
||||
#define ATT_FORMAT_SINT64 0x12 /*!< \brief Signed 64 bit integer */
|
||||
#define ATT_FORMAT_SINT128 0x13 /*!< \brief Signed 128 bit integer */
|
||||
#define ATT_FORMAT_FLOAT32 0x14 /*!< \brief IEEE-754 32 bit floating point */
|
||||
#define ATT_FORMAT_FLOAT64 0x15 /*!< \brief IEEE-754 64 bit floating point */
|
||||
#define ATT_FORMAT_SFLOAT 0x16 /*!< \brief IEEE-11073 16 bit SFLOAT */
|
||||
#define ATT_FORMAT_FLOAT 0x17 /*!< \brief IEEE-11073 32 bit FLOAT */
|
||||
#define ATT_FORMAT_DUINT16 0x18 /*!< \brief IEEE-20601 format */
|
||||
#define ATT_FORMAT_UTF8 0x19 /*!< \brief UTF-8 string */
|
||||
#define ATT_FORMAT_UTF16 0x1A /*!< \brief UTF-16 string */
|
||||
#define ATT_FORMAT_STRUCT 0x1B /*!< \brief Opaque structure */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Database Hash
|
||||
* GATT database hash values
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_DATABASE_HASH_LEN 16 /*!< \brief Database hash length. */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Client Supported Features
|
||||
* Flags of features supported by the GATT Client
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATTS_CSF_ROBUST_CACHING 1 /*!< \brief Robust caching. */
|
||||
#define ATTS_CSF_OCT0_FEATURES ATTS_CSF_ROBUST_CACHING /*!< \brief Mask of all client supported features. */
|
||||
|
||||
#define ATT_CSF_LEN 1 /*!< \brief Length of client supported features array. */
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_ATT_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATT_DEFS_H */
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Interface to ATT event handler.
|
||||
*
|
||||
* 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 ATT_HANDLER_H
|
||||
#define ATT_HANDLER_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_EVENT
|
||||
* \{ */
|
||||
|
||||
/** \name ATT Event Handling
|
||||
* Message passing interface to ATT from other tasks through WSF.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATT handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerId WSF handler ID for ATT.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for ATT.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_EVENT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATT_HANDLER_H */
|
||||
+544
@@ -0,0 +1,544 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Attribute protocol UUIDs from the Bluetooth specification.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef ATT_UUID_H
|
||||
#define ATT_UUID_H
|
||||
|
||||
#include "att_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_ATT_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name ATT Service UUIDs
|
||||
* Defined BLE Service UUID constants.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_UUID_GAP_SERVICE 0x1800 /*!< \brief Generic Access Profile Service */
|
||||
#define ATT_UUID_GATT_SERVICE 0x1801 /*!< \brief Generic Attribute Profile Service */
|
||||
#define ATT_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /*!< \brief Immediate Alert Service */
|
||||
#define ATT_UUID_LINK_LOSS_SERVICE 0x1803 /*!< \brief Link Loss Service */
|
||||
#define ATT_UUID_TX_POWER_SERVICE 0x1804 /*!< \brief Tx Power Service */
|
||||
#define ATT_UUID_CURRENT_TIME_SERVICE 0x1805 /*!< \brief Current Time Service */
|
||||
#define ATT_UUID_REF_TIME_UPDATE_SERVICE 0x1806 /*!< \brief Reference Time Update Service */
|
||||
#define ATT_UUID_DST_CHANGE_SERVICE 0x1807 /*!< \brief Next DST Change Service */
|
||||
#define ATT_UUID_GLUCOSE_SERVICE 0x1808 /*!< \brief Glucose Service */
|
||||
#define ATT_UUID_HEALTH_THERM_SERVICE 0x1809 /*!< \brief Health Thermometer Service */
|
||||
#define ATT_UUID_DEVICE_INFO_SERVICE 0x180A /*!< \brief Device Information Service */
|
||||
#define ATT_UUID_NETWORK_AVAIL_SERVICE 0x180B /*!< \brief Network Availability Service */
|
||||
#define ATT_UUID_WATCHDOG_SERVICE 0x180C /*!< \brief Watchdog Service */
|
||||
#define ATT_UUID_HEART_RATE_SERVICE 0x180D /*!< \brief Heart Rate Service */
|
||||
#define ATT_UUID_PHONE_ALERT_SERVICE 0x180E /*!< \brief Phone Alert Status Service */
|
||||
#define ATT_UUID_BATTERY_SERVICE 0x180F /*!< \brief Battery Service */
|
||||
#define ATT_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /*!< \brief Blood Pressure Service */
|
||||
#define ATT_UUID_ALERT_NOTIF_SERVICE 0x1811 /*!< \brief Alert Notification Service */
|
||||
#define ATT_UUID_HID_SERVICE 0x1812 /*!< \brief Human Interface Device Service */
|
||||
#define ATT_UUID_SCAN_PARAM_SERVICE 0x1813 /*!< \brief Scan Parameter Service */
|
||||
#define ATT_UUID_RUNNING_SPEED_SERVICE 0x1814 /*!< \brief Running Speed Service */
|
||||
#define ATT_UUID_CYCLING_SPEED_SERVICE 0x1816 /*!< \brief Cycling Speed Service */
|
||||
#define ATT_UUID_CYCLING_POWER_SERVICE 0x1818 /*!< \brief Cycling Power Service */
|
||||
#define ATT_UUID_USER_DATA_SERVICE 0x181C /*!< \brief User Data Service */
|
||||
#define ATT_UUID_WEIGHT_SCALE_SERVICE 0x181D /*!< \brief Weight Scale Service */
|
||||
#define ATT_UUID_IP_SUPPORT_SERVICE 0x1820 /*!< \brief IP Support Service */
|
||||
#define ATT_UUID_PULSE_OXIMITER_SERVICE 0x1822 /*!< \brief Pulse Oximeter Service */
|
||||
#define ATT_UUID_MESH_PRV_SERVICE 0x1827 /*!< \brief Mesh Provisioning Service */
|
||||
#define ATT_UUID_MESH_PROXY_SERVICE 0x1828 /*!< \brief Mesh Proxy Service */
|
||||
#define ATT_UUID_CONSTANT_TONE_SERVICE 0x7F7F /*!< \brief Constant Tone Extension */
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT UUIDs
|
||||
* BLE Defined UUIDs of GATT Service components
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_UUID_PRIMARY_SERVICE 0x2800 /*!< \brief Primary Service */
|
||||
#define ATT_UUID_SECONDARY_SERVICE 0x2801 /*!< \brief Secondary Service */
|
||||
#define ATT_UUID_INCLUDE 0x2802 /*!< \brief Include */
|
||||
#define ATT_UUID_CHARACTERISTIC 0x2803 /*!< \brief Characteristic */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic Descriptor UUIDs
|
||||
* BLE Defined UUIDs of Characteristic Descriptors
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_UUID_CHARACTERISTIC_EXT 0x2900 /*!< \brief Characteristic Extended Properties */
|
||||
#define ATT_UUID_CHAR_USER_DESC 0x2901 /*!< \brief Characteristic User Description */
|
||||
#define ATT_UUID_CLIENT_CHAR_CONFIG 0x2902 /*!< \brief Client Characteristic Configuration */
|
||||
#define ATT_UUID_SERVER_CHAR_CONFIG 0x2903 /*!< \brief Server Characteristic Configuration */
|
||||
#define ATT_UUID_CHAR_PRES_FORMAT 0x2904 /*!< \brief Characteristic Presentation Format */
|
||||
#define ATT_UUID_AGGREGATE_FORMAT 0x2905 /*!< \brief Characteristic Aggregate Format */
|
||||
#define ATT_UUID_VALID_RANGE 0x2906 /*!< \brief Valid Range */
|
||||
#define ATT_UUID_HID_EXT_REPORT_MAPPING 0x2907 /*!< \brief HID External Report ID Mapping */
|
||||
#define ATT_UUID_HID_REPORT_ID_MAPPING 0x2908 /*!< \brief HID Report ID Mapping */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characistic UUIDs
|
||||
* BLE Defined UUIDs of Characeristics
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_UUID_DEVICE_NAME 0x2A00 /*!< \brief Device Name */
|
||||
#define ATT_UUID_APPEARANCE 0x2A01 /*!< \brief Appearance */
|
||||
#define ATT_UUID_PERIPH_PRIVACY_FLAG 0x2A02 /*!< \brief Peripheral Privacy Flag */
|
||||
#define ATT_UUID_RECONN_ADDR 0x2A03 /*!< \brief Reconnection Address */
|
||||
#define ATT_UUID_PREF_CONN_PARAM 0x2A04 /*!< \brief Peripheral Preferred Connection Parameters */
|
||||
#define ATT_UUID_SERVICE_CHANGED 0x2A05 /*!< \brief Service Changed */
|
||||
#define ATT_UUID_ALERT_LEVEL 0x2A06 /*!< \brief Alert Level */
|
||||
#define ATT_UUID_TX_POWER_LEVEL 0x2A07 /*!< \brief Tx Power Level */
|
||||
#define ATT_UUID_DATE_TIME 0x2A08 /*!< \brief Date Time */
|
||||
#define ATT_UUID_DAY_OF_WEEK 0x2A09 /*!< \brief Day of Week */
|
||||
#define ATT_UUID_DAY_DATE_TIME 0x2A0A /*!< \brief Day Date Time */
|
||||
#define ATT_UUID_EXACT_TIME_100 0x2A0B /*!< \brief Exact Time 100 */
|
||||
#define ATT_UUID_EXACT_TIME_256 0x2A0C /*!< \brief Exact Time 256 */
|
||||
#define ATT_UUID_DST_OFFSET 0x2A0D /*!< \brief DST Offset */
|
||||
#define ATT_UUID_TIME_ZONE 0x2A0E /*!< \brief Time Zone */
|
||||
#define ATT_UUID_LOCAL_TIME_INFO 0x2A0F /*!< \brief Local Time Information */
|
||||
#define ATT_UUID_SECONDARY_TIME_ZONE 0x2A10 /*!< \brief Secondary Time Zone */
|
||||
#define ATT_UUID_TIME_WITH_DST 0x2A11 /*!< \brief Time with DST */
|
||||
#define ATT_UUID_TIME_ACCURACY 0x2A12 /*!< \brief Time Accuracy */
|
||||
#define ATT_UUID_TIME_SOURCE 0x2A13 /*!< \brief Time Source */
|
||||
#define ATT_UUID_REFERENCE_TIME_INFO 0x2A14 /*!< \brief Reference Time Information */
|
||||
#define ATT_UUID_TIME_BROADCAST 0x2A15 /*!< \brief Time Broadcast */
|
||||
#define ATT_UUID_TIME_UPDATE_CP 0x2A16 /*!< \brief Time Update Control Point */
|
||||
#define ATT_UUID_TIME_UPDATE_STATE 0x2A17 /*!< \brief Time Update State */
|
||||
#define ATT_UUID_GLUCOSE_MEAS 0x2A18 /*!< \brief Glucose Measurement */
|
||||
#define ATT_UUID_BATTERY_LEVEL 0x2A19 /*!< \brief Battery Level */
|
||||
#define ATT_UUID_BATTERY_POWER_STATE 0x2A1A /*!< \brief Battery Power State */
|
||||
#define ATT_UUID_BATTERY_LEVEL_STATE 0x2A1B /*!< \brief Battery Level State */
|
||||
#define ATT_UUID_TEMP_MEAS 0x2A1C /*!< \brief Temperature Measurement */
|
||||
#define ATT_UUID_TEMP_TYPE 0x2A1D /*!< \brief Temperature Type */
|
||||
#define ATT_UUID_INTERMEDIATE_TEMP 0x2A1E /*!< \brief Intermediate Temperature */
|
||||
#define ATT_UUID_TEMP_C 0x2A1F /*!< \brief Temperature Celsius */
|
||||
#define ATT_UUID_TEMP_F 0x2A20 /*!< \brief Temperature Fahrenheit */
|
||||
#define ATT_UUID_MEAS_INTERVAL 0x2A21 /*!< \brief Measurement Interval */
|
||||
#define ATT_UUID_HID_BOOT_KEYBOARD_IN 0x2A22 /*!< \brief HID Boot Keyboard In */
|
||||
#define ATT_UUID_SYSTEM_ID 0x2A23 /*!< \brief System ID */
|
||||
#define ATT_UUID_MODEL_NUMBER 0x2A24 /*!< \brief Model Number String */
|
||||
#define ATT_UUID_SERIAL_NUMBER 0x2A25 /*!< \brief Serial Number String */
|
||||
#define ATT_UUID_FIRMWARE_REV 0x2A26 /*!< \brief Firmware Revision String */
|
||||
#define ATT_UUID_HARDWARE_REV 0x2A27 /*!< \brief Hardware Revision String */
|
||||
#define ATT_UUID_SOFTWARE_REV 0x2A28 /*!< \brief Software Revision String */
|
||||
#define ATT_UUID_MANUFACTURER_NAME 0x2A29 /*!< \brief Manufacturer Name String */
|
||||
#define ATT_UUID_11073_CERT_DATA 0x2A2A /*!< \brief IEEE 11073-20601 Regulatory Certification Data List */
|
||||
#define ATT_UUID_CURRENT_TIME 0x2A2B /*!< \brief Current Time */
|
||||
#define ATT_UUID_ELEVATION 0x2A2C /*!< \brief Elevation */
|
||||
#define ATT_UUID_LATITUDE 0x2A2D /*!< \brief Latitude */
|
||||
#define ATT_UUID_LONGITUDE 0x2A2E /*!< \brief Longitude */
|
||||
#define ATT_UUID_POSITION_2D 0x2A2F /*!< \brief Position 2D */
|
||||
#define ATT_UUID_POSITION_3D 0x2A30 /*!< \brief Position 3D */
|
||||
#define ATT_UUID_VENDOR_ID 0x2A31 /*!< \brief Vendor ID */
|
||||
#define ATT_UUID_HID_BOOT_KEYBOARD_OUT 0x2A32 /*!< \brief HID Boot Keyboard Out */
|
||||
#define ATT_UUID_HID_BOOT_MOUSE_IN 0x2A33 /*!< \brief HID Boot Mouse In */
|
||||
#define ATT_UUID_GLUCOSE_MEAS_CONTEXT 0x2A34 /*!< \brief Glucose Measurement Context */
|
||||
#define ATT_UUID_BP_MEAS 0x2A35 /*!< \brief Blood Pressure Measurement */
|
||||
#define ATT_UUID_INTERMEDIATE_BP 0x2A36 /*!< \brief Intermediate Cuff Pressure */
|
||||
#define ATT_UUID_HR_MEAS 0x2A37 /*!< \brief Heart Rate Measurement */
|
||||
#define ATT_UUID_HR_SENSOR_LOC 0x2A38 /*!< \brief Body Sensor Location */
|
||||
#define ATT_UUID_HR_CP 0x2A39 /*!< \brief Heart Rate Control Point */
|
||||
#define ATT_UUID_REMOVABLE 0x2A3A /*!< \brief Removable */
|
||||
#define ATT_UUID_SERVICE_REQ 0x2A3B /*!< \brief Service Required */
|
||||
#define ATT_UUID_SCI_TEMP_C 0x2A3C /*!< \brief Scientific Temperature in Celsius */
|
||||
#define ATT_UUID_STRING 0x2A3D /*!< \brief String */
|
||||
#define ATT_UUID_NETWORK_AVAIL 0x2A3E /*!< \brief Network Availability */
|
||||
#define ATT_UUID_ALERT_STATUS 0x2A3F /*!< \brief Alert Status */
|
||||
#define ATT_UUID_RINGER_CP 0x2A40 /*!< \brief Ringer Control Point */
|
||||
#define ATT_UUID_RINGER_SETTING 0x2A41 /*!< \brief Ringer Setting */
|
||||
#define ATT_UUID_ALERT_CAT_ID_MASK 0x2A42 /*!< \brief Alert Category ID Bit Mask */
|
||||
#define ATT_UUID_ALERT_CAT_ID 0x2A43 /*!< \brief Alert Category ID */
|
||||
#define ATT_UUID_ALERT_NOTIF_CP 0x2A44 /*!< \brief Alert Notification Control Point */
|
||||
#define ATT_UUID_UNREAD_ALERT_STATUS 0x2A45 /*!< \brief Unread Alert Status */
|
||||
#define ATT_UUID_NEW_ALERT 0x2A46 /*!< \brief New Alert */
|
||||
#define ATT_UUID_SUP_NEW_ALERT_CAT 0x2A47 /*!< \brief Supported New Alert Category */
|
||||
#define ATT_UUID_SUP_UNREAD_ALERT_CAT 0x2A48 /*!< \brief Supported Unread Alert Category */
|
||||
#define ATT_UUID_BP_FEATURE 0x2A49 /*!< \brief Blood Pressure Feature */
|
||||
#define ATT_UUID_HID_INFORMATION 0x2A4A /*!< \brief HID Information */
|
||||
#define ATT_UUID_HID_REPORT_MAP 0x2A4B /*!< \brief HID Report Map */
|
||||
#define ATT_UUID_HID_CONTROL_POINT 0x2A4C /*!< \brief HID Control Point */
|
||||
#define ATT_UUID_HID_REPORT 0x2A4D /*!< \brief HID Report */
|
||||
#define ATT_UUID_HID_PROTOCOL_MODE 0x2A4E /*!< \brief HID Protocol Mode */
|
||||
#define ATT_UUID_SCAN_INT_WIND 0x2A4F /*!< \brief Scan Interval Window */
|
||||
#define ATT_UUID_PNP_ID 0x2A50 /*!< \brief PnP ID */
|
||||
#define ATT_UUID_GLUCOSE_FEATURE 0x2A51 /*!< \brief Glucose Feature */
|
||||
#define ATT_UUID_RACP 0x2A52 /*!< \brief Record Access Control Point */
|
||||
#define ATT_UUID_CAR 0x2AA6 /*!< \brief Central Address Resolution */
|
||||
#define ATT_UUID_RUNNING_SPEED_FEATURE 0x2A54 /*!< \brief Running Speed Feature */
|
||||
#define ATT_UUID_RUNNING_SPEED_MEASUREMENT 0x2A53 /*!< \brief Running Speed Measurement */
|
||||
#define ATT_UUID_PULSE_OX_FEATURES 0x2A60 /*!< \brief Pulse Oximeter Features */
|
||||
#define ATT_UUID_PULSE_OX_SPOT_CHECK 0x2A5E /*!< \brief Pulse Oximeter Features */
|
||||
#define ATT_UUID_PULSE_OX_CONTINUOUS 0x2A5F /*!< \brief Pulse Oximeter Features */
|
||||
#define ATT_UUID_CYCLING_POWER_FEATURE 0x2A65 /*!< \brief Cycling Power Feature */
|
||||
#define ATT_UUID_CYCLING_POWER_MEASUREMENT 0x2A63 /*!< \brief Cycling Power Measurement */
|
||||
#define ATT_UUID_CYCLING_SPEED_FEATURE 0x2A5C /*!< \brief Cycling Speed Feature */
|
||||
#define ATT_UUID_CYCLING_SPEED_MEASUREMENT 0x2A5B /*!< \brief Cycling Speed Measurement */
|
||||
#define ATT_UUID_SENSOR_LOCATION 0x2A5D /*!< \brief Sensor Location */
|
||||
#define ATT_UUID_DB_CHANGE_INCREMENT 0x2A99 /*!< \brief Database Change Increment */
|
||||
#define ATT_UUID_USER_INDEX 0x2A9A /*!< \brief User Index */
|
||||
#define ATT_UUID_WEIGHT_MEAS 0x2A9D /*!< \brief Weight Measurement */
|
||||
#define ATT_UUID_WEIGHT_SCALE_FEATURE 0x2A9E /*!< \brief Weight Scale Feature */
|
||||
#define ATT_UUID_USER_CONTROL_POINT 0x2A9F /*!< \brief User Control Point */
|
||||
#define ATT_UUID_RPAO 0x2AC9 /*!< \brief Resolvable Prviate Address Only */
|
||||
#define ATT_UUID_MESH_PRV_DATA_IN 0x2ADB /*!< \brief Mesh Provisioning Data In */
|
||||
#define ATT_UUID_MESH_PRV_DATA_OUT 0x2ADC /*!< \brief Mesh Provisioning Data Out */
|
||||
#define ATT_UUID_MESH_PROXY_DATA_IN 0x2ADD /*!< \brief Mesh Proxy Data In */
|
||||
#define ATT_UUID_MESH_PROXY_DATA_OUT 0x2ADE /*!< \brief Mesh Proxy Data Out */
|
||||
#define ATT_UUID_CLIENT_SUPPORTED_FEATURES 0x2B29 /*!< \brief Client Supported Features */
|
||||
#define ATT_UUID_DATABASE_HASH 0x2B2A /*!< \brief Database Hash */
|
||||
#define ATT_UUID_CTE_ENABLE 0x7F80 /*!< \brief Constant Tone Extension enable */
|
||||
#define ATT_UUID_CTE_MIN_LEN 0x7F81 /*!< \brief Constant Tone Extension minimum length */
|
||||
#define ATT_UUID_CTE_TX_CNT 0x7F82 /*!< \brief Constant Tone Extension transmit count */
|
||||
#define ATT_UUID_CTE_TX_DURATION 0x7F83 /*!< \brief Constant Tone Extension transmit duration */
|
||||
#define ATT_UUID_CTE_INTERVAL 0x7F84 /*!< \brief Constant Tone Extension interval */
|
||||
#define ATT_UUID_CTE_PHY 0x7F85 /*!< \brief Constant Tone Extension PHY */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Unit UUIDs
|
||||
* BLE Defined GATT Unit UUIDs.
|
||||
*/
|
||||
/**@{*/
|
||||
#define ATT_UUID_UNITLESS 0x2700 /*!< \brief unitless */
|
||||
#define ATT_UUID_LENGTH_M 0x2701 /*!< \brief length metre */
|
||||
#define ATT_UUID_MASS_KG 0x2702 /*!< \brief mass kilogram */
|
||||
#define ATT_UUID_TIME_SEC 0x2703 /*!< \brief time second */
|
||||
#define ATT_UUID_ELECTRIC_CURRENT_AMP 0x2704 /*!< \brief electric current ampere */
|
||||
#define ATT_UUID_THERMO_TEMP_K 0x2705 /*!< \brief thermodynamic temperature kelvin */
|
||||
#define ATT_UUID_AMOUNT_OF_SUBSTANCE_MOLE 0x2706 /*!< \brief amount of substance mole */
|
||||
#define ATT_UUID_LUMINOUS_INTENSITY_CAND 0x2707 /*!< \brief luminous intensity candela */
|
||||
#define ATT_UUID_AREA_SQ_M 0x2710 /*!< \brief area square metres */
|
||||
#define ATT_UUID_VOLUME_CU_M 0x2711 /*!< \brief volume cubic metres */
|
||||
#define ATT_UUID_VELOCITY_MPS 0x2712 /*!< \brief velocity metres per second */
|
||||
#define ATT_UUID_ACCELERATION_MPS_SQ 0x2713 /*!< \brief acceleration metres per second squared */
|
||||
#define ATT_UUID_WAVENUMBER_RECIPROCAL_M 0x2714 /*!< \brief wavenumber reciprocal metre */
|
||||
#define ATT_UUID_DENSITY_KG_PER_CU_M 0x2715 /*!< \brief density kilogram per cubic metre */
|
||||
#define ATT_UUID_SURFACE_DENS_KG_PER_SQ_M 0x2716 /*!< \brief surface density kilogram per square metre */
|
||||
#define ATT_UUID_SPECIFIC_VOL_CU_M_PER_KG 0x2717 /*!< \brief specific volume cubic metre per kilogram */
|
||||
#define ATT_UUID_CURRENT_DENS_AMP_PER_SQ_M 0x2718 /*!< \brief current density ampere per square metre */
|
||||
#define ATT_UUID_MAG_FIELD_STR_AMP_PER_M 0x2719 /*!< \brief magnetic field strength ampere per metre */
|
||||
#define ATT_UUID_AMOUNT_CONC_MOLE_PER_CU_M 0x271A /*!< \brief amount concentration mole per cubic metre */
|
||||
#define ATT_UUID_MASS_CONC_KG_PER_CU_M 0x271B /*!< \brief mass concentration kilogram per cubic metre */
|
||||
#define ATT_UUID_LUM_CAND_PER_SQ_M 0x271C /*!< \brief luminance candela per square metre */
|
||||
#define ATT_UUID_REFRACTIVE_INDEX 0x271D /*!< \brief refractive index */
|
||||
#define ATT_UUID_RELATIVE_PERMEABILITY 0x271E /*!< \brief relative permeability */
|
||||
#define ATT_UUID_PLANE_ANGLE_R 0x2720 /*!< \brief plane angle radian */
|
||||
#define ATT_UUID_SOLID_ANGLE_STER 0x2721 /*!< \brief solid angle steradian */
|
||||
#define ATT_UUID_FREQUENCY_HERTZ 0x2722 /*!< \brief frequency hertz */
|
||||
#define ATT_UUID_FORCE_NEWT 0x2723 /*!< \brief force newton */
|
||||
#define ATT_UUID_PRESSURE_PASCAL 0x2724 /*!< \brief pressure pascal */
|
||||
#define ATT_UUID_ENERGY_J 0x2725 /*!< \brief energy joule */
|
||||
#define ATT_UUID_POWER_W 0x2726 /*!< \brief power watt */
|
||||
#define ATT_UUID_ELECTRIC_CHG_C 0x2727 /*!< \brief electric charge coulomb */
|
||||
#define ATT_UUID_ELECTRIC_POTENTIAL_VOLT 0x2728 /*!< \brief electric potential difference volt */
|
||||
#define ATT_UUID_CAPACITANCE_F 0x2729 /*!< \brief capacitance farad */
|
||||
#define ATT_UUID_ELECTRIC_RESISTANCE_OHM 0x272A /*!< \brief electric resistance ohm */
|
||||
#define ATT_UUID_ELECTRIC_COND_SIEMENS 0x272B /*!< \brief electric conductance siemens */
|
||||
#define ATT_UUID_MAGNETIC_FLEX_WEBER 0x272C /*!< \brief magnetic flex weber */
|
||||
#define ATT_UUID_MAGNETIC_FLEX_DENS_TESLA 0x272D /*!< \brief magnetic flex density tesla */
|
||||
#define ATT_UUID_INDUCTANCE_H 0x272E /*!< \brief inductance henry */
|
||||
#define ATT_UUID_C_TEMP_DEG_C 0x272F /*!< \brief Celsius temperature degree Celsius */
|
||||
#define ATT_UUID_LUMINOUS_FLUX_LUMEN 0x2730 /*!< \brief luminous flux lumen */
|
||||
#define ATT_UUID_ILLUMINANCE_LUX 0x2731 /*!< \brief illuminance lux */
|
||||
#define ATT_UUID_RADIONUCLIDE_BECQUEREL 0x2732 /*!< \brief activity referred to a radionuclide becquerel */
|
||||
#define ATT_UUID_ABSORBED_DOSE_GRAY 0x2733 /*!< \brief absorbed dose gray */
|
||||
#define ATT_UUID_DOSE_EQUIVALENT_SIEVERT 0x2734 /*!< \brief dose equivalent sievert */
|
||||
#define ATT_UUID_CATALYTIC_ACTIVITY_KATAL 0x2735 /*!< \brief catalytic activity katal */
|
||||
#define ATT_UUID_DYNAMIC_VISC_PASCAL_SEC 0x2740 /*!< \brief dynamic viscosity pascal second */
|
||||
#define ATT_UUID_MOMENT_OF_FORCE_NEWT_M 0x2741 /*!< \brief moment of force newton metre */
|
||||
#define ATT_UUID_SURFACE_TENSION_NEWT_PER_M 0x2742 /*!< \brief surface tension newton per metre */
|
||||
#define ATT_UUID_ANG_VELOCITY_R_PER_SEC 0x2743 /*!< \brief angular velocity radian per second */
|
||||
#define ATT_UUID_ANG_ACCEL_R_PER_SEC_SQD 0x2744 /*!< \brief angular acceleration radian per second squared */
|
||||
#define ATT_UUID_HEAT_FLUX_DEN_W_PER_SQ_M 0x2745 /*!< \brief heat flux density watt per square metre */
|
||||
#define ATT_UUID_HEAT_CAP_J_PER_K 0x2746 /*!< \brief heat capacity joule per kelvin */
|
||||
#define ATT_UUID_SPEC_HEAT_CAP_J_PER_KG_K 0x2747 /*!< \brief specific heat capacity joule per kilogram kelvin */
|
||||
#define ATT_UUID_SPEC_ENERGY_J_PER_KG 0x2748 /*!< \brief specific energy joule per kilogram */
|
||||
#define ATT_UUID_THERMAL_COND_W_PER_M_K 0x2749 /*!< \brief thermal conductivity watt per metre kelvin */
|
||||
#define ATT_UUID_ENERGY_DENSITY_J_PER_CU_M 0x274A /*!< \brief energy density joule per cubic metre */
|
||||
#define ATT_UUID_ELEC_FIELD_STR_VOLT_PER_M 0x274B /*!< \brief electric field strength volt per metre */
|
||||
#define ATT_UUID_ELEC_CHG_DENS_C_PER_CU_M 0x274C /*!< \brief electric charge density coulomb per cubic metre */
|
||||
#define ATT_UUID_SURF_CHG_DENS_C_PER_SQ_M 0x274D /*!< \brief surface charge density coulomb per square metre */
|
||||
#define ATT_UUID_ELEC_FLUX_DENS_C_PER_SQ_M 0x274E /*!< \brief electric flux density coulomb per square metre */
|
||||
#define ATT_UUID_PERMITTIVITY_F_PER_M 0x274F /*!< \brief permittivity farad per metre */
|
||||
#define ATT_UUID_PERMEABILITY_H_PER_M 0x2750 /*!< \brief permeability henry per metre */
|
||||
#define ATT_UUID_MOLAR_ENERGY_J_PER_MOLE 0x2751 /*!< \brief molar energy joule per mole */
|
||||
#define ATT_UUID_MOLAR_ENTROPY_J_PER_MOLE_K 0x2752 /*!< \brief molar entropy joule per mole kelvin */
|
||||
#define ATT_UUID_EXPOSURE_C_PER_KG 0x2753 /*!< \brief exposure coulomb per kilogram */
|
||||
#define ATT_UUID_DOSE_RATE_GRAY_PER_SEC 0x2754 /*!< \brief absorbed dose rate gray per second */
|
||||
#define ATT_UUID_RT_INTENSITY_W_PER_STER 0x2755 /*!< \brief radiant intensity watt per steradian */
|
||||
#define ATT_UUID_RCE_W_PER_SQ_METER_STER 0x2756 /*!< \brief radiance watt per square meter steradian */
|
||||
#define ATT_UUID_CATALYTIC_KATAL_PER_CU_M 0x2757 /*!< \brief catalytic activity concentration katal per cubic metre */
|
||||
#define ATT_UUID_TIME_MIN 0x2760 /*!< \brief time minute */
|
||||
#define ATT_UUID_TIME_HR 0x2761 /*!< \brief time hour */
|
||||
#define ATT_UUID_TIME_DAY 0x2762 /*!< \brief time day */
|
||||
#define ATT_UUID_PLANE_ANGLE_DEG 0x2763 /*!< \brief plane angle degree */
|
||||
#define ATT_UUID_PLANE_ANGLE_MIN 0x2764 /*!< \brief plane angle minute */
|
||||
#define ATT_UUID_PLANE_ANGLE_SEC 0x2765 /*!< \brief plane angle second */
|
||||
#define ATT_UUID_AREA_HECTARE 0x2766 /*!< \brief area hectare */
|
||||
#define ATT_UUID_VOLUME_L 0x2767 /*!< \brief volume litre */
|
||||
#define ATT_UUID_MASS_TONNE 0x2768 /*!< \brief mass tonne */
|
||||
#define ATT_UUID_PRESSURE_BAR 0x2780 /*!< \brief pressure bar */
|
||||
#define ATT_UUID_PRESSURE_MM 0x2781 /*!< \brief pressure millimetre of mercury */
|
||||
#define ATT_UUID_LENGTH_ANGSTROM 0x2782 /*!< \brief length angstrom */
|
||||
#define ATT_UUID_LENGTH_NAUTICAL_MILE 0x2783 /*!< \brief length nautical mile */
|
||||
#define ATT_UUID_AREA_BARN 0x2784 /*!< \brief area barn */
|
||||
#define ATT_UUID_VELOCITY_KNOT 0x2785 /*!< \brief velocity knot */
|
||||
#define ATT_UUID_LOG_RADIO_QUANT_NEPER 0x2786 /*!< \brief logarithmic radio quantity neper */
|
||||
#define ATT_UUID_LOG_RADIO_QUANT_BEL 0x2787 /*!< \brief logarithmic radio quantity bel */
|
||||
#define ATT_UUID_LOG_RADIO_QUANT_DB 0x2788 /*!< \brief logarithmic radio quantity decibel */
|
||||
#define ATT_UUID_LENGTH_YARD 0x27A0 /*!< \brief length yard */
|
||||
#define ATT_UUID_LENGTH_PARSEC 0x27A1 /*!< \brief length parsec */
|
||||
#define ATT_UUID_LENGTH_IN 0x27A2 /*!< \brief length inch */
|
||||
#define ATT_UUID_LENGTH_FOOT 0x27A3 /*!< \brief length foot */
|
||||
#define ATT_UUID_LENGTH_MILE 0x27A4 /*!< \brief length mile */
|
||||
#define ATT_UUID_PRESSURE_POUND_PER_SQ_IN 0x27A5 /*!< \brief pressure pound-force per square inch */
|
||||
#define ATT_UUID_VELOCITY_KPH 0x27A6 /*!< \brief velocity kilometre per hour */
|
||||
#define ATT_UUID_VELOCITY_MPH 0x27A7 /*!< \brief velocity mile per hour */
|
||||
#define ATT_UUID_ANG_VELOCITY_RPM 0x27A8 /*!< \brief angular velocity revolution per minute */
|
||||
#define ATT_UUID_ENERGY_GRAM_CALORIE 0x27A9 /*!< \brief energy gram calorie */
|
||||
#define ATT_UUID_ENERGY_KG_CALORIE 0x27AA /*!< \brief energy kilogram calorie */
|
||||
#define ATT_UUID_ENERGY_KILOWATT_HR 0x27AB /*!< \brief energy kilowatt hour */
|
||||
#define ATT_UUID_THERM_TEMP_F 0x27AC /*!< \brief thermodynamic temperature degree Fahrenheit */
|
||||
#define ATT_UUID_PERCENTAGE 0x27AD /*!< \brief percentage */
|
||||
#define ATT_UUID_PER_MILLE 0x27AE /*!< \brief per mille */
|
||||
#define ATT_UUID_PERIOD_BEATS_PER_MIN 0x27AF /*!< \brief period beats per minute */
|
||||
#define ATT_UUID_ELECTRIC_CHG_AMP_HRS 0x27B0 /*!< \brief electric charge ampere hours */
|
||||
#define ATT_UUID_MASS_DENSITY_MG_PER_DL 0x27B1 /*!< \brief mass density milligram per decilitre */
|
||||
#define ATT_UUID_MASS_DENSITY_MMOLE_PER_L 0x27B2 /*!< \brief mass density millimole per litre */
|
||||
#define ATT_UUID_TIME_YEAR 0x27B3 /*!< \brief time year */
|
||||
#define ATT_UUID_TIME_MONTH 0x27B4 /*!< \brief time month */
|
||||
/**@}*/
|
||||
|
||||
/** \name Arm Ltd. proprietary UUIDs
|
||||
* propertietary services defined by Arm Ltd.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*! \brief Base UUID: E0262760-08C2-11E1-9073-0E8AC72EXXXX */
|
||||
#define ATT_UUID_ARM_BASE 0x2E, 0xC7, 0x8A, 0x0E, 0x73, 0x90, \
|
||||
0xE1, 0x11, 0xC2, 0x08, 0x60, 0x27, 0x26, 0xE0
|
||||
|
||||
/*! \brief Macro for building Arm Ltd. UUIDs */
|
||||
#define ATT_UUID_ARM_BUILD(part) UINT16_TO_BYTES(part), ATT_UUID_ARM_BASE
|
||||
|
||||
|
||||
/** \brief Partial proprietary service P1 UUID */
|
||||
#define ATT_UUID_P1_SERVICE_PART 0x1001
|
||||
|
||||
/** \brief Partial proprietary characteristic data D1 UUID */
|
||||
#define ATT_UUID_D1_DATA_PART 0x0001
|
||||
|
||||
/*! \brief Proprietary services */
|
||||
#define ATT_UUID_P1_SERVICE ATT_UUID_ARM_BUILD(ATT_UUID_P1_SERVICE_PART)
|
||||
|
||||
/*! \brief Proprietary characteristics */
|
||||
#define ATT_UUID_D1_DATA ATT_UUID_ARM_BUILD(ATT_UUID_D1_DATA_PART)
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name ATT Service UUID Variables
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
extern const uint8_t attGapSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Generic Access Profile Service */
|
||||
extern const uint8_t attGattSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Generic Attribute Profile Service */
|
||||
extern const uint8_t attIasSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Immediate Alert Service */
|
||||
extern const uint8_t attLlsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Link Loss Service */
|
||||
extern const uint8_t attTpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Tx Power Service */
|
||||
extern const uint8_t attCtsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Current Time Service */
|
||||
extern const uint8_t attRtusSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Reference Time Update Service */
|
||||
extern const uint8_t attNdcsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Next DST Change Service */
|
||||
extern const uint8_t attGlsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Service */
|
||||
extern const uint8_t attHtsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Health Thermometer Service */
|
||||
extern const uint8_t attDisSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Device Information Service */
|
||||
extern const uint8_t attNwaSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Network Availability Service */
|
||||
extern const uint8_t attWdsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Watchdog Service */
|
||||
extern const uint8_t attHrsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Service */
|
||||
extern const uint8_t attPassSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Phone Alert Status Service */
|
||||
extern const uint8_t attBasSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Service */
|
||||
extern const uint8_t attBpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Service */
|
||||
extern const uint8_t attAnsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Notification Service */
|
||||
extern const uint8_t attHidSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Human Interface Device Service */
|
||||
extern const uint8_t attSpsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Scan Parameter Service */
|
||||
extern const uint8_t attPlxsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Service */
|
||||
extern const uint8_t attUdsSvcUuid[ATT_16_UUID_LEN]; /*!< \brief User Data Service */
|
||||
extern const uint8_t attMprvSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Service */
|
||||
extern const uint8_t attMprxSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Service */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT UUID Variables
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
extern const uint8_t attPrimSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Primary Service */
|
||||
extern const uint8_t attSecSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Secondary Service */
|
||||
extern const uint8_t attIncUuid[ATT_16_UUID_LEN]; /*!< \brief Include */
|
||||
extern const uint8_t attChUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic Descriptor UUID Variables
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
extern const uint8_t attChExtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Extended Properties */
|
||||
extern const uint8_t attChUserDescUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic User Description */
|
||||
extern const uint8_t attCliChCfgUuid[ATT_16_UUID_LEN]; /*!< \brief Client Characteristic Configuration */
|
||||
extern const uint8_t attSrvChCfgUuid[ATT_16_UUID_LEN]; /*!< \brief Server Characteristic Configuration */
|
||||
extern const uint8_t attChPresFmtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Presentation Format */
|
||||
extern const uint8_t attAggFmtUuid[ATT_16_UUID_LEN]; /*!< \brief Characteristic Aggregate Format */
|
||||
extern const uint8_t attHidErmUuid[ATT_16_UUID_LEN]; /*!< \brief HID External Report Reference */
|
||||
extern const uint8_t attHidRimUuid[ATT_16_UUID_LEN]; /*!< \brief HID Report ID Mapping */
|
||||
extern const uint8_t attValRangeUuid[ATT_16_UUID_LEN]; /*!< \brief Valid Range */
|
||||
/**@}*/
|
||||
|
||||
/** \name GATT Characteristic UUID Variables
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
extern const uint8_t attDnChUuid[ATT_16_UUID_LEN]; /*!< \brief Device Name */
|
||||
extern const uint8_t attApChUuid[ATT_16_UUID_LEN]; /*!< \brief Appearance */
|
||||
extern const uint8_t attPpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Peripheral Privacy Flag */
|
||||
extern const uint8_t attRaChUuid[ATT_16_UUID_LEN]; /*!< \brief Reconnection Address */
|
||||
extern const uint8_t attPpcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Peripheral Preferred Connection Parameters */
|
||||
extern const uint8_t attScChUuid[ATT_16_UUID_LEN]; /*!< \brief Service Changed */
|
||||
extern const uint8_t attAlChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Level */
|
||||
extern const uint8_t attTxpChUuid[ATT_16_UUID_LEN]; /*!< \brief Tx Power Level */
|
||||
extern const uint8_t attDtChUuid[ATT_16_UUID_LEN]; /*!< \brief Date Time */
|
||||
extern const uint8_t attDwChUuid[ATT_16_UUID_LEN]; /*!< \brief Day of Week */
|
||||
extern const uint8_t attDdtChUuid[ATT_16_UUID_LEN]; /*!< \brief Day Date Time */
|
||||
extern const uint8_t attEt100ChUuid[ATT_16_UUID_LEN]; /*!< \brief Exact Time 100 */
|
||||
extern const uint8_t attEt256ChUuid[ATT_16_UUID_LEN]; /*!< \brief Exact Time 256 */
|
||||
extern const uint8_t attDstoChUuid[ATT_16_UUID_LEN]; /*!< \brief DST Offset */
|
||||
extern const uint8_t attTzChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Zone */
|
||||
extern const uint8_t attLtiChUuid[ATT_16_UUID_LEN]; /*!< \brief Local Time Information */
|
||||
extern const uint8_t attStzChUuid[ATT_16_UUID_LEN]; /*!< \brief Secondary Time Zone */
|
||||
extern const uint8_t attTdstChUuid[ATT_16_UUID_LEN]; /*!< \brief Time with DST */
|
||||
extern const uint8_t attTaChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Accuracy */
|
||||
extern const uint8_t attTsChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Source */
|
||||
extern const uint8_t attRtiChUuid[ATT_16_UUID_LEN]; /*!< \brief Reference Time Information */
|
||||
extern const uint8_t attTbChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Broadcast */
|
||||
extern const uint8_t attTucpChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Update Control Point */
|
||||
extern const uint8_t attTusChUuid[ATT_16_UUID_LEN]; /*!< \brief Time Update State */
|
||||
extern const uint8_t attGlmChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Measurement */
|
||||
extern const uint8_t attBlChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Level */
|
||||
extern const uint8_t attBpsChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Power State */
|
||||
extern const uint8_t attBlsChUuid[ATT_16_UUID_LEN]; /*!< \brief Battery Level State */
|
||||
extern const uint8_t attTmChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Measurement */
|
||||
extern const uint8_t attTtChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Type */
|
||||
extern const uint8_t attItChUuid[ATT_16_UUID_LEN]; /*!< \brief Intermediate Temperature */
|
||||
extern const uint8_t attTcelChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Celsius */
|
||||
extern const uint8_t attTfahChUuid[ATT_16_UUID_LEN]; /*!< \brief Temperature Fahrenheit */
|
||||
extern const uint8_t attSidChUuid[ATT_16_UUID_LEN]; /*!< \brief System ID */
|
||||
extern const uint8_t attMnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Model Number String */
|
||||
extern const uint8_t attSnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Serial Number String */
|
||||
extern const uint8_t attFrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Firmware Revision String */
|
||||
extern const uint8_t attHrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Hardware Revision String */
|
||||
extern const uint8_t attSrsChUuid[ATT_16_UUID_LEN]; /*!< \brief Software Revision String */
|
||||
extern const uint8_t attMfnsChUuid[ATT_16_UUID_LEN]; /*!< \brief Manufacturer Name String */
|
||||
extern const uint8_t attIeeeChUuid[ATT_16_UUID_LEN]; /*!< \brief IEEE 11073-20601 Regulatory Certification Data List */
|
||||
extern const uint8_t attCtChUuid[ATT_16_UUID_LEN]; /*!< \brief Current Time */
|
||||
extern const uint8_t attElChUuid[ATT_16_UUID_LEN]; /*!< \brief Elevation */
|
||||
extern const uint8_t attLatChUuid[ATT_16_UUID_LEN]; /*!< \brief Latitude */
|
||||
extern const uint8_t attLongChUuid[ATT_16_UUID_LEN]; /*!< \brief Longitude */
|
||||
extern const uint8_t attP2dChUuid[ATT_16_UUID_LEN]; /*!< \brief Position 2D */
|
||||
extern const uint8_t attP3dChUuid[ATT_16_UUID_LEN]; /*!< \brief Position 3D */
|
||||
extern const uint8_t attVidChUuid[ATT_16_UUID_LEN]; /*!< \brief Vendor ID */
|
||||
extern const uint8_t attGlmcChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Measurement Context */
|
||||
extern const uint8_t attBpmChUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Measurement */
|
||||
extern const uint8_t attIcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Intermediate Cuff Pressure */
|
||||
extern const uint8_t attHrmChUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Measurement */
|
||||
extern const uint8_t attBslChUuid[ATT_16_UUID_LEN]; /*!< \brief Body Sensor Location */
|
||||
extern const uint8_t attHrcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Heart Rate Control Point */
|
||||
extern const uint8_t attRemChUuid[ATT_16_UUID_LEN]; /*!< \brief Removable */
|
||||
extern const uint8_t attSrChUuid[ATT_16_UUID_LEN]; /*!< \brief Service Required */
|
||||
extern const uint8_t attStcChUuid[ATT_16_UUID_LEN]; /*!< \brief Scientific Temperature in Celsius */
|
||||
extern const uint8_t attStrChUuid[ATT_16_UUID_LEN]; /*!< \brief String */
|
||||
extern const uint8_t attNwaChUuid[ATT_16_UUID_LEN]; /*!< \brief Network Availability */
|
||||
extern const uint8_t attAsChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Status */
|
||||
extern const uint8_t attRcpChUuid[ATT_16_UUID_LEN]; /*!< \brief Ringer Control Point */
|
||||
extern const uint8_t attRsChUuid[ATT_16_UUID_LEN]; /*!< \brief Ringer Setting */
|
||||
extern const uint8_t attAcbmChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Category ID Bit Mask */
|
||||
extern const uint8_t attAcChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Category ID */
|
||||
extern const uint8_t attAncpChUuid[ATT_16_UUID_LEN]; /*!< \brief Alert Notification Control Point */
|
||||
extern const uint8_t attUasChUuid[ATT_16_UUID_LEN]; /*!< \brief Unread Alert Status */
|
||||
extern const uint8_t attNaChUuid[ATT_16_UUID_LEN]; /*!< \brief New Alert */
|
||||
extern const uint8_t attSnacChUuid[ATT_16_UUID_LEN]; /*!< \brief Supported New Alert Category */
|
||||
extern const uint8_t attSuacChUuid[ATT_16_UUID_LEN]; /*!< \brief Supported Unread Alert Category */
|
||||
extern const uint8_t attBpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Blood Pressure Feature */
|
||||
extern const uint8_t attHidBmiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
|
||||
extern const uint8_t attHidBkiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
|
||||
extern const uint8_t attHidBkoChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
|
||||
extern const uint8_t attHidiChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Information */
|
||||
extern const uint8_t attHidRmChUuid[ATT_16_UUID_LEN]; /*!< \brief Report Map */
|
||||
extern const uint8_t attHidcpChUuid[ATT_16_UUID_LEN]; /*!< \brief HID Control Point */
|
||||
extern const uint8_t attHidRepChUuid[ATT_16_UUID_LEN]; /*!< \brief Report */
|
||||
extern const uint8_t attHidPmChUuid[ATT_16_UUID_LEN]; /*!< \brief Protocol Mode */
|
||||
extern const uint8_t attSiwChUuid[ATT_16_UUID_LEN]; /*!< \brief Scan Interval Window */
|
||||
extern const uint8_t attPnpChUuid[ATT_16_UUID_LEN]; /*!< \brief PnP ID */
|
||||
extern const uint8_t attGlfChUuid[ATT_16_UUID_LEN]; /*!< \brief Glucose Feature */
|
||||
extern const uint8_t attRacpChUuid[ATT_16_UUID_LEN]; /*!< \brief Record Access Control Point */
|
||||
extern const uint8_t attCarChUuid[ATT_16_UUID_LEN]; /*!< \brief Central Address Resolution */
|
||||
extern const uint8_t attRsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Running Speed Features */
|
||||
extern const uint8_t attRsmChUuid[ATT_16_UUID_LEN]; /*!< \brief Running Speed Measurement */
|
||||
extern const uint8_t attCpfChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Power Features */
|
||||
extern const uint8_t attCpmChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Power Measurement */
|
||||
extern const uint8_t attCsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Speed Features */
|
||||
extern const uint8_t attCsmChUuid[ATT_16_UUID_LEN]; /*!< \brief Cycling Speed Measurement */
|
||||
extern const uint8_t attSlChUuid[ATT_16_UUID_LEN]; /*!< \brief Sensor Location */
|
||||
extern const uint8_t attPlxfChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Features */
|
||||
extern const uint8_t attPlxscmChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Spot Check Measurement */
|
||||
extern const uint8_t attPlxcmChUuid[ATT_16_UUID_LEN]; /*!< \brief Pulse Oximeter Continuous Measurement */
|
||||
extern const uint8_t attRpaoChUuid[ATT_16_UUID_LEN]; /*!< \brief Resolvable Private Address Only */
|
||||
extern const uint8_t attDbciChUuid[ATT_16_UUID_LEN]; /*!< \brief Database Change Increment */
|
||||
extern const uint8_t attUiChUuid[ATT_16_UUID_LEN]; /*!< \brief User Index */
|
||||
extern const uint8_t attUcpChUuid[ATT_16_UUID_LEN]; /*!< \brief User Control Point */
|
||||
extern const uint8_t attMprvDinChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Data In */
|
||||
extern const uint8_t attMprvDoutChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Provisioning Data Out */
|
||||
extern const uint8_t attMprxDinChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Data In */
|
||||
extern const uint8_t attMprxDoutChUuid[ATT_16_UUID_LEN]; /*!< \brief Mesh Proxy Data Out */
|
||||
extern const uint8_t attWssSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Weight scale service */
|
||||
extern const uint8_t attWmChUuid[ATT_16_UUID_LEN]; /*!< \brief Weight measurement */
|
||||
extern const uint8_t attWsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Weight scale feature */
|
||||
extern const uint8_t attGattCsfChUuid[ATT_16_UUID_LEN]; /*!< \brief Client supported features */
|
||||
extern const uint8_t attGattDbhChUuid[ATT_16_UUID_LEN]; /*!< \brief Database hash */
|
||||
extern const uint8_t attCteSvcUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension service */
|
||||
extern const uint8_t attCteEnChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension enable */
|
||||
extern const uint8_t attCteMinLenChUuid[ATT_16_UUID_LEN];/*!< \brief Constant Tone Extension minimum length */
|
||||
extern const uint8_t attCteTxCntChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension minimum transmit count */
|
||||
extern const uint8_t attCteTxDurChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension transmit duration */
|
||||
extern const uint8_t attCteIntChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension interval */
|
||||
extern const uint8_t attCtePhyChUuid[ATT_16_UUID_LEN]; /*!< \brief Constant Tone Extension PHY */
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_ATT_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATT_UUID_H */
|
||||
+2721
File diff suppressed because it is too large
Load Diff
+77
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Interface to DM event handler.
|
||||
*
|
||||
* 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_HANDLER_H
|
||||
#define DM_HANDLER_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_EVENT
|
||||
* \{ */
|
||||
|
||||
/** \name DM Event Handling
|
||||
* Message passing interface to DM from other tasks through WSF.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerId WSF handler ID for DM.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_DM_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_HANDLER_H */
|
||||
+2435
File diff suppressed because it is too large
Load Diff
+95
@@ -0,0 +1,95 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI command 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 HCI_CMD_H
|
||||
#define HCI_CMD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an HCI command and service the HCI command queue.
|
||||
*
|
||||
* \param pData Buffer containing HCI command to send or NULL.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCmdSend(uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate an HCI command buffer and set the command header fields.
|
||||
*
|
||||
* \param opcode Command opcode.
|
||||
* \param len length of command parameters.
|
||||
*
|
||||
* \return Pointer to WSF msg buffer.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCmdAlloc(uint16_t opcode, uint16_t len);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the HCI cmd module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCmdInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process an HCI command timeout.
|
||||
*
|
||||
* \param pMsg Message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCmdTimeout(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process an HCI Command Complete or Command Status event.
|
||||
*
|
||||
* \param numCmdPkts Number of commands that can be sent to the controller.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCmdRecvCmpl(uint8_t numCmdPkts);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_CMD_H */
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI core interfaces.
|
||||
*
|
||||
* 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 HCI_CORE_H
|
||||
#define HCI_CORE_H
|
||||
|
||||
#include "hci_core_ps.h"
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_os.h"
|
||||
#include "hci_api.h"
|
||||
#include "cfg_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Callback Function Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief HCI Reset sequence callback type */
|
||||
typedef void(*hciResetSeq_t)(uint8_t *pMsg, uint16_t opcode);
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Per-connection structure for ACL packet accounting */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *pTxAclPkt; /*!< \brief Fragmenting TX ACL packet pointer */
|
||||
uint8_t *pNextTxFrag; /*!< \brief Next TX ACL packet fragment */
|
||||
uint8_t *pRxAclPkt; /*!< \brief RX ACL packet pointer */
|
||||
uint8_t *pNextRxFrag; /*!< \brief Next RX ACL packet fragment */
|
||||
uint16_t handle; /*!< \brief Connection handle */
|
||||
uint16_t txAclRemLen; /*!< \brief Fragmenting TX ACL packet remaining length */
|
||||
uint16_t rxAclRemLen; /*!< \brief Fragmented RX ACL packet remaining length */
|
||||
bool_t fragmenting; /*!< \brief TRUE if fragmenting a TX ACL packet */
|
||||
bool_t flowDisabled; /*!< \brief TRUE if data flow disabled */
|
||||
uint8_t queuedBufs; /*!< \brief Queued ACL buffers on this connection */
|
||||
uint8_t outBufs; /*!< \brief Outstanding ACL buffers sent to controller */
|
||||
} hciCoreConn_t;
|
||||
|
||||
/*! \brief Main control block for dual-chip implementation */
|
||||
typedef struct
|
||||
{
|
||||
hciCoreConn_t conn[DM_CONN_MAX]; /*!< \brief Connection structures */
|
||||
uint8_t leStates[HCI_LE_STATES_LEN]; /*!< \brief Controller LE supported states */
|
||||
bdAddr_t bdAddr; /*!< \brief Bluetooth device address */
|
||||
wsfQueue_t aclQueue; /*!< \brief HCI ACL TX queue */
|
||||
hciCoreConn_t *pConnRx; /*!< \brief Connection struct for current transport RX packet */
|
||||
uint16_t maxRxAclLen; /*!< \brief Maximum reassembled RX ACL packet length */
|
||||
uint16_t bufSize; /*!< \brief Controller ACL data buffer size */
|
||||
uint8_t aclQueueHi; /*!< \brief Disable flow when this many ACL buffers queued */
|
||||
uint8_t aclQueueLo; /*!< \brief Enable flow when this many ACL buffers queued */
|
||||
uint8_t availBufs; /*!< \brief Current avail ACL data buffers */
|
||||
uint8_t numBufs; /*!< \brief Controller number of ACL data buffers */
|
||||
uint8_t whiteListSize; /*!< \brief Controller white list size */
|
||||
uint8_t numCmdPkts; /*!< \brief Controller command packed count */
|
||||
uint32_t leSupFeat; /*!< \brief Controller LE supported features */
|
||||
int8_t advTxPwr; /*!< \brief Controller advertising TX power */
|
||||
uint8_t resListSize; /*!< \brief Controller resolving list size */
|
||||
uint16_t maxAdvDataLen; /*!< \brief Controller maximum advertisement (or scan response) data length */
|
||||
uint8_t numSupAdvSets; /*!< \brief Controller maximum number of advertising sets */
|
||||
uint8_t perAdvListSize; /*!< \brief Controller periodic advertising list size */
|
||||
hciLocalVerInfo_t locVerInfo; /*!< \brief Controller version information */
|
||||
hciResetSeq_t extResetSeq; /*!< \brief HCI extended reset sequence callback */
|
||||
} hciCoreCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Control block */
|
||||
extern hciCoreCb_t hciCoreCb;
|
||||
|
||||
/*! \brief Event mask */
|
||||
extern const uint8_t hciEventMask[HCI_EVT_MASK_LEN];
|
||||
|
||||
/*! \brief LE event mask */
|
||||
extern const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN];
|
||||
|
||||
/*! \brief Event mask page 2 */
|
||||
extern const uint8_t hciEventMaskPage2[HCI_EVT_MASK_LEN];
|
||||
|
||||
/*! \brief LE supported features configuration mask */
|
||||
extern uint32_t hciLeSupFeatCfg;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreResetStart
|
||||
*
|
||||
* \brief Start the HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreResetStart(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection open.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnOpen(uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection close.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnClose(uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get a connection structure by handle
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL data to transport.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Service the TX data path.
|
||||
*
|
||||
* \param bufs Number of new buffers now available.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxReady(uint8_t bufs);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, start of packet.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param len ACL packet length.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, continuation of fragmented packets.
|
||||
*
|
||||
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
|
||||
* sent from this connection structure. If NULL the function finds the next
|
||||
* connection structure with a fragment to be sent.
|
||||
*
|
||||
* \return TRUE if packet sent, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called from the HCI transport layer when transmission of an ACL
|
||||
* packet is complete.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reassemble an ACL packet.
|
||||
*
|
||||
* \param pData Input ACL packet.
|
||||
*
|
||||
* \return pointer to ACL packet to send, or NULL if no packet to send.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCoreAclReassembly(uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a TX ACL packet is being fragmented.
|
||||
*
|
||||
* \param pConn Connection context.
|
||||
*
|
||||
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_CORE_H */
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI driver interface.
|
||||
*
|
||||
* Copyright (c) 2012-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 HCI_DRV_H
|
||||
#define HCI_DRV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write data the driver.
|
||||
*
|
||||
* \param type HCI packet type
|
||||
* \param len Number of bytes to write.
|
||||
* \param pData Byte array to write.
|
||||
*
|
||||
* \return Return actual number of data bytes written.
|
||||
*
|
||||
* \note The type parameter allows the driver layer to prepend the data with a header on the
|
||||
* same write transaction.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t hciDrvWrite(uint8_t type, uint16_t len, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read data bytes from the driver.
|
||||
*
|
||||
* \param len Number of bytes to read.
|
||||
* \param pData Byte array to store data.
|
||||
*
|
||||
* \return Return actual number of data bytes read.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t hciDrvRead(uint16_t len, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Returns TRUE if driver allows MCU to enter low power sleep mode.
|
||||
*
|
||||
* \return TRUE if ready to sleep, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciDrvReadyToSleep(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_DRV_H */
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI event 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 HCI_EVT_H
|
||||
#define HCI_EVT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_HCI_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief HCI event statistics */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t numDiscCmplEvt; /*!< \brief Number discovery complete events. */
|
||||
uint16_t numEncChangeEvt; /*!< \brief Number encryption change events. */
|
||||
uint16_t numReadRemoteVerInfoCmpEvt; /*!< \brief Number read remote version info complete events. */
|
||||
uint16_t numCmdCmplEvt; /*!< \brief Number command complete events. */
|
||||
uint16_t numCmdStatusEvt; /*!< \brief Number command status events. */
|
||||
uint16_t numHwErrorEvt; /*!< \brief Number hardware error events. */
|
||||
uint16_t numCmplPktsEvt; /*!< \brief Number complete packet events. */
|
||||
uint16_t numDataBufOverflowEvt; /*!< \brief Number data buf overflow events. */
|
||||
uint16_t numEncKeyRefreshCmplEvt; /*!< \brief Number encryption key refresh complete events. */
|
||||
uint16_t numLeMetaEvt; /*!< \brief Number LE meta events. */
|
||||
uint16_t numVendorSpecEvt; /*!< \brief Number vendor specific events. */
|
||||
uint16_t numAuthToEvt; /*!< \brief Number authenticated to events. */
|
||||
} hciEvtStats_t;
|
||||
|
||||
/*! \} */ /* STACK_HCI_API */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received HCI events.
|
||||
*
|
||||
* \param pEvt Buffer containing HCI event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciEvtProcessMsg(uint8_t *pEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get event statistics.
|
||||
*
|
||||
* \return Event statistics.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciEvtStats_t *hciEvtGetStats(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_EVT_H */
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Interface to HCI event handler.
|
||||
*
|
||||
* 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 HCI_HANDLER_H
|
||||
#define HCI_HANDLER_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_EVENT
|
||||
* \{ */
|
||||
|
||||
/** \name HCI Event Handling
|
||||
* Message passing interface to HCI from application and other stack layers through WSF.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerId WSF handler ID for HCI.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for HCI.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**@}*/
|
||||
/*! \} */ /* STACK_HCI_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_HANDLER_H */
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI transport interface.
|
||||
*
|
||||
* 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 HCI_TR_H
|
||||
#define HCI_TR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a complete HCI ACL packet to the transport.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
* \param pAclData WSF msg buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendAclData(void *pContext, uint8_t *pAclData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a complete HCI command to the transport.
|
||||
*
|
||||
* \param pCmdData WSF msg buffer containing an HCI command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendCmd(uint8_t *pCmdData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize HCI transport resources.
|
||||
*
|
||||
* \param port COM port.
|
||||
* \param baudRate Baud rate.
|
||||
* \param flowControl TRUE if flow control is enabled
|
||||
*
|
||||
* \return TRUE if initialization succeeds, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciTrInit(uint8_t port, uint32_t baudRate, bool_t flowControl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Close HCI transport resources.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrShutdown(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_TR_H */
|
||||
+476
@@ -0,0 +1,476 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP subsystem API.
|
||||
*
|
||||
* 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 L2C_API_H
|
||||
#define L2C_API_H
|
||||
|
||||
#include "dm_api.h"
|
||||
#include "l2c_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_L2CAP_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name L2CAP Control Callback Events
|
||||
* Control callback message events
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_CTRL_FLOW_ENABLE_IND 0 /*!< \brief Data flow enabled */
|
||||
#define L2C_CTRL_FLOW_DISABLE_IND 1 /*!< \brief Data flow disabled */
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Invalid channel registration ID for connection oriented channels */
|
||||
#define L2C_COC_REG_ID_NONE 0
|
||||
|
||||
/*! \brief Invalid channel ID for connection oriented channels */
|
||||
#define L2C_COC_CID_NONE 0
|
||||
|
||||
/*! \brief Invalid signal identifier */
|
||||
#define L2C_SIGNAL_ID_INVALID 0
|
||||
|
||||
/** \name L2CAP COC Channel Roles
|
||||
* Connection oriented channel initiator/acceptor role
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_COC_ROLE_NONE 0x00 /*!< \brief No role (unallocated) */
|
||||
#define L2C_COC_ROLE_INITIATOR 0x01 /*!< \brief Channel initiator */
|
||||
#define L2C_COC_ROLE_ACCEPTOR 0x02 /*!< \brief Channel acceptor */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP COC Data Confirm Codes
|
||||
* Connection oriented channel data confirm status values
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_COC_DATA_SUCCESS 0 /*!< \brief Data request successful */
|
||||
#define L2C_COC_DATA_ERR_MEMORY 1 /*!< \brief Out of memory */
|
||||
#define L2C_COC_DATA_ERR_OVERFLOW 2 /*!< \brief Transaction overflow */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP COC Callback Events
|
||||
* Connection oriented channel callback events.
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_COC_CBACK_START 0x70 /*!< \brief L2C callback event starting value */
|
||||
/*! \brief COC callback events */
|
||||
enum
|
||||
{
|
||||
L2C_COC_CONNECT_IND = L2C_COC_CBACK_START, /*!< \brief Channel connect indication */
|
||||
L2C_COC_DISCONNECT_IND, /*!< \brief Channel disconnect indication */
|
||||
L2C_COC_DATA_IND, /*!< \brief Received data indication */
|
||||
L2C_COC_DATA_CNF /*!< \brief Transmit data confirm */
|
||||
};
|
||||
|
||||
#define L2C_COC_CBACK_CBACK_END L2C_COC_DATA_CNF /*!< \brief L2C callback event ending value */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Connection oriented channel registration ID */
|
||||
typedef uint16_t l2cCocRegId_t;
|
||||
|
||||
/*! \brief Connection oriented channel registration structure */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t psm; /*!< \brief Protocol service multiplexer */
|
||||
uint16_t mps; /*!< \brief Maximum receive PDU fragment size */
|
||||
uint16_t mtu; /*!< \brief Maximum receive data packet size */
|
||||
uint16_t credits; /*!< \brief Data packet receive credits for this channel */
|
||||
bool_t authoriz; /*!< \brief TRUE if authorization is required */
|
||||
uint8_t secLevel; /*!< \brief Channel minimum security level requirements */
|
||||
uint8_t role; /*!< \brief Channel initiator/acceptor role */
|
||||
} l2cCocReg_t;
|
||||
|
||||
/*! \brief Connection oriented channel connect indication structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Header structure */
|
||||
uint16_t cid; /*!< \brief Local channel ID */
|
||||
uint16_t peerMtu; /*!< \brief Data packet MTU peer can receive */
|
||||
uint16_t psm; /*!< \brief Connected PSM */
|
||||
} l2cCocConnectInd_t;
|
||||
|
||||
/*! \brief Connection oriented channel disconnect indication structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Header structure */
|
||||
uint16_t cid; /*!< \brief Local channel ID */
|
||||
uint16_t result; /*!< \brief Connection failure result code */
|
||||
} l2cCocDisconnectInd_t;
|
||||
|
||||
/*! \brief Connection oriented channel data indication structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Header structure */
|
||||
uint16_t cid; /*!< \brief Local channel ID */
|
||||
uint8_t *pData; /*!< \brief Pointer to packet data */
|
||||
uint16_t dataLen; /*!< \brief packet data length */
|
||||
} l2cCocDataInd_t;
|
||||
|
||||
/*! \brief Connection oriented channel disconnect indication structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Header structure */
|
||||
uint16_t cid; /*!< \brief Local channel ID */
|
||||
} l2cCocDataCnf_t;
|
||||
|
||||
/*!
|
||||
* \brief Connection oriented channel event structure
|
||||
*
|
||||
* Connection oriented channel callback header parameters:
|
||||
*
|
||||
* \param hdr.event Callback event
|
||||
* \param hdr.param DM connection ID
|
||||
* \param hdr.status Event status (L2C_COC_DATA_CNF only)
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Header structure */
|
||||
l2cCocConnectInd_t connectInd; /*!< \brief Channel connect indication */
|
||||
l2cCocDisconnectInd_t disconnectInd; /*!< \brief Channel disconnect indication */
|
||||
l2cCocDataInd_t dataInd; /*!< \brief Received data indication */
|
||||
l2cCocDataCnf_t dataCnf; /*!< \brief Transmit data confirm */
|
||||
} l2cCocEvt_t;
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t reqTimeout; /*!< \brief Request timeout in seconds */
|
||||
} l2cCfg_t;
|
||||
|
||||
/*! \} */ /* STACK_L2CAP_API */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables;
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \addtogroup STACK_INIT
|
||||
* \{ */
|
||||
|
||||
/** \name L2CAP Configuration Structure
|
||||
* Pointer to structure containing initialization details of the L2CAP Subsystem. To be configured
|
||||
* by Application.
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Configuration pointer */
|
||||
extern l2cCfg_t *pL2cCfg;
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_INIT */
|
||||
|
||||
/**************************************************************************************************
|
||||
Callback Function Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \addtogroup STACK_L2CAP_API
|
||||
* \{ */
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function sends a received L2CAP packet to the client.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*l2cDataCback_t)(uint16_t handle, uint16_t len, uint8_t *pPacket);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function sends control messages to the client.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*l2cCtrlCback_t)(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function sends data and other events to connection oriented
|
||||
* channels clients.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*l2cCocCback_t)(l2cCocEvt_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function is used for authoriztion of connection oriented channels.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param regId The registration instance requiring authorization.
|
||||
* \param psm The PSM of the registration instance.
|
||||
*
|
||||
* \return L2C_CONN_SUCCESS if authorization is successful, any other value for failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef uint16_t (*l2cCocAuthorCback_t)(dmConnId_t connId, l2cCocRegId_t regId, uint16_t psm);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name L2CAP Initialization
|
||||
* Initialization and registration functions
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C subsystem.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C for operation as a Bluetooth LE master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cMasterInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C for operation as a Bluetooth LE slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cSlaveInit(void);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP CID Functions
|
||||
* Register and send data over a CID
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief called by the L2C client, such as ATT or SMP, to register for the given CID.
|
||||
*
|
||||
* \param cid channel identifier.
|
||||
* \param dataCback Callback function for L2CAP data received for this CID.
|
||||
* \param ctrlCback Callback function for control events for this CID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cRegister(uint16_t cid, l2cDataCback_t dataCback, l2cCtrlCback_t ctrlCback);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an L2CAP data packet on the given CID.
|
||||
*
|
||||
* \param cid The channel identifier.
|
||||
* \param handle The connection handle. The client receives this handle from DM.
|
||||
* \param len The length of the payload data in pPacket.
|
||||
* \param pL2cPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDataReq(uint16_t cid, uint16_t handle, uint16_t len, uint8_t *pL2cPacket);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build and send a signaling packet.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param code Type of command.
|
||||
* \param len Length of the parameter.
|
||||
* \param pParam parameters of command to send.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDmSigReq(uint16_t handle, uint8_t code, uint16_t len, uint8_t *pParam);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP COC Functions
|
||||
* Connection Oriented Channels Functions
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C connection oriented channel subsystem.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register to use a connection oriented channel, as either a channel acceptor,
|
||||
* initiator, or both. If registering as channel acceptor then the PSM is specified.
|
||||
* After registering a connection can be established by the client using this
|
||||
* registration instance.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
* \param pReg Registration parameter structure.
|
||||
*
|
||||
* \return Registration instance ID or L2C_COC_REG_ID_NONE if registration failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
l2cCocRegId_t L2cCocRegister(l2cCocCback_t cback, l2cCocReg_t *pReg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Deregister and deallocate a connection oriented channel registration instance.
|
||||
* This function should only be called if there are no active channels using this
|
||||
* registration instance.
|
||||
*
|
||||
* \param regId Registration instance ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocDeregister(l2cCocRegId_t regId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate a connection to the given peer PSM.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param regId The associated registration instance.
|
||||
* \param psm Peer PSM.
|
||||
*
|
||||
* \return Local CID or L2C_COC_CID_NONE none if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t L2cCocConnectReq(dmConnId_t connId, l2cCocRegId_t regId, uint16_t psm);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Disconnect the channel for the given CID.
|
||||
*
|
||||
* \param cid Channel ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocDisconnectReq(uint16_t cid);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an L2CAP data packet on the given connection oriented CID.
|
||||
*
|
||||
* \param cid The local channel identifier.
|
||||
* \param len The length of the payload data in pPacket.
|
||||
* \param pPayload Packet payload data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocDataReq(uint16_t cid, uint16_t len, uint8_t *pPayload);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For testing purposes only.
|
||||
*
|
||||
* \param result Result code
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocErrorTest(uint16_t result);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For testing purposes only.
|
||||
*
|
||||
* \param cid The local channel identifier.
|
||||
* \param credits Credits to send.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocCreditSendTest(uint16_t cid, uint16_t credits);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Connection Parameter Update Functions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. This function is called by DM to send an L2CAP
|
||||
* connection update request.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param pConnSpec Pointer to the connection specification structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDmConnUpdateReq(uint16_t handle, hciConnSpec_t *pConnSpec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. This function is called by DM to send an L2CAP
|
||||
* connection update response.
|
||||
*
|
||||
* \param identifier Identifier value previously passed from L2C to DM.
|
||||
* \param handle The connection handle.
|
||||
* \param result Connection update response result.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDmConnUpdateRsp(uint8_t identifier, uint16_t handle, uint16_t result);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /*! STACK_L2CAP_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* L2C_API_H */
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP constants and definitions from the Bluetooth specification.
|
||||
*
|
||||
* 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 L2C_DEFS_H
|
||||
#define L2C_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_L2CAP_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name L2CAP Packet Constants
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_HDR_LEN 4 /*!< \brief L2CAP packet header length */
|
||||
#define L2C_MIN_MTU 23 /*!< \brief Minimum packet payload MTU for LE */
|
||||
#define L2C_SIG_HDR_LEN 4 /*!< \brief L2CAP signaling command header length */
|
||||
#define L2C_LE_SDU_HDR_LEN 2 /*!< \brief L2CAP LE SDU data header length */
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Start of L2CAP payload in an HCI ACL packet buffer */
|
||||
#define L2C_PAYLOAD_START (HCI_ACL_HDR_LEN + L2C_HDR_LEN)
|
||||
|
||||
/*! \brief L2CAP signaling packet base length, including HCI header */
|
||||
#define L2C_SIG_PKT_BASE_LEN (HCI_ACL_HDR_LEN + L2C_HDR_LEN + L2C_SIG_HDR_LEN)
|
||||
|
||||
/*! \brief L2CAP LE SDU packet base length, including HCI header */
|
||||
#define L2C_LE_SDU_PKT_BASE_LEN (HCI_ACL_HDR_LEN + L2C_HDR_LEN + L2C_LE_SDU_HDR_LEN)
|
||||
|
||||
/** \name L2CAP Parameter Lengths
|
||||
* Signaling packet parameter lengths
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_SIG_CONN_UPDATE_REQ_LEN 8 /*!< \brief Connection update request length. */
|
||||
#define L2C_SIG_CONN_UPDATE_RSP_LEN 2 /*!< \brief Connection update response length. */
|
||||
#define L2C_SIG_CMD_REJ_LEN 2 /*!< \brief Command reject length. */
|
||||
#define L2C_SIG_DISCONN_REQ_LEN 4 /*!< \brief Disconnection request length. */
|
||||
#define L2C_SIG_DISCONN_RSP_LEN 4 /*!< \brief Disconnection response length. */
|
||||
#define L2C_SIG_LE_CONN_REQ_LEN 10 /*!< \brief LE connection request length. */
|
||||
#define L2C_SIG_LE_CONN_RSP_LEN 10 /*!< \brief LE connection response length. */
|
||||
#define L2C_SIG_FLOW_CTRL_CREDIT_LEN 4 /*!< \brief Flow control credit lenghth. */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Connection Identifiers
|
||||
* BLE Defined Connection Identifiers (CID)
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_CID_ATT 0x0004 /*!< \brief CID for attribute protocol */
|
||||
#define L2C_CID_LE_SIGNALING 0x0005 /*!< \brief CID for LE signaling */
|
||||
#define L2C_CID_SMP 0x0006 /*!< \brief CID for security manager protocol */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Signaling Codes
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_SIG_CMD_REJ 0x01 /*!< \brief Comand reject */
|
||||
#define L2C_SIG_DISCONNECT_REQ 0x06 /*!< \brief Disconnect request */
|
||||
#define L2C_SIG_DISCONNECT_RSP 0x07 /*!< \brief Disconnect response */
|
||||
#define L2C_SIG_CONN_UPDATE_REQ 0x12 /*!< \brief Connection parameter update request */
|
||||
#define L2C_SIG_CONN_UPDATE_RSP 0x13 /*!< \brief Connection parameter update response */
|
||||
#define L2C_SIG_LE_CONNECT_REQ 0x14 /*!< \brief LE credit based connection request */
|
||||
#define L2C_SIG_LE_CONNECT_RSP 0x15 /*!< \brief LE credit based connection response */
|
||||
#define L2C_SIG_FLOW_CTRL_CREDIT 0x16 /*!< \brief LE flow control credit */
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Signaling response code flag */
|
||||
#define L2C_SIG_RSP_FLAG 0x01
|
||||
|
||||
/** \name L2CAP Command Rejection Codes
|
||||
* BLE defined Command rejection reason codes
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_REJ_NOT_UNDERSTOOD 0x0000 /*!< \brief Command not understood */
|
||||
#define L2C_REJ_MTU_EXCEEDED 0x0001 /*!< \brief Signaling MTU exceeded */
|
||||
#define L2C_REJ_INVALID_CID 0x0002 /*!< \brief Invalid CID in request */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Connection Parameter Update Result Codes
|
||||
* BLE defined result codes
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_CONN_PARAM_ACCEPTED 0x0000 /*!< \brief Connection parameters accepted */
|
||||
#define L2C_CONN_PARAM_REJECTED 0x0001 /*!< \brief Connection parameters rejected */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Connection Result Codes
|
||||
* BLE defined result codes
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_CONN_SUCCESS 0x0000 /*!< \brief Connection successful */
|
||||
#define L2C_CONN_NONE 0x0001 /*!< \brief No connection result value available */
|
||||
#define L2C_CONN_FAIL_PSM 0x0002 /*!< \brief Connection refused LE_PSM not supported */
|
||||
#define L2C_CONN_FAIL_RES 0x0004 /*!< \brief Connection refused no resources available */
|
||||
#define L2C_CONN_FAIL_AUTH 0x0005 /*!< \brief Connection refused insufficient authentication */
|
||||
#define L2C_CONN_FAIL_AUTHORIZ 0x0006 /*!< \brief Connection refused insufficient authorization */
|
||||
#define L2C_CONN_FAIL_KEY_SIZE 0x0007 /*!< \brief Connection refused insufficient encryption key size */
|
||||
#define L2C_CONN_FAIL_ENC 0x0008 /*!< \brief Connection Refused insufficient encryption */
|
||||
#define L2C_CONN_FAIL_INVALID_SCID 0x0009 /*!< \brief Connection refused invalid source CID */
|
||||
#define L2C_CONN_FAIL_ALLOCATED_SCID 0x000A /*!< \brief Connection refused source CID already allocated */
|
||||
#define L2C_CONN_FAIL_UNACCEPT_PARAM 0x000B /*!< \brief Connection refused unacceptable parameters */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Interal Connection Result Codes
|
||||
* Proprietary codes not sent in any L2CAP packet.
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_CONN_FAIL_TIMEOUT 0xF000 /*!< \brief Request timeout */
|
||||
/**@}*/
|
||||
|
||||
/** \name L2CAP Signaling Parameter Value Ranges
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define L2C_PSM_MIN 0x0001 /*!< \brief PSM minimum. */
|
||||
#define L2C_PSM_MAX 0x00FF /*!< \brief PSM maximum. */
|
||||
#define L2C_CID_DYN_MIN 0x0040 /*!< \brief CID dynamic minimum. */
|
||||
#define L2C_CID_DYN_MAX 0x007F /*!< \brief CID dynamic maximum. */
|
||||
#define L2C_MTU_MIN 0x0017 /*!< \brief MTU minimum. */
|
||||
#define L2C_MPS_MIN 0x0017 /*!< \brief MPS minimum. */
|
||||
#define L2C_MPS_MAX 0xFFFD /*!< \brief MPS maximum. */
|
||||
#define L2C_CREDITS_MAX 0xFFFF /*!< \brief Credits maximum. */
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /*! STACK_L2CAP_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* L2C_DEFS_H */
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP handler interface.
|
||||
*
|
||||
* 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 L2C_HANDLER_H
|
||||
#define L2C_HANDLER_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_EVENT
|
||||
* \{ */
|
||||
|
||||
/** \name L2CAP Event Handling
|
||||
* Message passing interface to L2CAP from other tasks through WSF.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Event handler initialization function for L2C when operating as a slave.
|
||||
*
|
||||
* \param handlerId ID for this event handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cSlaveHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief The WSF event handler for L2C when operating as a slave.
|
||||
*
|
||||
* \param event Event mask.
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cSlaveHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Event handler initialization function for L2C with connection oriented channels.
|
||||
*
|
||||
* \param handlerId ID for this event handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief The WSF event handler for L2C with connection oriented channels.
|
||||
*
|
||||
* \param event Event mask.
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cCocHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_EVENT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* L2C_HANDLER_H */
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief AES and random number security service API.
|
||||
*
|
||||
* Copyright (c) 2010-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef SEC_API_H
|
||||
#define SEC_API_H
|
||||
|
||||
#include "wsf_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_SECURITY_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief CMAC algorithm key length. */
|
||||
#define SEC_CMAC_KEY_LEN 16
|
||||
|
||||
/*! \brief CMAC algorithm result length. */
|
||||
#define SEC_CMAC_HASH_LEN 16
|
||||
|
||||
/*! \brief ECC algorithm key length. */
|
||||
#define SEC_ECC_KEY_LEN 32
|
||||
|
||||
/** \name CCM-Mode algorithm lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define SEC_CCM_KEY_LEN 16
|
||||
#define SEC_CCM_MAX_ADDITIONAL_LEN ((1<<16) - (1<<8))
|
||||
#define SEC_CCM_L 2
|
||||
#define SEC_CCM_NONCE_LEN (15-SEC_CCM_L)
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Invalid AES Token. */
|
||||
#define SEC_TOKEN_INVALID 0xFF
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief AES Security callback parameters structure. */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
uint8_t *pCiphertext; /*!< Pointer to 16 bytes of ciphertext data. */
|
||||
} secAes_t;
|
||||
|
||||
/*! \brief CMAC Security callback parameters structure. */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
uint8_t *pCiphertext; /*!< Pointer to 16 bytes of ciphertext data. */
|
||||
uint8_t *pPlainText; /*!< Pointer to pPlaintext parameter passed to SecCmac. */
|
||||
} secCmacMsg_t;
|
||||
|
||||
/*! \brief CCM-Mode encrypt callback parameters structure. */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
uint8_t *pCiphertext; /*!< Pointer to ciphertext data. */
|
||||
uint16_t textLen; /*!< Length of pCiphertext in bytes. */
|
||||
} secCcmEncMsg_t;
|
||||
|
||||
/*! \brief CCM-Mode decrypt and authenticate callback parameters structure. */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
uint8_t *pText; /*!< Pointer to decrypted text within result buffer. */
|
||||
uint8_t *pResult; /*!< Pointer to result buffer (passed into SecCcmDec). */
|
||||
uint16_t textLen; /*!< Length of pText in bytes. */
|
||||
bool_t success; /*!< TRUE if message is authenticated. */
|
||||
} secCcmDecMsg_t;
|
||||
|
||||
/*! \brief Generic security callback parameters structure. */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
secAes_t aes; /*!< AES complete message. */
|
||||
secCmacMsg_t cmac; /*!< CMAC complete message. */
|
||||
secCcmEncMsg_t ccmEnc; /*!< CCM-Mode Encrypt complete message. */
|
||||
secCcmDecMsg_t ccmDec; /*!< CCM-Mode Decrypt complete message. */
|
||||
} secMsg_t;
|
||||
|
||||
/*! \brief ECC Security public/private key pair. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t pubKey_x[SEC_ECC_KEY_LEN]; /*!< x component of ECC public key. */
|
||||
uint8_t pubKey_y[SEC_ECC_KEY_LEN]; /*!< y component of ECC public key. */
|
||||
uint8_t privKey[SEC_ECC_KEY_LEN]; /*!< ECC private key. */
|
||||
} secEccKey_t;
|
||||
|
||||
/*! \brief ECC security DH Key shared secret. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t secret[SEC_ECC_KEY_LEN]; /*!< DH Key Shared secret. */
|
||||
} secEccSharedSec_t;
|
||||
|
||||
|
||||
/*! \brief ECC Security callback parameters structure. */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header. */
|
||||
union
|
||||
{
|
||||
secEccSharedSec_t sharedSecret; /*!< Shared secret. */
|
||||
secEccKey_t key; /*!< ECC public/private key pair. */
|
||||
bool_t keyValid; /*!< TRUE if ECC public/private key pair is valid. */
|
||||
} data; /*!< ECC message data union. */
|
||||
} secEccMsg_t;
|
||||
|
||||
/*! \brief Block encryption function. */
|
||||
typedef void (*SecBlkEncFunc_t)(uint8_t *pKey, uint8_t *pMessage, void *pParam);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name Security Initialization Functions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the security service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the random number service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecRandInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the AES service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the AES (reverse) service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesRevInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize CMAC security. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCmacInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize CCM security.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCcmInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize ECC security. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccInit(void);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name Security AES, CMAC and CCM Functions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
|
||||
* sent to the specified handler. This function returns a token value that
|
||||
* the client can use to match calls to this function with messages.
|
||||
*
|
||||
* \param pKey Pointer to 16 byte key.
|
||||
* \param pPlaintext Pointer to 16 byte plaintext.
|
||||
* \param handlerId WSF handler ID.
|
||||
* \param param Client-defined parameter returned in message.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t SecAes(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
|
||||
* sent to the specified handler. This function returns a token value that
|
||||
* the client can use to match calls to this function with messages. Note this version
|
||||
* reverses the key and plaintext bytes.
|
||||
*
|
||||
* \param pKey Pointer to 16 byte key.
|
||||
* \param pPlaintext Pointer to 16 byte plaintext.
|
||||
* \param handlerId WSF handler ID.
|
||||
* \param param Client-defined parameter returned in message.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t SecAesRev(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the CMAC algorithm.
|
||||
*
|
||||
* \param pKey Key used in CMAC operation.
|
||||
* \param pPlaintext Plain text buffer - buffer must persist until secCmacMsg_t callback.
|
||||
* \param textLen Size of pPlaintext in bytes.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCmac(const uint8_t *pKey, uint8_t *pPlaintext, uint16_t textLen, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the CCM-Mode encryption algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pPlainText Pointer to text to encrypt.
|
||||
* \param textLen Length of pPlainText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
|
||||
wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the CCM-Mode verify and decrypt algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pCypherText Pointer to text to decrypt.
|
||||
* \param textLen Length of pCypherText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param pMic Pointer to authentication digest.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
|
||||
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name Security ECC Functions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param pKey ECC Key structure.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name Security Random Number Generator Functions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function returns up to 16 bytes of random data to a buffer provided by the
|
||||
* client.
|
||||
*
|
||||
* \param pRand Pointer to returned random data.
|
||||
* \param randLen Length of random data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecRand(uint8_t *pRand, uint8_t randLen);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_SECURITY_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SEC_API_H */
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP subsystem API.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef SMP_API_H
|
||||
#define SMP_API_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
#include "smp_defs.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_SMP_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name SMP Events
|
||||
* Events recognized and handled by the SMP state machine.
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Event handler messages for SMP state machines */
|
||||
enum
|
||||
{
|
||||
SMP_MSG_API_PAIR_REQ = 1, /*!< \brief API pairing request */
|
||||
SMP_MSG_API_PAIR_RSP, /*!< \brief API pairing response */
|
||||
SMP_MSG_API_CANCEL_REQ, /*!< \brief API cancel request */
|
||||
SMP_MSG_API_AUTH_RSP, /*!< \brief API pin response */
|
||||
SMP_MSG_API_SECURITY_REQ, /*!< \brief API security request */
|
||||
SMP_MSG_CMD_PKT, /*!< \brief SMP command packet received */
|
||||
SMP_MSG_CMD_PAIRING_FAILED, /*!< \brief SMP pairing failed packet received */
|
||||
SMP_MSG_DM_ENCRYPT_CMPL, /*!< \brief Link encrypted */
|
||||
SMP_MSG_DM_ENCRYPT_FAILED, /*!< \brief Link encryption failed */
|
||||
SMP_MSG_DM_CONN_CLOSE, /*!< \brief Connection closed */
|
||||
SMP_MSG_WSF_AES_CMPL, /*!< \brief AES calculation complete */
|
||||
SMP_MSG_INT_SEND_NEXT_KEY, /*!< \brief Send next key to be distributed */
|
||||
SMP_MSG_INT_MAX_ATTEMPTS, /*!< \brief Maximum pairing attempts reached */
|
||||
SMP_MSG_INT_PAIRING_CMPL, /*!< \brief Pairing complete */
|
||||
SMP_MSG_INT_RSP_TIMEOUT, /*!< \brief Pairing protocol response timeout */
|
||||
SMP_MSG_INT_WI_TIMEOUT, /*!< \brief Pairing protocol wait interval timeout */
|
||||
SMP_MSG_INT_LESC, /*!< \brief Pair with Secure Connections */
|
||||
SMP_MSG_INT_LEGACY, /*!< \brief Pair with Legacy Security */
|
||||
SMP_MSG_INT_JW_NC, /*!< \brief LESC Just-Works/Numeric Comparison pairing */
|
||||
SMP_MSG_INT_PASSKEY, /*!< \brief LESC Passkey pairing */
|
||||
SMP_MSG_INT_OOB, /*!< \brief LESC Out-of-Band Pairing */
|
||||
SMP_MSG_API_USER_CONFIRM, /*!< \brief User confirms valid numeric comparison */
|
||||
SMP_MSG_API_USER_KEYPRESS, /*!< \brief User keypress in passkey pairing */
|
||||
SMP_MSG_API_KEYPRESS_CMPL, /*!< \brief User keypress complete in passkey pairing */
|
||||
SMP_MSG_WSF_ECC_CMPL, /*!< \brief WSF ECC operation complete */
|
||||
SMP_MSG_INT_PK_NEXT, /*!< \brief Continue to next passkey bit */
|
||||
SMP_MSG_INT_PK_CMPL, /*!< \brief Passkey operation complete */
|
||||
SMP_MSG_WSF_CMAC_CMPL, /*!< \brief WSF CMAC operation complete */
|
||||
SMP_MSG_DH_CHECK_FAILURE, /*!< \brief DHKey check failure */
|
||||
SMP_MSG_EARLY_CNF, /*!< \brief An early Confirm from the initiator in passkey pairing */
|
||||
SMP_NUM_MSGS /*!< \brief Number of SMP message types. */
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/*! \brief Additional SMP messages */
|
||||
enum
|
||||
{
|
||||
SMP_DB_SERVICE_IND = SMP_NUM_MSGS /*!< \brief SMP DB Service timer indication */
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t attemptTimeout; /*!< \brief 'Repeated attempts' timeout in msec */
|
||||
uint8_t ioCap; /*!< \brief I/O Capability */
|
||||
uint8_t minKeyLen; /*!< \brief Minimum encryption key length */
|
||||
uint8_t maxKeyLen; /*!< \brief Maximum encryption key length */
|
||||
uint8_t maxAttempts; /*!< \brief Attempts to trigger 'repeated attempts' timeout */
|
||||
uint8_t auth; /*!< \brief Device authentication requirements */
|
||||
uint32_t maxAttemptTimeout; /*!< \brief Maximum 'Repeated attempts' timeout in msec */
|
||||
uint32_t attemptDecTimeout; /*!< \brief Time msec before attemptExp decreases */
|
||||
uint16_t attemptExp; /*!< \brief Exponent to raise attemptTimeout on maxAttempts */
|
||||
} smpCfg_t;
|
||||
|
||||
/*! \brief Data type for SMP_MSG_API_PAIR_REQ and SMP_MSG_API_PAIR_RSP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Message header */
|
||||
uint8_t oob; /*!< \brief Out-of-band data present flag */
|
||||
uint8_t auth; /*!< \brief authentication flags */
|
||||
uint8_t iKeyDist; /*!< \brief Initiator key distribution flags */
|
||||
uint8_t rKeyDist; /*!< \brief Responder key distribution flags */
|
||||
} smpDmPair_t;
|
||||
|
||||
/*! \brief Data type for SMP_MSG_API_AUTH_RSP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Message header */
|
||||
uint8_t authData[SMP_OOB_LEN]; /*!< \brief Authentication data to display */
|
||||
uint8_t authDataLen; /*!< \brief Length of authentication data */
|
||||
} smpDmAuthRsp_t;
|
||||
|
||||
/*! \brief Data type for SMP_MSG_API_USER_KEYPRESS */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Message header */
|
||||
uint8_t keypress; /*!< \brief Keypress */
|
||||
} smpDmKeypress_t;
|
||||
|
||||
/*! \brief Data type for SMP_MSG_API_SECURITY_REQ */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Message header */
|
||||
uint8_t auth; /*!< \brief Authentication flags */
|
||||
} smpDmSecurityReq_t;
|
||||
|
||||
/*! \brief Union SMP DM message data types */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< \brief Message header */
|
||||
smpDmPair_t pair; /*!< \brief Pairing request/response message */
|
||||
smpDmAuthRsp_t authRsp; /*!< \brief Authentication message */
|
||||
smpDmSecurityReq_t securityReq; /*!< \brief Security Request message */
|
||||
smpDmKeypress_t keypress; /*!< \brief Keypress message */
|
||||
} smpDmMsg_t;
|
||||
|
||||
/*! \} */ /* STACK_SMP_API */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables;
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \addtogroup STACK_INIT
|
||||
* \{ */
|
||||
|
||||
/** \name SMP Configuration Structure
|
||||
* Pointer to structure containing initialization details of the SMP Subsystem. To be configured
|
||||
* by Application.
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Configuration pointer */
|
||||
extern smpCfg_t *pSmpCfg;
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_INIT */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \addtogroup STACK_SMP_API
|
||||
* \{ */
|
||||
|
||||
/** \name SMP Initialization Functions
|
||||
* Legacy and Secure Connections initialization for Initiator and Responder roles.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP initiator role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpiInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP responder role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmprInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP initiator role utilizing BTLE Secure Connections.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpiScInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP responder role utilizing BTLE Secure Connections.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmprScInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Use this SMP init function when SMP is not supported.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpNonInit(void);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP DM Interface Functions
|
||||
* Functions that allow the DM to send messages to SMP.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by DM to send a message to SMP.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDmMsgSend(smpDmMsg_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by DM to notify SMP of encrypted link status.
|
||||
*
|
||||
* \param pMsg Pointer to HCI message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDmEncryptInd(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the STK for the given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pSecLevel Returns the security level of pairing when STK was created.
|
||||
*
|
||||
* \return Pointer to STK or NULL if not available.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpDmGetStk(dmConnId_t connId, uint8_t *pSecLevel);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Format a cancel message with consideration for the attempts counter
|
||||
*
|
||||
* \param connId Connection Id.
|
||||
* \param pHdr Pointer to header of message to fill.
|
||||
* \param status Status to include.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScGetCancelMsgWithReattempt(dmConnId_t connId, wsfMsgHdr_t *pHdr, uint8_t status);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the SMP Database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to force the DhKey to zero for qualification test purposes.
|
||||
*
|
||||
* \param enable TRUE - Force DhKey to zero. FALSE - Use calculated key
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScEnableZeroDhKey(bool_t enable);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_SMP_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMP_API_H */
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Security manager constants and definitions from the Bluetooth specification.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef SMP_DEFS_H
|
||||
#define SMP_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_SMP_API
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief PDU format */
|
||||
#define SMP_HDR_LEN 1 /*!< \brief Attribute PDU header length. */
|
||||
|
||||
/*! \brief Protocol timeout */
|
||||
#define SMP_TIMEOUT 30 /*!< \brief Protocol timeout in seconds. */
|
||||
|
||||
/** \name SMP Encryption Key Size
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_KEY_SIZE_MAX 16 /*!< \brief Maximum encryption key size. */
|
||||
#define SMP_KEY_SIZE_MIN 7 /*!< \brief Minimum encryption key size. */
|
||||
/**@}*/
|
||||
|
||||
#define SMP_OOB_LEN 16 /*!< \brief OOB Data length in bytes. */
|
||||
#define SMP_PIN_LEN 3 /*!< \brief Passkey Pin lenght in bytes. */
|
||||
|
||||
/** \name SMP Error Codes
|
||||
* SMP PDU status codes
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_ERR_PASSKEY_ENTRY 0x01 /*!< \brief User input of passkey failed. */
|
||||
#define SMP_ERR_OOB 0x02 /*!< \brief OOB data is not available. */
|
||||
#define SMP_ERR_AUTH_REQ 0x03 /*!< \brief Authentication requirements cannot be met. */
|
||||
#define SMP_ERR_CONFIRM_VALUE 0x04 /*!< \brief Confirm value does not match. */
|
||||
#define SMP_ERR_PAIRING_NOT_SUP 0x05 /*!< \brief Pairing is not supported by the device. */
|
||||
#define SMP_ERR_ENC_KEY_SIZE 0x06 /*!< \brief Insufficient encryption key size. */
|
||||
#define SMP_ERR_COMMAND_NOT_SUP 0x07 /*!< \brief Command not supported. */
|
||||
#define SMP_ERR_UNSPECIFIED 0x08 /*!< \brief Unspecified reason. */
|
||||
#define SMP_ERR_ATTEMPTS 0x09 /*!< \brief Repeated attempts. */
|
||||
#define SMP_ERR_INVALID_PARAM 0x0A /*!< \brief Invalid parameter or command length. */
|
||||
#define SMP_ERR_DH_KEY_CHECK 0x0B /*!< \brief DH Key check did not match. */
|
||||
#define SMP_ERR_NUMERIC_COMPARISON 0x0C /*!< \brief Numeric comparison did not match. */
|
||||
#define SMP_ERR_BR_EDR_IN_PROGRESS 0x0D /*!< \brief BR/EDR in progress. */
|
||||
#define SMP_ERR_CROSS_TRANSPORT 0x0E /*!< \brief BR/EDR cross transport key generation not allowed. */
|
||||
/**@}*/
|
||||
|
||||
/** \name Proprietary Error Codes
|
||||
* Internal error codes not sent in any SMP PDU.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_ERR_MEMORY 0xE0 /*!< \brief Out of memory. */
|
||||
#define SMP_ERR_TIMEOUT 0xE1 /*!< \brief Transaction timeout. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP PDU Codes
|
||||
* SMP PDU Code describing command received or sent.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_CMD_PAIR_REQ 0x01 /*!< \brief Pairing request. */
|
||||
#define SMP_CMD_PAIR_RSP 0x02 /*!< \brief Pairing response. */
|
||||
#define SMP_CMD_PAIR_CNF 0x03 /*!< \brief Pairing confirm. */
|
||||
#define SMP_CMD_PAIR_RAND 0x04 /*!< \brief Pairing random. */
|
||||
#define SMP_CMD_PAIR_FAIL 0x05 /*!< \brief Pairing failed. */
|
||||
#define SMP_CMD_ENC_INFO 0x06 /*!< \brief Encryption information. */
|
||||
#define SMP_CMD_MASTER_ID 0x07 /*!< \brief Master identification. */
|
||||
#define SMP_CMD_ID_INFO 0x08 /*!< \brief Identity information. */
|
||||
#define SMP_CMD_ID_ADDR_INFO 0x09 /*!< \brief Identity address information. */
|
||||
#define SMP_CMD_SIGN_INFO 0x0A /*!< \brief Signing information. */
|
||||
#define SMP_CMD_SECURITY_REQ 0x0B /*!< \brief Security fequest. */
|
||||
#define SMP_CMD_PUBLIC_KEY 0x0C /*!< \brief Public Kkey. */
|
||||
#define SMP_CMD_DHKEY_CHECK 0x0D /*!< \brief DH Key check. */
|
||||
#define SMP_CMD_KEYPRESS 0x0E /*!< \brief User key press. */
|
||||
#define SMP_CMD_MAX 0x0F /*!< \brief Command code maximum. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP PDU Packet Lengths
|
||||
* Fixed length of the PDU to be sent.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_PAIR_REQ_LEN 7 /*!< \brief Pairing request message length. */
|
||||
#define SMP_PAIR_RSP_LEN 7 /*!< \brief Pairing response message length. */
|
||||
#define SMP_PAIR_CNF_LEN 17 /*!< \brief Pairing confirmation message length. */
|
||||
#define SMP_PAIR_RAND_LEN 17 /*!< \brief Pairing random message length. */
|
||||
#define SMP_PAIR_FAIL_LEN 2 /*!< \brief Pairing fail message length. */
|
||||
#define SMP_ENC_INFO_LEN 17 /*!< \brief Encryption information message length. */
|
||||
#define SMP_MASTER_ID_LEN 11 /*!< \brief Master identification messagelength. */
|
||||
#define SMP_ID_INFO_LEN 17 /*!< \brief Identity information message length. */
|
||||
#define SMP_ID_ADDR_INFO_LEN 8 /*!< \brief Identity address information message length. */
|
||||
#define SMP_SIGN_INFO_LEN 17 /*!< \brief Signing information message length. */
|
||||
#define SMP_SECURITY_REQ_LEN 2 /*!< \brief Security request message length. */
|
||||
#define SMP_PUB_KEY_MSG_LEN (1 + 2*SMP_PUB_KEY_LEN) /*!< \brief Public key message length. */
|
||||
#define SMP_DHKEY_CHECK_MSG_LEN (1 + SMP_DHKEY_CHECK_LEN) /*!< \brief Diffie-Hellman key check message length. */
|
||||
#define SMP_KEYPRESS_MSG_LEN 2 /*!< \brief Keypress message length. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP I/O Capabilities
|
||||
* I/O capabilities codes to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_IO_DISP_ONLY 0x00 /*!< \brief Display only. */
|
||||
#define SMP_IO_DISP_YES_NO 0x01 /*!< \brief Display yes/no. */
|
||||
#define SMP_IO_KEY_ONLY 0x02 /*!< \brief Keyboard only. */
|
||||
#define SMP_IO_NO_IN_NO_OUT 0x03 /*!< \brief No input, no output. */
|
||||
#define SMP_IO_KEY_DISP 0x04 /*!< \brief Keyboard display. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP OOB Data Flag
|
||||
* Out-of-Band codes to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_OOB_DATA_NONE 0x00 /*!< \brief No OOB data from the remote device is present. */
|
||||
#define SMP_OOB_DATA_PRESENT 0x01 /*!< \brief OOB data from the remote device is present. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP Authentication Requirements Flags
|
||||
* Authentication Requirements Flags to be set for \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_AUTH_BOND_MASK 0x03 /*!< \brief Mask for bonding bits. */
|
||||
#define SMP_AUTH_BOND_FLAG 0x01 /*!< \brief Bonding requested. */
|
||||
#define SMP_AUTH_MITM_FLAG 0x04 /*!< \brief MITM (authenticated pairing) requested. */
|
||||
#define SMP_AUTH_SC_FLAG 0x08 /*!< \brief LE Secure Connections requested. */
|
||||
#define SMP_AUTH_KP_FLAG 0x10 /*!< \brief Keypress notifications requested. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP Key Distribution Flags
|
||||
* Flags of security keys this device is requesting to be distribution once pairing completes.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_KEY_DIST_ENC 0x01 /*!< \brief Distribute LTK. */
|
||||
#define SMP_KEY_DIST_ID 0x02 /*!< \brief Distribute IRK. */
|
||||
#define SMP_KEY_DIST_SIGN 0x04 /*!< \brief Distribute CSRK. */
|
||||
/*! \brief Key distribution mask. */
|
||||
#define SMP_KEY_DIST_MASK (SMP_KEY_DIST_ENC | SMP_KEY_DIST_ID | SMP_KEY_DIST_SIGN)
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP LE Secure Connection Keypress Codes
|
||||
* Keypress codes found in \ref SMP_CMD_KEYPRESS PDU to be sent on the respective action when
|
||||
* the \ref SMP_AUTH_KP_FLAG is set in both the \ref SMP_CMD_PAIR_REQ and \ref SMP_CMD_PAIR_RSP.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_PASSKEY_ENTRY_STARTED 0x00 /*!< \brief Passkey entry started keypress type. */
|
||||
#define SMP_PASSKEY_DIGIT_ENTERED 0x01 /*!< \brief Passkey digit entered keypress type. */
|
||||
#define SMP_PASSKEY_DIGIT_ERASED 0x02 /*!< \brief Passkey digit erased keypress type. */
|
||||
#define SMP_PASSKEY_CLEARED 0x03 /*!< \brief Passkey cleared keypress type. */
|
||||
#define SMP_PASSKEY_ENTRY_COMPLETED 0x04 /*!< \brief Passkey entry complete keypress type. */
|
||||
/**@}*/
|
||||
|
||||
/** \name SMP Value Length Constants
|
||||
* Lengths of various keys and values.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_RAND_LEN 16 /*!< \brief Random number length. */
|
||||
#define SMP_CONFIRM_LEN 16 /*!< \brief Confirm number length. */
|
||||
#define SMP_KEY_LEN 16 /*!< \brief Key length. */
|
||||
#define SMP_RAND8_LEN 8 /*!< \brief Random 8-byte number length. */
|
||||
#define SMP_PRIVATE_KEY_LEN 32 /*!< \brief Secure connections private key length. */
|
||||
#define SMP_PUB_KEY_LEN 32 /*!< \brief Secure connecdtions public key length. */
|
||||
#define SMP_DHKEY_LEN 32 /*!< \brief Secure connection Diffie-Hellman key length. */
|
||||
#define SMP_DHKEY_CHECK_LEN 16 /*!< \brief Secure connection Diffie-Hellman key check length. */
|
||||
/**@}*/
|
||||
|
||||
/** \name CMAC Input Lengths Constants
|
||||
* Input lengths of SMP cryptopgraphic toolbox functions.
|
||||
*/
|
||||
/**@{*/
|
||||
#define SMP_F4_TEXT_LEN (SMP_PUB_KEY_LEN * 2 + 1) /*!< \brief F4 input length. */
|
||||
#define SMP_G2_TEXT_LEN (SMP_PUB_KEY_LEN * 2 + SMP_RAND_LEN) /*!< \brief G2 input length. */
|
||||
#define SMP_F5_TKEY_TEXT_LEN (SMP_DHKEY_LEN) /*!< \brief F5 Temporary key input length. */
|
||||
#define SMP_F5_TEXT_LEN (9 + 2*BDA_ADDR_LEN + 2*SMP_RAND_LEN) /*!< \brief F5 input length. */
|
||||
#define SMP_F6_TEXT_LEN (2*BDA_ADDR_LEN + 3*SMP_RAND_LEN + 5) /*!< \brief F6 input length. */
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_SMP_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMP_DEFS_H */
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Interface to SMP event handler.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef SMP_HANDLER_H
|
||||
#define SMP_HANDLER_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_EVENT
|
||||
* \{ */
|
||||
|
||||
/** \name SMP Event Handling
|
||||
* Message passing interface to SMP from other tasks through WSF.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief SMP handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerId WSF handler ID for SMP.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for SMP.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* STACK_SMP_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMP_HANDLER_H */
|
||||
+1354
File diff suppressed because it is too large
Load Diff
+88
@@ -0,0 +1,88 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_apollo3.h
|
||||
//!
|
||||
//! @brief Support functions for the Nationz BTLE radio in Apollo3.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_APOLLO3_H
|
||||
#define HCI_DRV_APOLLO3_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// NATIONZ vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
|
||||
// Tx power level in dBm.
|
||||
typedef enum
|
||||
{
|
||||
TX_POWER_LEVEL_MINUS_10P0_dBm = 0x3,
|
||||
TX_POWER_LEVEL_0P0_dBm = 0x8,
|
||||
TX_POWER_LEVEL_PLUS_3P0_dBm = 0xF,
|
||||
TX_POWER_LEVEL_INVALID = 0x10,
|
||||
}txPowerLevel_t;
|
||||
|
||||
|
||||
bool_t HciVsA3_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
|
||||
void HciVsA3_ConstantTransmission(uint8_t txchannel);
|
||||
void HciVsA3_CarrierWaveMode(uint8_t txchannel);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Hci driver functions unique to Apollo3
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
extern void HciDrvHandlerInit(wsfHandlerId_t handlerId);
|
||||
extern void HciDrvIntService(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_DRV_APOLLO3_H
|
||||
+565
@@ -0,0 +1,565 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv.c
|
||||
//!
|
||||
//! @brief HCI driver interface.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_cs.h"
|
||||
#include "hci_defs.h"
|
||||
#include "hci_drv.h"
|
||||
#include "hci_drv_apollo.h"
|
||||
#include "hci_tr_apollo.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_util.h"
|
||||
#include "am_devices_em9304.h"
|
||||
#include "hci_drv_em9304.h"
|
||||
#include "em9304_patches.h"
|
||||
#include "em9304_init.h"
|
||||
#include "hci_apollo_config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Unless the config file overwrites this option, the HCI driver will use a
|
||||
// direct call to the HAL when it needs to sleep.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_SLEEP
|
||||
#define HCI_DRV_SLEEP am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP)
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// If the config file doesn't say anything about MAC addresses, use a EM Microelectronic
|
||||
// assigned BD address by default .
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_APOLLO_MAC
|
||||
#define HCI_APOLLO_MAC {0x01, 0x00, 0x00, 0xEE, 0xF3, 0x0C}
|
||||
#endif
|
||||
|
||||
// HCI_APOLLO_USE_CUSTOMER_OWN_MAC should be defined to true if customer
|
||||
// supply their own BD address.
|
||||
|
||||
#ifndef HCI_APOLLO_USE_CUSTOMER_OWN_MAC
|
||||
#define HCI_APOLLO_USE_CUSTOMER_OWN_MAC false
|
||||
#endif
|
||||
|
||||
uint8_t radio_boot_complete = 0;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Mac address for the EM.
|
||||
//
|
||||
//*****************************************************************************
|
||||
static uint8_t g_pui8BLEMacAddress[6] = HCI_APOLLO_MAC;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// HCI RX packet buffer for EM9304 Driver.
|
||||
//
|
||||
//*****************************************************************************
|
||||
static uint32_t g_pui32HCIRXBuffer[64];
|
||||
static uint32_t g_ui32HCIPacketSize;
|
||||
static uint8_t g_consumed_bytes;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Static record of the EM9304 vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
g_EMVSEvent_t g_EMVendorSpecificEvents = {0,0,0,0,0,0,0};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Workaround for Keil memcpy()
|
||||
//
|
||||
// Keil's version of memcpy() contains an optimization that allows it to copy
|
||||
// data more efficiently when both the source and destination pointers are well
|
||||
// aligned. Unforunately, some of exactLE's complex callback structures confuse
|
||||
// Keil's memcpy implementation. Left unchecked, this can lead to intermittent
|
||||
// hard-faults.
|
||||
//
|
||||
// This function definition will intercept calls to this optimized version of
|
||||
// memcpy and avoid the problem when the pointers are unexpectedly unaligned.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#if defined(__ARMCC_VERSION)
|
||||
|
||||
void $Super$$__aeabi_memcpy4(void *dest, const void *src, size_t n);
|
||||
|
||||
void
|
||||
$Sub$$__aeabi_memcpy4(void *dest, const void *src, size_t n)
|
||||
{
|
||||
//
|
||||
// If the pointers are aligned, we can use Keil's normal memcpy.
|
||||
//
|
||||
if ((((uint32_t)dest % 4) == 0) && (((uint32_t)src % 4) == 0))
|
||||
{
|
||||
$Super$$__aeabi_memcpy4(dest, src, n);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, make sure we use 8-bit pointers.
|
||||
//
|
||||
uint8_t *tempSrc = (uint8_t *)(src);
|
||||
uint8_t *tempDest = (uint8_t *)(dest);
|
||||
|
||||
//
|
||||
// Copy from src to dest, one byte at a time.
|
||||
//
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
*tempDest++ = *tempSrc++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Get the EM9304 vendor specific event counters.
|
||||
//!
|
||||
//! @return Returns a pointer to the EM9304 vendor specific event counters.
|
||||
//
|
||||
//*****************************************************************************
|
||||
g_EMVSEvent_t *getEM9304VSEventCounters(void)
|
||||
{
|
||||
return &g_EMVendorSpecificEvents;
|
||||
}
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Write data the driver.
|
||||
//!
|
||||
//! @param type HCI packet type
|
||||
//! @param len Number of bytes to write
|
||||
//! @param pData Byte array to write
|
||||
//!
|
||||
//! @return Returns the number of bytes written.
|
||||
//
|
||||
//*****************************************************************************
|
||||
uint16_t
|
||||
hciDrvWrite(uint8_t type, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
//
|
||||
// Turn on the IOM for this operation.
|
||||
//
|
||||
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
|
||||
|
||||
//
|
||||
// Write the HCI packet.
|
||||
//
|
||||
am_devices_em9304_block_write(&g_sEm9304, type, pData, len );
|
||||
|
||||
//
|
||||
// Disable IOM SPI pins and turn off the IOM after operation
|
||||
//
|
||||
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// hciDrvReadyToSleep - Stub provided to allow other layers to run correctly.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool_t
|
||||
hciDrvReadyToSleep(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool_t
|
||||
HciDataReadyISR(void)
|
||||
{
|
||||
//
|
||||
// If the radio boot has not yet completed, then do not process HCI packets
|
||||
if (!radio_boot_complete)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// check if there's pending HCI data from last time
|
||||
if (g_ui32HCIPacketSize > g_consumed_bytes)
|
||||
{
|
||||
g_consumed_bytes += hciTrSerialRxIncoming(
|
||||
((uint8_t *)g_pui32HCIRXBuffer) + g_consumed_bytes,
|
||||
g_ui32HCIPacketSize - g_consumed_bytes);
|
||||
|
||||
if (g_consumed_bytes == g_ui32HCIPacketSize) {
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Turn on the IOM for this operation.
|
||||
//
|
||||
am_devices_em9304_spi_awake(g_sEm9304.ui32IOMModule);
|
||||
|
||||
g_ui32HCIPacketSize = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
|
||||
|
||||
// Check for EM9304 Vendor Specific events and record them.
|
||||
if ( (g_ui32HCIPacketSize > 3) && (0x0001FF04 == (g_pui32HCIRXBuffer[0] & 0x00FFFFFF)) )
|
||||
{
|
||||
switch((g_pui32HCIRXBuffer[0] & 0xFF000000) >> 24)
|
||||
{
|
||||
case 0x01:
|
||||
g_EMVendorSpecificEvents.EM_ActiveStateEntered++;
|
||||
am_util_debug_printf("Received EM_ActiveStateEntered Event\n");
|
||||
break;
|
||||
case 0x03:
|
||||
g_EMVendorSpecificEvents.EM_TestModeEntered++;
|
||||
am_util_debug_printf("Received EM_TestModeEntered Event\n");
|
||||
break;
|
||||
case 0x04:
|
||||
g_EMVendorSpecificEvents.EM_HalNotification++;
|
||||
am_util_debug_printf("Received EM_HalNotification Event\n");
|
||||
break;
|
||||
default:
|
||||
am_util_debug_printf("Received Unknown Vendor Specific Event from EM9304\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the packet size to 0 so that this packet will not be processed by the host stack.
|
||||
//
|
||||
g_ui32HCIPacketSize = 0;
|
||||
}
|
||||
|
||||
if (g_ui32HCIPacketSize > 0)
|
||||
{
|
||||
g_consumed_bytes += hciTrSerialRxIncoming((uint8_t *)g_pui32HCIRXBuffer, g_ui32HCIPacketSize);
|
||||
if (g_consumed_bytes == g_ui32HCIPacketSize) {
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Disable IOM SPI pins and turn off the IOM after operation
|
||||
//
|
||||
am_devices_em9304_spi_sleep(g_sEm9304.ui32IOMModule);
|
||||
|
||||
return (g_ui32HCIPacketSize == 0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Configure the necessary pins and start the EM9304 radio.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
HciDrvRadioBoot(uint32_t ui32UartModule)
|
||||
{
|
||||
uint32_t patch_dest_memory = DEST_MEMORY_IRAM;
|
||||
|
||||
uint32_t ui32PN;
|
||||
|
||||
// disable interrupt during EM9304 initialization.
|
||||
am_devices_em9304_disable_interrupt();
|
||||
|
||||
radio_boot_complete = 0;
|
||||
|
||||
//
|
||||
// Enable the radio pins.
|
||||
//
|
||||
#ifdef HCI_APOLLO_POWER_PIN
|
||||
|
||||
//
|
||||
// Insert a power on reset to TLSR8269
|
||||
// (with TLSR8269 EVK, this is only done via power pin)
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_POWER_PIN, HCI_APOLLO_POWER_CFG);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_POWER_PIN);
|
||||
am_util_delay_ms(100);
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_POWER_PIN);
|
||||
am_util_delay_ms(100);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Device identification
|
||||
//
|
||||
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
|
||||
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
|
||||
|
||||
// Currently only enable this for Apollo2-Blue
|
||||
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
|
||||
{
|
||||
am_hal_gpio_pin_config(30, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(30);
|
||||
am_hal_gpio_pin_config(35, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(35);
|
||||
am_hal_gpio_pin_config(36, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(36);
|
||||
|
||||
}
|
||||
//
|
||||
// Assert RESET to the EM9304 device.
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
//
|
||||
// Setup SPI interface for EM9304
|
||||
//
|
||||
am_devices_em9304_config_pins();
|
||||
am_devices_em9304_spi_init(g_sEm9304.ui32IOMModule, &g_sEm9304IOMConfigSPI);
|
||||
|
||||
//
|
||||
// Enable the IOM and GPIO interrupt handlers.
|
||||
//
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
//
|
||||
// Delay for 20ms to make sure the em device gets ready for commands.
|
||||
//
|
||||
am_util_delay_ms(20);
|
||||
|
||||
//
|
||||
// Initialize the EM9304.
|
||||
//
|
||||
patch_dest_memory = initEM9304();
|
||||
|
||||
//
|
||||
// Delay for 20ms to make sure the em device completes initialization.
|
||||
//
|
||||
am_util_delay_ms(20);
|
||||
|
||||
if (patch_dest_memory == DEST_MEMORY_OTP)
|
||||
{
|
||||
|
||||
//
|
||||
// Completed the patching process by cycling RESET to the EM9304 device.
|
||||
//
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
am_util_delay_ms(20);
|
||||
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
// delay here to make sure EM9304 is ready for operation after
|
||||
// patch is loaded.
|
||||
am_util_delay_ms(20);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Set the MAC address if customer provides their own BD address
|
||||
//
|
||||
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
|
||||
{
|
||||
//
|
||||
// currently just use the default one, customer either update g_pui8BLEMacAddress
|
||||
// directly or call HciDrvAssignBDAddress() with a pointer of assigned BD address.
|
||||
HciDrvAssignBDAddress(g_pui8BLEMacAddress);
|
||||
}
|
||||
|
||||
// Initialization of the EM9304 is complete.
|
||||
radio_boot_complete = 1;
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
am_util_debug_printf("HciDrvRadioBoot complete\n");
|
||||
|
||||
// enable interrupt after EM9304 initialization is done.
|
||||
am_devices_em9304_enable_interrupt();
|
||||
}
|
||||
|
||||
void
|
||||
HciDrvRadioShutdown(void)
|
||||
{
|
||||
uint32_t ui32PN;
|
||||
|
||||
radio_boot_complete = 0;
|
||||
g_ui32HCIPacketSize = 0;
|
||||
g_consumed_bytes = 0;
|
||||
|
||||
am_devices_em9304_disable_interrupt();
|
||||
AM_HAL_GPIO_MASKCREATE(GpioIntMask);
|
||||
am_hal_gpio_int_clear(AM_HAL_GPIO_MASKBIT(pGpioIntMask, AM_BSP_GPIO_EM9304_INT));
|
||||
|
||||
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_CS, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_CS);
|
||||
|
||||
am_hal_clkgen_clkout_disable();
|
||||
|
||||
//
|
||||
// Device identification
|
||||
//
|
||||
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
|
||||
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
|
||||
|
||||
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
|
||||
{
|
||||
// Currently clear pin 24 only for Apollo2-Blue
|
||||
am_hal_gpio_pin_config(24, AM_HAL_PIN_24_CLKOUT);
|
||||
am_hal_gpio_out_bit_clear(24);
|
||||
}
|
||||
|
||||
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
|
||||
|
||||
|
||||
am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_INT, AM_HAL_PIN_OUTPUT);
|
||||
am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_INT);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsSetRfPowerLevelEx
|
||||
*
|
||||
* \brief Vendor-specific command for settting Radio transmit power level
|
||||
* for EM9304.
|
||||
*
|
||||
* \param txPowerlevel valid range from 0 to 17 in decimal.
|
||||
*
|
||||
* \return true when success, otherwise false
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel)
|
||||
{
|
||||
// make sure it's 8 bit
|
||||
uint8_t tx_power_level = (uint8_t)txPowerlevel;
|
||||
|
||||
if(tx_power_level < TX_POWER_LEVEL_INVALID) {
|
||||
HciVendorSpecificCmd(0xFC26, sizeof(tx_power_level), &tx_power_level);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsEM_TransmitterTest
|
||||
*
|
||||
* \brief Vendor-specific command for start transmitter testing
|
||||
*
|
||||
* \param test_mode refer to em9304 datasheet
|
||||
* \param channel_number refer to em9304 datasheet
|
||||
* \param packet_len refer to em9304 datasheet
|
||||
* \param packet_payload_type refer to em9304 datasheet
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type)
|
||||
{
|
||||
uint8_t params[4] = {
|
||||
test_mode,
|
||||
channel_number,
|
||||
packet_len,
|
||||
packet_payload_type
|
||||
};
|
||||
|
||||
HciVendorSpecificCmd(0xFC11, sizeof(params), ¶ms[0]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsEM_TransmitterTestEnd
|
||||
*
|
||||
* \brief Vendor-specific command for ending Radio transmitter testing.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsEM_TransmitterTestEnd(void)
|
||||
{
|
||||
HciVendorSpecificCmd(0xFC12, 0, NULL);
|
||||
}
|
||||
|
||||
void HciVsEM_ReadAtAddress(uint32_t addr)
|
||||
{
|
||||
uint8_t ReadAtAddress[5];
|
||||
|
||||
// only read 4 bytes
|
||||
memcpy(ReadAtAddress, &addr, 4);
|
||||
ReadAtAddress[4] = 4;
|
||||
HciVendorSpecificCmd(0xFC20, sizeof(ReadAtAddress), ReadAtAddress);
|
||||
}
|
||||
|
||||
void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value)
|
||||
{
|
||||
uint8_t WriteAtAddress[8];
|
||||
|
||||
// only write 4 bytes
|
||||
memcpy(WriteAtAddress, &addr, 4);
|
||||
memcpy(WriteAtAddress+4, &value, 4);
|
||||
HciVendorSpecificCmd(0xFC22, sizeof(WriteAtAddress), WriteAtAddress);
|
||||
}
|
||||
|
||||
void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address)
|
||||
{
|
||||
if (customer_unique_bd_address)
|
||||
{
|
||||
memcpy(g_pui8BLEMacAddress, customer_unique_bd_address, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void HciVsEM_SetBDAddress(void)
|
||||
{
|
||||
if (HCI_APOLLO_USE_CUSTOMER_OWN_MAC)
|
||||
{
|
||||
HciVendorSpecificCmd(0xFC02, 6, g_pui8BLEMacAddress);
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_em9304.h
|
||||
//!
|
||||
//! @brief Support functions for the EM Micro EM9304 BTLE radio.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#ifndef HCI_DRV_EM9304_H
|
||||
#define HCI_DRV_EM9304_H
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// EM9304 vendor specific events
|
||||
//
|
||||
//*****************************************************************************
|
||||
typedef struct
|
||||
{
|
||||
uint32_t EM_ActiveStateEntered;
|
||||
uint32_t EM_TestModeEntered;
|
||||
uint32_t EM_HalNotification;
|
||||
uint32_t EM_DebugPrint;
|
||||
uint32_t EM_DebugStackUsage;
|
||||
uint32_t EM_DebugBacktrace;
|
||||
uint32_t EM_DebugAssert;
|
||||
} g_EMVSEvent_t;
|
||||
|
||||
// Tx power level in dBm.
|
||||
typedef enum
|
||||
{
|
||||
TX_POWER_LEVEL_MINOR_33P5_dBm, // 0, not compliant with BT spec
|
||||
TX_POWER_LEVEL_MINOR_29P0_dBm, // 1, not compliant with BT spec
|
||||
TX_POWER_LEVEL_MINOR_17P9_dBm, // 2
|
||||
TX_POWER_LEVEL_MINOR_16P4_dBm, // 3
|
||||
TX_POWER_LEVEL_MINOR_14P6_dBm, // 4
|
||||
TX_POWER_LEVEL_MINOR_13P1_dBm, // 5
|
||||
TX_POWER_LEVEL_MINOR_11P4_dBm, // 6
|
||||
TX_POWER_LEVEL_MINOR_9P9_dBm, // 7
|
||||
TX_POWER_LEVEL_MINOR_8P4_dBm, // 8
|
||||
TX_POWER_LEVEL_MINOR_6P9_dBm, // 9
|
||||
TX_POWER_LEVEL_MINOR_5P5_dBm, // 10
|
||||
TX_POWER_LEVEL_MINOR_4P0_dBm, // 11
|
||||
TX_POWER_LEVEL_MINOR_2P6_dBm, // 12
|
||||
TX_POWER_LEVEL_MINOR_1P4_dBm, // 13
|
||||
TX_POWER_LEVEL_PLUS_0P4_dBm, // 14
|
||||
TX_POWER_LEVEL_PLUS_2P5_dBm, // 15
|
||||
TX_POWER_LEVEL_PLUS_4P6_dBm, // 16
|
||||
TX_POWER_LEVEL_PLUS_6P2_dBm, // 17
|
||||
TX_POWER_LEVEL_INVALID
|
||||
}txPowerLevel_t;
|
||||
|
||||
extern g_EMVSEvent_t *getEM9304VSEventCounters(void);
|
||||
extern uint32_t HciVsEM_SetRfPowerLevelEx(txPowerLevel_t txPowerlevel);
|
||||
extern void HciVsEM_TransmitterTest(uint8_t test_mode, uint8_t channel_number, uint8_t packet_len, uint8_t packet_payload_type);
|
||||
extern void HciVsEM_TransmitterTestEnd(void);
|
||||
extern void HciVsEM_ReadAtAddress(uint32_t addr);
|
||||
extern void HciVsEM_WriteAtAddress(uint32_t addr, uint32_t value);
|
||||
extern void HciDrvAssignBDAddress(uint8_t * customer_unique_bd_address);
|
||||
extern void HciVsEM_SetBDAddress(void);
|
||||
|
||||
|
||||
#endif // HCI_DRV_EM9304_H
|
||||
+1626
File diff suppressed because it is too large
Load Diff
Vendored
+703
@@ -0,0 +1,703 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Advertising Extensions (AE) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set advertising set random device address command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pAddr Random device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetAdvSetRandAddrCmd(uint8_t advHandle, const uint8_t *pAddr)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_ADV_SET_RAND_ADDR, HCI_LEN_LE_SET_ADV_SET_RAND_ADDR)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
BDA_TO_BSTREAM(p, pAddr);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising parameters command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pExtAdvParam Extended advertising parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvParamCmd(uint8_t advHandle, hciExtAdvParam_t *pExtAdvParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_PARAM, HCI_LEN_LE_SET_EXT_ADV_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT16_TO_BSTREAM(p, pExtAdvParam->advEventProp);
|
||||
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMin);
|
||||
UINT24_TO_BSTREAM(p, pExtAdvParam->priAdvInterMax);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvChanMap);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->peerAddrType);
|
||||
BDA_TO_BSTREAM(p, pExtAdvParam->pPeerAddr);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advFiltPolicy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advTxPwr);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->priAdvPhy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvMaxSkip);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->secAdvPhy);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->advSetId);
|
||||
UINT8_TO_BSTREAM(p, pExtAdvParam->scanReqNotifEna);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param fragPref Fragment preference.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Advertising data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
|
||||
const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_EXT_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_EXT_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_DATA, HCI_LEN_LE_SET_EXT_ADV_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, fragPref);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended scan response data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param fragPref Fragment preference.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Scan response data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtScanRespDataCmd(uint8_t advHandle, uint8_t op, uint8_t fragPref, uint8_t len,
|
||||
const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_EXT_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_EXT_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_RESP_DATA,
|
||||
HCI_LEN_LE_SET_EXT_SCAN_RESP_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, fragPref);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended advertising enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
|
||||
* \param numSets Number of advertising sets.
|
||||
* \param pScanParam Advertising enable parameter array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtAdvEnableCmd(uint8_t enable, uint8_t numSets, hciExtAdvEnableParam_t *pEnableParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_ADV_ENABLE, HCI_LEN_LE_EXT_ADV_ENABLE(numSets))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, numSets);
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pEnableParam[i].advHandle);
|
||||
UINT16_TO_BSTREAM(p, pEnableParam[i].duration);
|
||||
UINT8_TO_BSTREAM(p, pEnableParam[i].maxEaEvents);
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read maximum advertising data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadMaxAdvDataLen(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN, HCI_LEN_LE_READ_MAX_ADV_DATA_LEN)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read number of supported advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadNumSupAdvSets(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS, HCI_LEN_LE_READ_NUM_OF_SUP_ADV_SETS)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE remove advertising set command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return Status error code.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeRemoveAdvSet(uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_ADV_SET, HCI_LEN_LE_REMOVE_ADV_SET)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE clear advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeClearAdvSets(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_ADV_SETS, HCI_LEN_LE_CLEAR_ADV_SETS)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising parameters command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advIntervalMin Periodic advertising interval minimum.
|
||||
* \param advIntervalMax Periodic advertising interval maximum.
|
||||
* \param advProps Periodic advertising properties.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvParamCmd(uint8_t advHandle, uint16_t advIntervalMin, uint16_t advIntervalMax,
|
||||
uint16_t advProps)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_PARAM, HCI_LEN_LE_SET_PER_ADV_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT16_TO_BSTREAM(p, advIntervalMin);
|
||||
UINT16_TO_BSTREAM(p, advIntervalMax);
|
||||
UINT16_TO_BSTREAM(p, advProps);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising data command.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Operation.
|
||||
* \param len Data buffer length.
|
||||
* \param pData Advertising data buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvDataCmd(uint8_t advHandle, uint8_t op, uint8_t len, const uint8_t *pData)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if (len > HCI_PER_ADV_DATA_LEN)
|
||||
{
|
||||
len = HCI_PER_ADV_DATA_LEN;
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_DATA, HCI_LEN_LE_SET_PER_ADV_DATA(len))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT8_TO_BSTREAM(p, len);
|
||||
memcpy(p, pData, len);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable advertising, FALSE to disable advertising.
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvEnableCmd(uint8_t enable, uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_ENABLE, HCI_LEN_LE_SET_PER_ADV_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set extended scanning parameters command.
|
||||
*
|
||||
* \param ownAddrType Address type used by this device.
|
||||
* \param scanFiltPolicy Scan filter policy.
|
||||
* \param scanPhys Scanning PHYs.
|
||||
* \param pScanParam Scanning parameter array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetExtScanParamCmd(uint8_t ownAddrType, uint8_t scanFiltPolicy, uint8_t scanPhys,
|
||||
hciExtScanParam_t *pScanParam)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t numPhys;
|
||||
|
||||
/* find out number of scanning PHYs */
|
||||
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
numPhys++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_PARAM, HCI_LEN_LE_SET_EXT_SCAN_PARAM(numPhys))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, scanFiltPolicy);
|
||||
UINT8_TO_BSTREAM(p, scanPhys);
|
||||
|
||||
for (i = 0; i < numPhys; i++)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pScanParam[i].scanType);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow)
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE extended scan enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable scanning, FALSE to disable scanning.
|
||||
* \param filterDup Set to TRUE to filter duplicates.
|
||||
* \param duration Duration.
|
||||
* \param period Period.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeExtScanEnableCmd(uint8_t enable, uint8_t filterDup, uint16_t duration, uint16_t period)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_EXT_SCAN_ENABLE, HCI_LEN_LE_SET_EXT_SCAN_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT8_TO_BSTREAM(p, filterDup);
|
||||
UINT16_TO_BSTREAM(p, duration);
|
||||
UINT16_TO_BSTREAM(p, period);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE extended create connection command.
|
||||
*
|
||||
* \param pInitParam Initiating parameters.
|
||||
* \param pScanParam Initiating scan parameters.
|
||||
* \param pConnSpec Connection specification.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeExtCreateConnCmd(hciExtInitParam_t *pInitParam, hciExtInitScanParam_t *pScanParam,
|
||||
hciConnSpec_t *pConnSpec)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t numPhys;
|
||||
|
||||
/* find out number of initiating PHYs */
|
||||
for (i = 0, numPhys = 0; (i < 8) && (numPhys <= HCI_MAX_NUM_PHYS); i++)
|
||||
{
|
||||
if (pInitParam->initPhys & (1 << i))
|
||||
{
|
||||
numPhys++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_EXT_CREATE_CONN, HCI_LEN_LE_EXT_CREATE_CONN(numPhys))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, pInitParam->filterPolicy);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->ownAddrType);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->peerAddrType);
|
||||
BDA_TO_BSTREAM(p, pInitParam->pPeerAddr);
|
||||
UINT8_TO_BSTREAM(p, pInitParam->initPhys);
|
||||
|
||||
for (i = 0; i < numPhys; i++)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanInterval);
|
||||
UINT16_TO_BSTREAM(p, pScanParam[i].scanWindow);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMin);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connIntervalMax);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].connLatency);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].supTimeout);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].minCeLen);
|
||||
UINT16_TO_BSTREAM(p, pConnSpec[i].maxCeLen);
|
||||
}
|
||||
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising create sync command.
|
||||
*
|
||||
* \param options Options.
|
||||
* \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.
|
||||
* \param unused Reserved for future use (must be zero).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvCreateSyncCmd(uint8_t options, uint8_t advSid, uint8_t advAddrType,
|
||||
uint8_t *pAdvAddr, uint16_t skip, uint16_t syncTimeout, uint8_t unused)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC, HCI_LEN_LE_PER_ADV_CREATE_SYNC)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, options);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, unused);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising create sync cancel command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvCreateSyncCancelCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_CREATE_SYNC_CANCEL, HCI_LEN_LE_PER_ADV_CREATE_SYNC_CANCEL)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising terminate sync command.
|
||||
*
|
||||
* \param syncHandle Sync handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvTerminateSyncCmd(uint16_t syncHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_TERMINATE_SYNC, HCI_LEN_LE_PER_ADV_TERMINATE_SYNC)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE add device to periodic advertiser list command.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeAddDeviceToPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_ADD_DEV_PER_ADV_LIST, HCI_LEN_LE_ADD_DEV_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE remove device from periodic advertiser list command.
|
||||
*
|
||||
* \param advAddrType Advertiser address type.
|
||||
* \param pAdvAddr Advertiser address.
|
||||
* \param advSid Advertising SID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeRemoveDeviceFromPerAdvListCmd(uint8_t advAddrType, uint8_t *pAdvAddr, uint8_t advSid)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_REMOVE_DEV_PER_ADV_LIST, HCI_LEN_LE_REMOVE_DEV_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, advAddrType);
|
||||
BDA_TO_BSTREAM(p, pAdvAddr);
|
||||
UINT8_TO_BSTREAM(p, advSid);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE clear periodic advertiser list command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeClearPerAdvListCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CLEAR_PER_ADV_LIST, HCI_LEN_LE_CLEAR_PER_ADV_LIST)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read periodic advertiser size command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadPerAdvListSizeCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE, HCI_LEN_LE_READ_PER_ADV_LIST_SIZE)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read transmit power command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadTxPower(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_TX_POWER, HCI_LEN_LE_READ_TX_POWER)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read RF path compensation command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadRfPathComp(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_RF_PATH_COMP, HCI_LEN_LE_READ_RF_PATH_COMP)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE write RF path compensation command.
|
||||
*
|
||||
* \param txPathComp RF transmit path compensation value.
|
||||
* \param rxPathComp RF receive path compensation value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeWriteRfPathComp(int16_t txPathComp, int16_t rxPathComp)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_WRITE_RF_PATH_COMP, HCI_LEN_LE_WRITE_RF_PATH_COMP)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, txPathComp);
|
||||
UINT16_TO_BSTREAM(p, rxPathComp);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+165
@@ -0,0 +1,165 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Constant Tone Extension (CTE) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set connection CTE receive parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param samplingEnable TRUE to enable Connection IQ sampling, FALSE to disable it.
|
||||
* \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 HciLeSetConnCteRxParamsCmd(uint16_t connHandle, uint8_t samplingEnable, uint8_t slotDurations,
|
||||
uint8_t switchPatternLen, uint8_t *pAntennaIDs)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_RX_PARAMS,
|
||||
HCI_LEN_LE_SET_CONN_CTE_RX_PARAMS(switchPatternLen))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, samplingEnable);
|
||||
UINT8_TO_BSTREAM(p, slotDurations);
|
||||
UINT8_TO_BSTREAM(p, switchPatternLen);
|
||||
memcpy(p, pAntennaIDs, switchPatternLen);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set connection CTE transmit parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \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 HciLeSetConnCteTxParamsCmd(uint16_t connHandle, uint8_t cteTypeBits, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_CONN_CTE_TX_PARAMS,
|
||||
HCI_LEN_LE_SET_CONN_CTE_TX_PARAMS(switchPatternLen))) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, cteTypeBits);
|
||||
UINT8_TO_BSTREAM(p, switchPatternLen);
|
||||
memcpy(p, pAntennaIDs, switchPatternLen);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE connection CTE request enable command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param enable TRUE to enable CTE request for connection, FALSE to disable it.
|
||||
* \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 HciLeConnCteReqEnableCmd(uint16_t connHandle, uint8_t enable, uint16_t cteReqInt,
|
||||
uint8_t reqCteLen, uint8_t reqCteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_REQ_ENABLE,
|
||||
HCI_LEN_LE_CONN_CTE_REQ_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
UINT16_TO_BSTREAM(p, cteReqInt);
|
||||
UINT8_TO_BSTREAM(p, reqCteLen);
|
||||
UINT8_TO_BSTREAM(p, reqCteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE connection CTE response enable command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param enable TRUE to enable CTE response for connection, FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeConnCteRspEnableCmd(uint16_t connHandle, uint8_t enable)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_CONN_CTE_RSP_ENABLE,
|
||||
HCI_LEN_LE_CONN_CTE_RSP_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE read antenna information command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadAntennaInfoCmd(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_ANTENNA_INFO, HCI_LEN_LE_READ_ANTENNA_INFO)) != NULL)
|
||||
{
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+171
@@ -0,0 +1,171 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI Periodic Advertising Sync Transfer (PAST) command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising receive enable command.
|
||||
*
|
||||
* \param syncHandle Periodic sync handle.
|
||||
* \param enable TRUE to enable reports, FALSE to disable reports.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvRcvEnableCmd(uint16_t syncHandle, uint8_t enable)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PER_ADV_RCV_ENABLE,
|
||||
HCI_LEN_LE_SET_PER_ADV_RCV_ENABLE)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
UINT8_TO_BSTREAM(p, enable);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE periodic advertising sync transfer command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param serviceData Service data provided by the host.
|
||||
* \param syncHandle Periodic sync handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvSyncTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint16_t syncHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SYNC_TRANSFER,
|
||||
HCI_LEN_LE_PER_ADV_SYNC_TRANSFER)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT16_TO_BSTREAM(p, serviceData);
|
||||
UINT16_TO_BSTREAM(p, syncHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising set info transfer command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param serviceData Service data provided by the host.
|
||||
* \param advHandle Handle to identify an advertising set.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLePerAdvSetInfoTrsfCmd(uint16_t connHandle, uint16_t serviceData, uint8_t advHandle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_PER_ADV_SET_INFO_TRANSFER,
|
||||
HCI_LEN_LE_PER_ADV_SET_INFO_TRANSFER)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT16_TO_BSTREAM(p, serviceData);
|
||||
UINT8_TO_BSTREAM(p, advHandle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set periodic advertising sync transfer parameters command.
|
||||
*
|
||||
* \param connHandle Connection handle.
|
||||
* \param mode Periodic sync advertising sync transfer mode.
|
||||
* \param skip The number of periodic advertising packets that can be skipped after
|
||||
* a successful receive.
|
||||
* \param syncTimeout Synchronization timeout for the periodic advertising.
|
||||
* \param cteType Constant tone extension type(Used in AoD/AoA).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPerAdvSyncTrsfParamsCmd(uint16_t connHandle, uint8_t mode, uint16_t skip,
|
||||
uint16_t syncTimeout, uint8_t cteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PAST_PARAM, HCI_LEN_LE_SET_PAST_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, connHandle);
|
||||
UINT8_TO_BSTREAM(p, mode);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, cteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI LE set default periodic advertising sync transfer parameters command.
|
||||
*
|
||||
* \param mode Periodic sync advertising sync transfer mode.
|
||||
* \param skip The number of periodic advertising packets that can be skipped after
|
||||
* a successful receive.
|
||||
* \param syncTimeout Synchronization timeout for the periodic advertising.
|
||||
* \param cteType Constant tone extension type(Used in AoD/AoA).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetDefaultPerAdvSyncTrsfParamsCmd(uint8_t mode, uint16_t skip, uint16_t syncTimeout,
|
||||
uint8_t cteType)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEFAULT_PAST_PARAM,
|
||||
HCI_LEN_LE_SET_DEFAULT_PAST_PARAM)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, mode);
|
||||
UINT16_TO_BSTREAM(p, skip);
|
||||
UINT16_TO_BSTREAM(p, syncTimeout);
|
||||
UINT8_TO_BSTREAM(p, cteType);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI PHY command module.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI read PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeReadPhyCmd(uint16_t handle)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_READ_PHY, HCI_LEN_LE_READ_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI set default PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetDefaultPhyCmd(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_DEF_PHY, HCI_LEN_LE_SET_DEF_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT8_TO_BSTREAM(p, allPhys);
|
||||
UINT8_TO_BSTREAM(p, txPhys);
|
||||
UINT8_TO_BSTREAM(p, rxPhys);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI set PHY command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciLeSetPhyCmd(uint16_t handle, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pBuf = hciCmdAlloc(HCI_OPCODE_LE_SET_PHY, HCI_LEN_LE_SET_PHY)) != NULL)
|
||||
{
|
||||
p = pBuf + HCI_CMD_HDR_LEN;
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT8_TO_BSTREAM(p, allPhys);
|
||||
UINT8_TO_BSTREAM(p, txPhys);
|
||||
UINT8_TO_BSTREAM(p, rxPhys);
|
||||
UINT16_TO_BSTREAM(p, phyOptions);
|
||||
hciCmdSend(pBuf);
|
||||
}
|
||||
}
|
||||
+924
@@ -0,0 +1,924 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core.c
|
||||
*
|
||||
* \brief HCI core module, platform independent functions.
|
||||
*
|
||||
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
|
||||
* $Revision: 11501 $
|
||||
*
|
||||
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "l2c_defs.h"
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default ACL buffer flow control watermark levels */
|
||||
#ifndef HCI_ACL_QUEUE_HI
|
||||
#define HCI_ACL_QUEUE_HI 5 /* Disable flow when this many buffers queued */
|
||||
#endif
|
||||
#ifndef HCI_ACL_QUEUE_LO
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
#define HCI_ACL_QUEUE_LO 3 /* Enable flow when this many buffers queued */
|
||||
#else
|
||||
#define HCI_ACL_QUEUE_LO 1 /* Enable flow when this many buffers queued */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Default maximum ACL packet size for reassembly */
|
||||
#ifndef HCI_MAX_RX_ACL_LEN
|
||||
#define HCI_MAX_RX_ACL_LEN HCI_ACL_DEFAULT_LEN
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Event mask */
|
||||
const uint8_t hciEventMask[HCI_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_DISCONNECT_CMPL | /* Byte 0 */
|
||||
HCI_EVT_MASK_ENC_CHANGE, /* Byte 0 */
|
||||
HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_HW_ERROR, /* Byte 1 */
|
||||
0, /* Byte 2 */
|
||||
HCI_EVT_MASK_DATA_BUF_OVERFLOW, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
HCI_EVT_MASK_LE_META /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE event mask */
|
||||
const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_LE_CONN_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_ADV_REPORT_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_LTK_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL, /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT, /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_ADV_SET_TERM_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* event mask page 2 */
|
||||
const uint8_t hciEventMaskPage2[HCI_EVT_MASK_PAGE_2_LEN] =
|
||||
{
|
||||
0, /* Byte 0 */
|
||||
0, /* Byte 1 */
|
||||
HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE supported features configuration mask */
|
||||
uint32_t hciLeSupFeatCfg =
|
||||
HCI_LE_SUP_FEAT_ENCRYPTION | /* LE Encryption */
|
||||
HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC | /* Connection Parameters Request Procedure */
|
||||
HCI_LE_SUP_FEAT_EXT_REJECT_IND | /* Extended Reject Indication */
|
||||
HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH | /* Slave-initiated Features Exchange */
|
||||
HCI_LE_SUP_FEAT_LE_PING | /* LE Ping */
|
||||
HCI_LE_SUP_FEAT_DATA_LEN_EXT | /* LE Data Packet Length Extension */
|
||||
HCI_LE_SUP_FEAT_PRIVACY | /* LL Privacy */
|
||||
HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY | /* Extended Scanner Filter Policies */
|
||||
HCI_LE_SUP_FEAT_LE_2M_PHY | /* LE 2M PHY supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER | /* Stable Modulation Index - Transmitter supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER | /* Stable Modulation Index - Receiver supported */
|
||||
HCI_LE_SUP_FEAT_LE_EXT_ADV | /* LE Extended Advertising */
|
||||
HCI_LE_SUP_FEAT_LE_PER_ADV; /* LE Periodic Advertising */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
hciCoreCb_t hciCoreCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnAlloc
|
||||
*
|
||||
* \brief Allocate a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnAlloc(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == HCI_HANDLE_NONE)
|
||||
{
|
||||
/* allocate and initialize */
|
||||
pConn->handle = handle;
|
||||
pConn->flowDisabled = FALSE;
|
||||
pConn->outBufs = 0;
|
||||
pConn->queuedBufs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN0("HCI conn struct alloc failure");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnFree
|
||||
*
|
||||
* \brief Free a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnFree(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreConnFree handle not found:%u", handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnByHandle
|
||||
*
|
||||
* \brief Get a connection structure by handle
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreNextConnFragment
|
||||
*
|
||||
* \brief Get the next connection structure with a packet fragment to send.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hciCoreConn_t *hciCoreNextConnFragment(void)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle != HCI_HANDLE_NONE && pConn->fragmenting)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnOpen
|
||||
*
|
||||
* \brief Perform internal processing on HCI connection open.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnOpen(uint16_t handle)
|
||||
{
|
||||
/* allocate connection structure */
|
||||
hciCoreConnAlloc(handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreConnClose
|
||||
*
|
||||
* \brief Perform internal processing on HCI connection close.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnClose(uint16_t handle)
|
||||
{
|
||||
/* free connection structure */
|
||||
hciCoreConnFree(handle);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreSendAclData
|
||||
*
|
||||
* \brief Send ACL data to transport.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* increment outstanding buf count for handle */
|
||||
pConn->outBufs++;
|
||||
|
||||
/* send to transport */
|
||||
hciTrSendAclData(pConn, pData);
|
||||
|
||||
/* decrement available buffer count */
|
||||
if (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN0("hciCoreSendAclData availBufs=0");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxReady
|
||||
*
|
||||
* \brief Service the TX data path.
|
||||
*
|
||||
* \param bufs Number of new buffers now available.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxReady(uint8_t bufs)
|
||||
{
|
||||
uint8_t *pData;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* increment available buffers, with ceiling */
|
||||
if (bufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs += bufs;
|
||||
if (hciCoreCb.availBufs > hciCoreCb.numBufs)
|
||||
{
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
}
|
||||
}
|
||||
|
||||
/* service ACL data queue and send as many buffers as we can */
|
||||
while (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send continuation of any fragments first */
|
||||
if (hciCoreTxAclContinue(NULL) == FALSE)
|
||||
{
|
||||
/* if no fragments then check for any queued ACL data */
|
||||
if ((pData = WsfMsgDeq(&hciCoreCb.aclQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up conn structure and send data */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
/* handle not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreTxReady discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragments or queued data to send; we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclStart
|
||||
*
|
||||
* \brief Send ACL packets, start of packet.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param len ACL packet length.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
uint16_t hciLen;
|
||||
|
||||
/* make sure not already fragmenting on this connection */
|
||||
WSF_ASSERT(pConn->fragmenting == FALSE);
|
||||
|
||||
hciLen = HciGetBufSize();
|
||||
|
||||
HCI_TRACE_INFO1("hciCoreTxAclStart len=%u", len);
|
||||
|
||||
/* if acl len > controller acl buf len */
|
||||
if (len > hciLen)
|
||||
{
|
||||
/* store remaining acl len = acl len - hci acl buf len */
|
||||
pConn->txAclRemLen = len - hciLen;
|
||||
|
||||
/* store position for next fragment */
|
||||
pConn->pNextTxFrag = pData + hciLen;
|
||||
|
||||
/* store information required for fragmentation */
|
||||
pConn->pTxAclPkt = pData;
|
||||
pConn->fragmenting = TRUE;
|
||||
|
||||
/* set acl len in packet to hci acl buf len */
|
||||
UINT16_TO_BUF(&pData[2], hciLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
|
||||
/* send additional fragments while there are HCI buffers available */
|
||||
while ((hciCoreCb.availBufs > 0) && hciCoreTxAclContinue(pConn));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragmentation, just send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclContinue
|
||||
*
|
||||
* \brief Send ACL packets, continuation of fragmented packets.
|
||||
*
|
||||
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
|
||||
* sent from this connection structure. If NULL the function finds the next
|
||||
* connection structure with a fragment to be sent.
|
||||
*
|
||||
* \return TRUE if packet sent, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn)
|
||||
{
|
||||
uint16_t aclLen;
|
||||
|
||||
if (pConn == NULL)
|
||||
{
|
||||
pConn = hciCoreNextConnFragment();
|
||||
}
|
||||
|
||||
if (pConn != NULL)
|
||||
{
|
||||
/* get next fragment length */
|
||||
aclLen = (pConn->txAclRemLen < HciGetBufSize()) ? pConn->txAclRemLen : HciGetBufSize();
|
||||
|
||||
if (aclLen > 0)
|
||||
{
|
||||
/* decrement remaining length */
|
||||
pConn->txAclRemLen -= aclLen;
|
||||
|
||||
/* set handle in packet with continuation bit set */
|
||||
UINT16_TO_BUF(pConn->pNextTxFrag, (pConn->handle | HCI_PB_CONTINUE));
|
||||
|
||||
/* set acl len in packet */
|
||||
UINT16_TO_BUF(&(pConn->pNextTxFrag[2]), aclLen);
|
||||
|
||||
HCI_TRACE_INFO2("hciCoreTxAclContinue aclLen=%u remLen=%u", aclLen, pConn->txAclRemLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pConn->pNextTxFrag);
|
||||
|
||||
/* set up pointer to next fragment */
|
||||
if (pConn->txAclRemLen > 0)
|
||||
{
|
||||
pConn->pNextTxFrag += aclLen;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclComplete
|
||||
*
|
||||
* \brief This function is called from the HCI transport layer when transmission of an ACL
|
||||
* packet is complete.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* if fragmenting */
|
||||
if (pConn->fragmenting)
|
||||
{
|
||||
/* check if all fragments sent */
|
||||
if (pConn->txAclRemLen == 0)
|
||||
{
|
||||
/* free original buffer */
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
pConn->fragmenting = FALSE;
|
||||
HCI_TRACE_INFO0("hciCoreTxAclComplete free pTxAclPkt");
|
||||
}
|
||||
}
|
||||
else if (pData != NULL)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreAclReassembly
|
||||
*
|
||||
* \brief Reassemble an ACL packet.
|
||||
*
|
||||
* \param pData Input ACL packet.
|
||||
*
|
||||
* \return pointer to ACL packet to send, or NULL if no packet to send.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCoreAclReassembly(uint8_t *pData)
|
||||
{
|
||||
hciCoreConn_t *pConn;
|
||||
uint8_t *pDataRtn = NULL;
|
||||
uint16_t handle;
|
||||
uint16_t aclLen;
|
||||
uint16_t l2cLen;
|
||||
uint16_t pbf;
|
||||
bool_t freeData = TRUE;
|
||||
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
pbf = handle & HCI_PB_FLAG_MASK;
|
||||
handle &= HCI_HANDLE_MASK;
|
||||
BYTES_TO_UINT16(aclLen, &pData[2]);
|
||||
|
||||
/* look up connection */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if this is a start packet */
|
||||
if (pbf == HCI_PB_START_C2H)
|
||||
{
|
||||
/* if currently reassembled packet not complete */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
/* discard currently reassembled packet */
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
HCI_TRACE_WARN1("disarded hci rx pkt handle=0x%04x", handle);
|
||||
}
|
||||
|
||||
/* read l2cap length */
|
||||
if (aclLen >= L2C_HDR_LEN)
|
||||
{
|
||||
BYTES_TO_UINT16(l2cLen, &pData[4]);
|
||||
|
||||
/* check length vs. configured maximum */
|
||||
if ((l2cLen + L2C_HDR_LEN) > hciCoreCb.maxRxAclLen)
|
||||
{
|
||||
HCI_TRACE_WARN1("l2c len=0x%04x to large for reassembly", l2cLen);
|
||||
}
|
||||
/* if reassembly required */
|
||||
else if ((l2cLen + L2C_HDR_LEN) > aclLen)
|
||||
{
|
||||
/* allocate buffer to store complete l2cap packet */
|
||||
if ((pConn->pRxAclPkt = WsfMsgDataAlloc(l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN, 0)) != NULL)
|
||||
{
|
||||
/* store buffer for reassembly */
|
||||
pConn->pNextRxFrag = pConn->pRxAclPkt;
|
||||
|
||||
/* build acl header and copy data */
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, handle);
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, l2cLen + L2C_HDR_LEN);
|
||||
memcpy(pConn->pNextRxFrag, &pData[4], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* store remaining length */
|
||||
pConn->rxAclRemLen = l2cLen + L2C_HDR_LEN - aclLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* alloc failed; discard */
|
||||
HCI_TRACE_WARN1("reassembly alloc failed len=%u", (l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no reassembly required, pData is ready to go */
|
||||
pDataRtn = pData;
|
||||
freeData = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid l2cap packet; discard */
|
||||
HCI_TRACE_WARN1("invalid l2c pkt aclLen=%u", aclLen);
|
||||
}
|
||||
}
|
||||
/* else if this is a continuation packet */
|
||||
else if (pbf == HCI_PB_CONTINUE)
|
||||
{
|
||||
/* if expecting a continuation */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
if (aclLen <= pConn->rxAclRemLen)
|
||||
{
|
||||
/* copy data to start of next fragment */
|
||||
memcpy(pConn->pNextRxFrag, &pData[HCI_ACL_HDR_LEN], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* update remaining length */
|
||||
pConn->rxAclRemLen -= aclLen;
|
||||
|
||||
/* if reassembly complete return reassembled packet */
|
||||
if (pConn->rxAclRemLen == 0)
|
||||
{
|
||||
pDataRtn = pConn->pRxAclPkt;
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN2("continuation pkt too long len=%u RemLen=%u", aclLen, pConn->rxAclRemLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unexpected continuation pkt handle=0x%04x", handle);
|
||||
}
|
||||
}
|
||||
/* else unknown packet type */
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unknown pb flags=0x%04x", pbf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* connection not found */
|
||||
HCI_TRACE_WARN1("pkt rcvd on unknown handle=0x%04x", (handle & HCI_HANDLE_MASK));
|
||||
}
|
||||
|
||||
if (freeData)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
|
||||
return pDataRtn;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreTxAclDataFragmented
|
||||
*
|
||||
* \brief Check if a TX ACL packet is being fragmented.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
*
|
||||
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn)
|
||||
{
|
||||
return pConn->fragmenting;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciCoreInit
|
||||
*
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
WSF_QUEUE_INIT(&hciCoreCb.aclQueue);
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
hciCoreCb.conn[i].handle = HCI_HANDLE_NONE;
|
||||
}
|
||||
|
||||
hciCoreCb.maxRxAclLen = HCI_MAX_RX_ACL_LEN;
|
||||
hciCoreCb.aclQueueHi = HCI_ACL_QUEUE_HI;
|
||||
hciCoreCb.aclQueueLo = HCI_ACL_QUEUE_LO;
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
if (APOLLO3_GE_B0)
|
||||
{
|
||||
// B0 has only less internal ACL buffers
|
||||
hciCoreCb.aclQueueHi--;
|
||||
hciCoreCb.aclQueueLo--;
|
||||
}
|
||||
#endif
|
||||
hciCoreCb.extResetSeq = NULL;
|
||||
|
||||
hciCoreInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciResetSequence
|
||||
*
|
||||
* \brief Initiate an HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciResetSequence(void)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
wsfHandlerId_t handlerId;
|
||||
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
// free any pending incoming packets
|
||||
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* Free buffer */
|
||||
WsfMsgFree(pBuf);
|
||||
}
|
||||
|
||||
HCI_TRACE_INFO0("reset sequence");
|
||||
// free any pending tx packets
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
}
|
||||
|
||||
/* set resetting state */
|
||||
hciCb.resetting = TRUE;
|
||||
|
||||
/* start the reset sequence */
|
||||
hciCoreResetStart();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetMaxRxAclLen
|
||||
*
|
||||
* \brief Set the maximum reassembled RX ACL packet length. Minimum value is 27.
|
||||
*
|
||||
* \param len ACL packet length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetMaxRxAclLen(uint16_t len)
|
||||
{
|
||||
hciCoreCb.maxRxAclLen = len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetAclQueueWatermarks
|
||||
*
|
||||
* \brief Set TX ACL queue high and low watermarks.
|
||||
*
|
||||
* \param queueHi Disable flow on a connection when this many ACL buffers are queued.
|
||||
* queueLo Disable flow on a connection when this many ACL buffers are queued.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetAclQueueWatermarks(uint8_t queueHi, uint8_t queueLo)
|
||||
{
|
||||
hciCoreCb.aclQueueHi = queueHi;
|
||||
hciCoreCb.aclQueueLo = queueLo;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSetLeSupFeat
|
||||
*
|
||||
* \brief Set LE supported features configuration mask.
|
||||
*
|
||||
* \param feat Feature bit to set or clear
|
||||
* \param flag TRUE to set feature bit and FALSE to clear it
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetLeSupFeat(uint32_t feat, bool_t flag)
|
||||
{
|
||||
/* if asked to include feature */
|
||||
if (flag)
|
||||
{
|
||||
/* set feature bit */
|
||||
hciLeSupFeatCfg |= feat;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear feature bit */
|
||||
hciLeSupFeatCfg &= ~feat;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciSendAclData
|
||||
*
|
||||
* \brief Send data from the stack to HCI.
|
||||
*
|
||||
* \param pData WSF buffer containing an ACL packet
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSendAclData(uint8_t *pData)
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up connection structure */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if queue empty and buffers available */
|
||||
if (WsfQueueEmpty(&hciCoreCb.aclQueue) && hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send data */
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* queue data - message handler ID 'handerId' not used */
|
||||
WsfMsgEnq(&hciCoreCb.aclQueue, 0, pData);
|
||||
}
|
||||
|
||||
/* increment buffer queue count for this connection with consideration for HCI fragmentation */
|
||||
pConn->queuedBufs += ((len - 1) / HciGetBufSize()) + 1;
|
||||
|
||||
/* manage flow control to stack */
|
||||
if (pConn->queuedBufs >= hciCoreCb.aclQueueHi && pConn->flowDisabled == FALSE)
|
||||
{
|
||||
pConn->flowDisabled = TRUE;
|
||||
(*hciCb.flowCback)(handle, TRUE);
|
||||
}
|
||||
}
|
||||
/* connection not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("HciSendAclData discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
Vendored
+391
@@ -0,0 +1,391 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core_ps.c
|
||||
*
|
||||
* \brief HCI core platform-specific module for dual-chip.
|
||||
*
|
||||
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
|
||||
* $Revision: 10805 $
|
||||
*
|
||||
* Copyright (c) 2009-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_evt.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreInit
|
||||
*
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreInit(void)
|
||||
{
|
||||
hciCmdInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreNumCmplPkts
|
||||
*
|
||||
* \brief Handle an HCI Number of Completed Packets event.
|
||||
*
|
||||
* \param pMsg Message containing the HCI Number of Completed Packets event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreNumCmplPkts(uint8_t *pMsg)
|
||||
{
|
||||
uint8_t numHandles;
|
||||
uint16_t bufs;
|
||||
uint16_t handle;
|
||||
uint8_t availBufs = 0;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse number of handles */
|
||||
BSTREAM_TO_UINT8(numHandles, pMsg);
|
||||
|
||||
/* for each handle in event */
|
||||
while (numHandles-- > 0)
|
||||
{
|
||||
/* parse handle and number of buffers */
|
||||
BSTREAM_TO_UINT16(handle, pMsg);
|
||||
BSTREAM_TO_UINT16(bufs, pMsg);
|
||||
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* decrement outstanding buffer count to controller */
|
||||
pConn->outBufs -= (uint8_t) bufs;
|
||||
|
||||
/* decrement queued buffer count for this connection */
|
||||
pConn->queuedBufs -= (uint8_t) bufs;
|
||||
|
||||
/* increment available buffer count */
|
||||
availBufs += (uint8_t) bufs;
|
||||
|
||||
/* call flow control callback */
|
||||
if (pConn->flowDisabled && pConn->queuedBufs <= hciCoreCb.aclQueueLo)
|
||||
{
|
||||
pConn->flowDisabled = FALSE;
|
||||
(*hciCb.flowCback)(handle, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* service TX data path */
|
||||
hciCoreTxReady(availBufs);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreRecv
|
||||
*
|
||||
* \brief Send a received HCI event or ACL packet to the HCI event handler.
|
||||
*
|
||||
* \param msgType Message type: HCI_ACL_TYPE or HCI_EVT_TYPE.
|
||||
* \param pCoreRecvMsg Pointer to received message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg)
|
||||
{
|
||||
/* dump event for protocol analysis */
|
||||
if (msgType == HCI_EVT_TYPE)
|
||||
{
|
||||
HCI_PDUMP_EVT(*(pCoreRecvMsg + 1) + HCI_EVT_HDR_LEN, pCoreRecvMsg);
|
||||
}
|
||||
else if (msgType == HCI_ACL_TYPE)
|
||||
{
|
||||
HCI_PDUMP_RX_ACL(*(pCoreRecvMsg + 2) + HCI_ACL_HDR_LEN, pCoreRecvMsg);
|
||||
}
|
||||
|
||||
/* queue buffer */
|
||||
WsfMsgEnq(&hciCb.rxQueue, (wsfHandlerId_t) msgType, pCoreRecvMsg);
|
||||
|
||||
/* set event */
|
||||
WsfSetEvent(hciCb.handlerId, HCI_EVT_RX);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciCoreHandler
|
||||
*
|
||||
* \brief WSF event handler for core HCI.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
wsfHandlerId_t handlerId;
|
||||
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
/* Handle HCI command timeout */
|
||||
if (pMsg->event == HCI_MSG_CMD_TIMEOUT)
|
||||
{
|
||||
hciCmdTimeout(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event & HCI_EVT_RX)
|
||||
{
|
||||
/* Process rx queue */
|
||||
while ((pBuf = WsfMsgDeq(&hciCb.rxQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* Handle incoming HCI events */
|
||||
if (handlerId == HCI_EVT_TYPE)
|
||||
{
|
||||
/* Parse/process events */
|
||||
hciEvtProcessMsg(pBuf);
|
||||
|
||||
/* Handle events during reset sequence */
|
||||
if (hciCb.resetting)
|
||||
{
|
||||
hciCoreResetSequence(pBuf);
|
||||
}
|
||||
|
||||
/* Free buffer */
|
||||
WsfMsgFree(pBuf);
|
||||
}
|
||||
/* Handle ACL data */
|
||||
else
|
||||
{
|
||||
/* Reassemble */
|
||||
if ((pBuf = hciCoreAclReassembly(pBuf)) != NULL)
|
||||
{
|
||||
/* Call ACL callback; client will free buffer */
|
||||
hciCb.aclCback(pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetBdAddr
|
||||
*
|
||||
* \brief Return a pointer to the BD address of this device.
|
||||
*
|
||||
* \return Pointer to the BD address.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *HciGetBdAddr(void)
|
||||
{
|
||||
return hciCoreCb.bdAddr;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetWhiteListSize
|
||||
*
|
||||
* \brief Return the white list size.
|
||||
*
|
||||
* \return White list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetWhiteListSize(void)
|
||||
{
|
||||
return hciCoreCb.whiteListSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetAdvTxPwr
|
||||
*
|
||||
* \brief Return the advertising transmit power.
|
||||
*
|
||||
* \return Advertising transmit power.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
int8_t HciGetAdvTxPwr(void)
|
||||
{
|
||||
return hciCoreCb.advTxPwr;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetBufSize
|
||||
*
|
||||
* \brief Return the ACL buffer size supported by the controller.
|
||||
*
|
||||
* \return ACL buffer size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetBufSize(void)
|
||||
{
|
||||
return hciCoreCb.bufSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetNumBufs
|
||||
*
|
||||
* \brief Return the number of ACL buffers supported by the controller.
|
||||
*
|
||||
* \return Number of ACL buffers.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetNumBufs(void)
|
||||
{
|
||||
return hciCoreCb.numBufs;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetSupStates
|
||||
*
|
||||
* \brief Return the states supported by the controller.
|
||||
*
|
||||
* \return Pointer to the supported states array.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *HciGetSupStates(void)
|
||||
{
|
||||
return hciCoreCb.leStates;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetLeSupFeat
|
||||
*
|
||||
* \brief Return the LE supported features supported by the controller.
|
||||
*
|
||||
* \return Supported features.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t HciGetLeSupFeat(void)
|
||||
{
|
||||
// disable LL connection parameter update feature for a better
|
||||
// interoperability with Android phones (especially older Android OS).
|
||||
return hciCoreCb.leSupFeat & ~HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetMaxRxAclLen
|
||||
*
|
||||
* \brief Get the maximum reassembled RX ACL packet length.
|
||||
*
|
||||
* \return ACL packet length.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetMaxRxAclLen(void)
|
||||
{
|
||||
return hciCoreCb.maxRxAclLen;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetResolvingListSize
|
||||
*
|
||||
* \brief Return the resolving list size.
|
||||
*
|
||||
* \return resolving list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetResolvingListSize(void)
|
||||
{
|
||||
return hciCoreCb.resListSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciLlPrivacySupported
|
||||
*
|
||||
* \brief Whether LL Privacy is supported.
|
||||
*
|
||||
* \return TRUE if LL Privacy is supported. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t HciLlPrivacySupported(void)
|
||||
{
|
||||
return (hciCoreCb.resListSize > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetMaxAdvDataLen
|
||||
*
|
||||
* \brief Get the maximum advertisement (or scan response) data length supported by the Controller.
|
||||
*
|
||||
* \return Maximum advertisement data length.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t HciGetMaxAdvDataLen(void)
|
||||
{
|
||||
return hciCoreCb.maxAdvDataLen;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetNumSupAdvSets
|
||||
*
|
||||
* \brief Get the maximum number of advertising sets supported by the Controller.
|
||||
*
|
||||
* \return Maximum number of advertising sets.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetNumSupAdvSets(void)
|
||||
{
|
||||
return hciCoreCb.numSupAdvSets;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciLeAdvExtSupported
|
||||
*
|
||||
* \brief Whether LE Advertising Extensions is supported.
|
||||
*
|
||||
* \return TRUE if LE Advertising Extensions is supported. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t HciLeAdvExtSupported(void)
|
||||
{
|
||||
return (hciCoreCb.numSupAdvSets > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciGetPerAdvListSize
|
||||
*
|
||||
* \brief Return the periodic advertising list size.
|
||||
*
|
||||
* \return periodic advertising list size.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HciGetPerAdvListSize(void)
|
||||
{
|
||||
return hciCoreCb.perAdvListSize;
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_core_ps.h
|
||||
*
|
||||
* \brief HCI core platform-specific interfaces for dual-chip.
|
||||
*
|
||||
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
|
||||
* $Revision: 10805 $
|
||||
*
|
||||
* Copyright (c) 2013-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef HCI_CORE_PS_H
|
||||
#define HCI_CORE_PS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void hciCoreResetSequence(uint8_t *pMsg);
|
||||
void hciCoreNumCmplPkts(uint8_t *pMsg);
|
||||
void hciCoreRecv(uint8_t msgType, uint8_t *pCoreRecvMsg);
|
||||
uint8_t hciCoreVsCmdCmplRcvd(uint16_t opcode, uint8_t *pMsg, uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HCI_CORE_PS_H */
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_drv_apollo.h
|
||||
//!
|
||||
//! @brief Additional header information for the Apollo implementation of HCI.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef HCI_DRV_APOLLO_H
|
||||
#define HCI_DRV_APOLLO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Errors
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define HCI_DRV_SPECIFIC_ERROR_START 0x09000000
|
||||
typedef enum
|
||||
{
|
||||
HCI_DRV_TRANSMIT_QUEUE_FULL = HCI_DRV_SPECIFIC_ERROR_START,
|
||||
HCI_DRV_TX_PACKET_TOO_LARGE,
|
||||
HCI_DRV_RX_PACKET_TOO_LARGE,
|
||||
HCI_DRV_BLE_STACK_UNABLE_TO_ACCEPT_PACKET,
|
||||
HCI_DRV_PACKET_TRANSMIT_FAILED,
|
||||
HCI_DRV_IRQ_STUCK_HIGH,
|
||||
HCI_DRV_TOO_MANY_PACKETS,
|
||||
}
|
||||
hci_drv_error_t;
|
||||
|
||||
typedef void (*hci_drv_error_handler_t)(uint32_t ui32Error);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function prototypes.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void HciDrvUartEnable(void);
|
||||
extern void HciDrvUartDisable(void);
|
||||
extern void HciDrvUartFlowOff(void);
|
||||
extern void HciDrvUartFlowOn(void);
|
||||
extern void HciDrvUartPause(void);
|
||||
extern void HciDrvUartUnpause(void);
|
||||
extern bool HciDrvUartSafeShutdown(void);
|
||||
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
extern void HciDrvRadioBoot(bool bColdBoot);
|
||||
#else
|
||||
extern void HciDrvRadioBoot(uint32_t ui32UartModule);
|
||||
#endif
|
||||
|
||||
extern void HciDrvRadioShutdown(void);
|
||||
extern void HciDrvUartISR(uint32_t ui32Status);
|
||||
extern bool_t HciDataReadyISR(void);
|
||||
extern void HciDrvIntService(void);
|
||||
extern void HciDrvGPIOService(void);
|
||||
extern void HciDrvHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
extern void HciDrvErrorHandlerSet(hci_drv_error_handler_t pfnErrorHandler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_DRV_APOLLO_H
|
||||
+2081
File diff suppressed because it is too large
Load Diff
+304
@@ -0,0 +1,304 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_tr.c
|
||||
*
|
||||
* \brief HCI transport module.
|
||||
*
|
||||
* $Date: 2017-03-10 14:08:37 -0600 (Fri, 10 Mar 2017) $
|
||||
* $Revision: 11501 $
|
||||
*
|
||||
* Copyright (c) 2011-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_drv.h"
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
State variable
|
||||
**************************************************************************************************/
|
||||
static volatile bool_t g_bHCIReceivingPacket = FALSE;
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#define HCI_HDR_LEN_MAX HCI_ACL_HDR_LEN
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HCI_RX_STATE_IDLE,
|
||||
HCI_RX_STATE_HEADER,
|
||||
HCI_RX_STATE_DATA,
|
||||
HCI_RX_STATE_COMPLETE
|
||||
} hciRxState_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendAclData
|
||||
*
|
||||
* \brief Send a complete HCI ACL packet to the transport.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
* \param pData WSF msg buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendAclData(void *pContext, uint8_t *pData)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
/* get 16-bit length */
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
len += HCI_ACL_HDR_LEN;
|
||||
|
||||
/* dump event for protocol analysis */
|
||||
HCI_PDUMP_TX_ACL(len, pData);
|
||||
|
||||
/* transmit ACL header and data */
|
||||
if (hciDrvWrite(HCI_ACL_TYPE, len, pData) == len)
|
||||
{
|
||||
/* free buffer */
|
||||
hciCoreTxAclComplete(pContext, pData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendCmd
|
||||
*
|
||||
* \brief Send a complete HCI command to the transport.
|
||||
*
|
||||
* \param pData WSF msg buffer containing an HCI command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendCmd(uint8_t *pData)
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
/* get length */
|
||||
len = pData[2] + HCI_CMD_HDR_LEN;
|
||||
|
||||
/* dump event for protocol analysis */
|
||||
HCI_PDUMP_CMD(len, pData);
|
||||
|
||||
/* transmit ACL header and data */
|
||||
if (hciDrvWrite(HCI_CMD_TYPE, len, pData) == len)
|
||||
{
|
||||
/* free buffer */
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciSerialRxIncoming
|
||||
*
|
||||
* \brief Receive function. Gets called by external code when bytes are received.
|
||||
*
|
||||
* \param pBuf Pointer to buffer of incoming bytes.
|
||||
* \param len Number of bytes in incoming buffer.
|
||||
*
|
||||
* \return The number of bytes consumed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len)
|
||||
{
|
||||
static uint8_t stateRx = HCI_RX_STATE_IDLE;
|
||||
static uint8_t pktIndRx;
|
||||
static uint16_t iRx;
|
||||
static uint8_t hdrRx[HCI_HDR_LEN_MAX];
|
||||
static uint8_t *pPktRx;
|
||||
static uint8_t *pDataRx;
|
||||
|
||||
uint8_t dataByte;
|
||||
uint16_t consumed_bytes;
|
||||
|
||||
consumed_bytes = 0;
|
||||
/* loop until all bytes of incoming buffer are handled */
|
||||
while (len)
|
||||
{
|
||||
/* read single byte from incoming buffer and advance to next byte */
|
||||
dataByte = *pBuf;
|
||||
|
||||
/* --- Idle State --- */
|
||||
if (stateRx == HCI_RX_STATE_IDLE)
|
||||
{
|
||||
/* save the packet type */
|
||||
pktIndRx = dataByte;
|
||||
iRx = 0;
|
||||
stateRx = HCI_RX_STATE_HEADER;
|
||||
g_bHCIReceivingPacket = TRUE;
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* --- Header State --- */
|
||||
else if (stateRx == HCI_RX_STATE_HEADER)
|
||||
{
|
||||
uint8_t hdrLen = 0;
|
||||
uint16_t dataLen = 0;
|
||||
|
||||
/* determine header length based on packet type */
|
||||
if (pktIndRx == HCI_EVT_TYPE)
|
||||
{
|
||||
hdrLen = HCI_EVT_HDR_LEN;
|
||||
}
|
||||
else if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
hdrLen = HCI_ACL_HDR_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid packet type */
|
||||
WSF_ASSERT(0);
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
if (iRx != hdrLen) {
|
||||
/* copy current byte into the temp header buffer */
|
||||
hdrRx[iRx++] = dataByte;
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* see if entire header has been read */
|
||||
if (iRx == hdrLen)
|
||||
{
|
||||
/* extract data length from header */
|
||||
if (pktIndRx == HCI_EVT_TYPE)
|
||||
{
|
||||
dataLen = hdrRx[1];
|
||||
}
|
||||
else if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
BYTES_TO_UINT16(dataLen, &hdrRx[2]);
|
||||
}
|
||||
|
||||
/* allocate data buffer to hold entire packet */
|
||||
if (pktIndRx == HCI_ACL_TYPE)
|
||||
{
|
||||
pPktRx = (uint8_t*)WsfMsgDataAlloc(hdrLen + dataLen, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPktRx = (uint8_t*)WsfMsgAlloc(hdrLen + dataLen);
|
||||
}
|
||||
|
||||
if (pPktRx != NULL)
|
||||
{
|
||||
pDataRx = pPktRx;
|
||||
|
||||
/* copy header into data packet (note: memcpy is not so portable) */
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < hdrLen; i++)
|
||||
{
|
||||
*pDataRx++ = hdrRx[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* save number of bytes left to read */
|
||||
iRx = dataLen;
|
||||
if (iRx == 0)
|
||||
{
|
||||
stateRx = HCI_RX_STATE_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
stateRx = HCI_RX_STATE_DATA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WSF_ASSERT(0); /* allocate falied */
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Data State --- */
|
||||
else if (stateRx == HCI_RX_STATE_DATA)
|
||||
{
|
||||
/* write incoming byte to allocated buffer */
|
||||
*pDataRx++ = dataByte;
|
||||
|
||||
/* determine if entire packet has been read */
|
||||
iRx--;
|
||||
if (iRx == 0)
|
||||
{
|
||||
stateRx = HCI_RX_STATE_COMPLETE;
|
||||
}
|
||||
pBuf++;
|
||||
consumed_bytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* --- Complete State --- */
|
||||
/* ( Note Well! There is no else-if construct by design. ) */
|
||||
if (stateRx == HCI_RX_STATE_COMPLETE)
|
||||
{
|
||||
g_bHCIReceivingPacket = FALSE;
|
||||
|
||||
/* deliver data */
|
||||
if (pPktRx != NULL)
|
||||
{
|
||||
//am_hal_gpio_out_bit_set(13);
|
||||
hciCoreRecv(pktIndRx, pPktRx);
|
||||
//am_hal_gpio_out_bit_clear(13);
|
||||
}
|
||||
|
||||
/* reset state machine */
|
||||
stateRx = HCI_RX_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
return consumed_bytes;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @brief Check to see if the state machine has received part of a packet.
|
||||
//!
|
||||
//! This function checks the HCI packet-receive state machine to see if it is
|
||||
//! in the middle of receiving a packet. This information can be useful in
|
||||
//! determining whether the serial interface should remain enabled.
|
||||
//!
|
||||
//! @return TRUE if there is a packet in progress.
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool_t
|
||||
hciTrReceivingPacket(void)
|
||||
{
|
||||
return g_bHCIReceivingPacket;
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file hci_tr_apollo.h
|
||||
//!
|
||||
//! @brief Additional header information for the Apollo implementation of HCI.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef HCI_TR_APOLLO_H
|
||||
#define HCI_TR_APOLLO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function prototypes.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern bool_t hciTrReceivingPacket(void);
|
||||
extern uint16_t hciTrSerialRxIncoming(uint8_t *pBuf, uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // HCI_TR_APOLLO_H
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_vs.c
|
||||
*
|
||||
* \brief HCI vendor specific functions for generic controllers.
|
||||
*
|
||||
* $Date: 2017-02-28 11:31:38 -0600 (Tue, 28 Feb 2017) $
|
||||
* $Revision: 11299 $
|
||||
*
|
||||
* Copyright (c) 2011-2017 ARM Ltd., all rights reserved.
|
||||
* ARM Ltd. confidential and proprietary.
|
||||
*
|
||||
* IMPORTANT. Your use of this file is governed by a Software License Agreement
|
||||
* ("Agreement") that must be accepted in order to download or otherwise receive a
|
||||
* copy of this file. You may not use or copy this file for any purpose other than
|
||||
* as described in the Agreement. If you do not agree to all of the terms of the
|
||||
* Agreement do not use this file and delete all copies in your possession or control;
|
||||
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
|
||||
* to any use, copying or further distribution of this software.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "bda.h"
|
||||
#include "bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_apollo_config.h"
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
#if HCI_VS_TARGET == HCI_VS_GENERIC
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void hciCoreReadResolvingListSize(void);
|
||||
static void hciCoreReadMaxDataLen(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreReadResolvingListSize
|
||||
*
|
||||
* \brief Read resolving list command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadResolvingListSize(void)
|
||||
{
|
||||
/* if LL Privacy is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_PRIVACY) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_PRIVACY))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadResolvingListSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.resListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxDataLen();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreReadMaxDataLen
|
||||
*
|
||||
* \brief Read maximum data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadMaxDataLen(void)
|
||||
{
|
||||
/* if LE Data Packet Length Extensions is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_DATA_LEN_EXT) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_DATA_LEN_EXT))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadMaxDataLen();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreResetStart
|
||||
*
|
||||
* \brief Start the HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreResetStart(void)
|
||||
{
|
||||
/* send an HCI Reset command to start the sequence */
|
||||
HciResetCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreResetSequence
|
||||
*
|
||||
* \brief Implement the HCI reset sequence.
|
||||
*
|
||||
* \param pMsg HCI event message from previous command in the sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreResetSequence(uint8_t *pMsg)
|
||||
{
|
||||
uint16_t opcode;
|
||||
wsfMsgHdr_t hdr;
|
||||
static uint8_t randCnt;
|
||||
|
||||
/* if event is a command complete event */
|
||||
if (*pMsg == HCI_CMD_CMPL_EVT)
|
||||
{
|
||||
/* parse parameters */
|
||||
pMsg += HCI_EVT_HDR_LEN;
|
||||
pMsg++; /* skip num packets */
|
||||
BSTREAM_TO_UINT16(opcode, pMsg);
|
||||
pMsg++; /* skip status */
|
||||
|
||||
/* decode opcode */
|
||||
switch (opcode)
|
||||
{
|
||||
case HCI_OPCODE_RESET:
|
||||
/* initialize rand command count */
|
||||
randCnt = 0;
|
||||
|
||||
#ifdef AM_BSP_GPIO_EM9304_RESET
|
||||
// set the BD address after HCI reset for EM device
|
||||
extern void HciVsEM_SetBDAddress(void);
|
||||
|
||||
HciVsEM_SetBDAddress();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AM_BSP_NATIONZ_IOM
|
||||
extern uint8_t g_BLEMacAddress[6];
|
||||
HciVendorSpecificCmd(0xFC32, 6, g_BLEMacAddress);
|
||||
#endif
|
||||
|
||||
/* send next command in sequence */
|
||||
HciSetEventMaskCmd((uint8_t *) hciEventMask);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_SET_EVENT_MASK:
|
||||
/* send next command in sequence */
|
||||
HciLeSetEventMaskCmd((uint8_t *) hciLeEventMask);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_SET_EVENT_MASK:
|
||||
/* send next command in sequence */
|
||||
HciSetEventMaskPage2Cmd((uint8_t *) hciEventMaskPage2);
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_SET_EVENT_MASK_PAGE2:
|
||||
/* send next command in sequence */
|
||||
HciReadBdAddrCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_READ_BD_ADDR:
|
||||
/* parse and store event parameters */
|
||||
BdaCpy(hciCoreCb.bdAddr, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadBufSizeCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_BUF_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT16(hciCoreCb.bufSize, pMsg);
|
||||
BSTREAM_TO_UINT8(hciCoreCb.numBufs, pMsg);
|
||||
|
||||
|
||||
/* initialize ACL buffer accounting */
|
||||
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
|
||||
// B0 has less data buffer compared to A1 and A0
|
||||
if (!APOLLO3_GE_B0)
|
||||
{
|
||||
hciCoreCb.numBufs--;
|
||||
}
|
||||
#endif
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadSupStatesCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_SUP_STATES:
|
||||
/* parse and store event parameters */
|
||||
memcpy(hciCoreCb.leStates, pMsg, HCI_LE_STATES_LEN);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadWhiteListSizeCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_WHITE_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.whiteListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeReadLocalSupFeatCmd();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT16(hciCoreCb.leSupFeat, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadResolvingListSize();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_RES_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.resListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxDataLen();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_DATA_LEN:
|
||||
{
|
||||
uint16_t maxTxOctets;
|
||||
uint16_t maxTxTime;
|
||||
|
||||
BSTREAM_TO_UINT16(maxTxOctets, pMsg);
|
||||
BSTREAM_TO_UINT16(maxTxTime, pMsg);
|
||||
|
||||
/* use Controller's maximum supported payload octets and packet duration times
|
||||
* for transmission as Host's suggested values for maximum transmission number
|
||||
* of payload octets and maximum packet transmission time for new connections.
|
||||
*/
|
||||
HciLeWriteDefDataLen(maxTxOctets, maxTxTime);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_WRITE_DEF_DATA_LEN:
|
||||
if (hciCoreCb.extResetSeq)
|
||||
{
|
||||
/* send first extended command */
|
||||
(*hciCoreCb.extResetSeq)(pMsg, opcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initialize extended parameters */
|
||||
hciCoreCb.maxAdvDataLen = 0;
|
||||
hciCoreCb.numSupAdvSets = 0;
|
||||
hciCoreCb.perAdvListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN:
|
||||
case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS:
|
||||
case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE:
|
||||
if (hciCoreCb.extResetSeq)
|
||||
{
|
||||
/* send next extended command in sequence */
|
||||
(*hciCoreCb.extResetSeq)(pMsg, opcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_RAND:
|
||||
/* check if need to send second rand command */
|
||||
if (randCnt < (HCI_RESET_RAND_CNT-1))
|
||||
{
|
||||
randCnt++;
|
||||
HciLeRandCmd();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* last command in sequence; set resetting state and call callback */
|
||||
hciCb.resetting = FALSE;
|
||||
hdr.param = 0;
|
||||
hdr.event = HCI_RESET_SEQ_CMPL_CBACK_EVT;
|
||||
(*hciCb.evtCback)((hciEvt_t *) &hdr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreVsCmdCmplRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of vendor specific command complete events.
|
||||
*
|
||||
* \param opcode HCI command opcode.
|
||||
* \param pMsg Pointer to input HCI event parameter byte stream.
|
||||
* \param len Parameter byte stream length.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreVsCmdCmplRcvd(uint16_t opcode, uint8_t *pMsg, uint8_t len)
|
||||
{
|
||||
return HCI_VENDOR_SPEC_CMD_CMPL_CBACK_EVT;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreVsEvtRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of vendor specific HCI events.
|
||||
*
|
||||
* \param p Pointer to input HCI event parameter byte stream.
|
||||
* \param len Parameter byte stream length.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreVsEvtRcvd(uint8_t *p, uint8_t len)
|
||||
{
|
||||
return HCI_VENDOR_SPEC_EVT;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciCoreHwErrorRcvd
|
||||
*
|
||||
* \brief Perform internal HCI processing of hardware error event.
|
||||
*
|
||||
* \param p Pointer to input HCI event parameter byte stream.
|
||||
*
|
||||
* \return HCI callback event code or zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t hciCoreHwErrorRcvd(uint8_t *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn HciVsInit
|
||||
*
|
||||
* \brief Vendor-specific controller initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsInit(uint8_t param)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Vendored
+174
@@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2009-2019 Arm Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI vendor specific AE functions for generic controllers.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_core.h"
|
||||
|
||||
#if HCI_VS_TARGET == HCI_VS_GENERIC
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void hciCoreReadMaxAdvDataLen(void);
|
||||
static void hciCoreReadNumSupAdvSets(void);
|
||||
static void hciCoreReadPerAdvListSize(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read maximum advertising data length command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadMaxAdvDataLen(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_EXT_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_EXT_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadMaxAdvDataLen();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.maxAdvDataLen = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadNumSupAdvSets();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read read number of supported advertising sets command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadNumSupAdvSets(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_EXT_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_EXT_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadNumSupAdvSets();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.numSupAdvSets = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadPerAdvListSize();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read periodic advertiser list size command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreReadPerAdvListSize(void)
|
||||
{
|
||||
/* if LE Extended Advertising is supported by Controller and included */
|
||||
if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_LE_PER_ADV) &&
|
||||
(hciLeSupFeatCfg & HCI_LE_SUP_FEAT_LE_PER_ADV))
|
||||
{
|
||||
/* send next command in sequence */
|
||||
HciLeReadPerAdvListSizeCmd();
|
||||
}
|
||||
else
|
||||
{
|
||||
hciCoreCb.perAdvListSize = 0;
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Implement the HCI extended reset sequence.
|
||||
*
|
||||
* \param pMsg HCI event message from previous command in the sequence.
|
||||
* \param opcode HCI event message opcode.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreExtResetSequence(uint8_t *pMsg, uint16_t opcode)
|
||||
{
|
||||
/* decode opcode */
|
||||
switch (opcode)
|
||||
{
|
||||
case HCI_OPCODE_READ_LOCAL_VER_INFO:
|
||||
/* send next command in sequence */
|
||||
hciCoreReadMaxAdvDataLen();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN:
|
||||
BSTREAM_TO_UINT16(hciCoreCb.maxAdvDataLen, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadNumSupAdvSets();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.numSupAdvSets, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
hciCoreReadPerAdvListSize();
|
||||
break;
|
||||
|
||||
case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE:
|
||||
/* parse and store event parameters */
|
||||
BSTREAM_TO_UINT8(hciCoreCb.perAdvListSize, pMsg);
|
||||
|
||||
/* send next command in sequence */
|
||||
HciLeRandCmd();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Vendor-specific controller AE initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciVsAeInit(uint8_t param)
|
||||
{
|
||||
hciCoreCb.extResetSeq = hciCoreExtResetSequence;
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+838
@@ -0,0 +1,838 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief HCI core module, platform independent functions.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This module implements core platform independent HCI features for transmit data path,
|
||||
* fragmentation, reassembly, and connection management.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "util/bda.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_main.h"
|
||||
#include "l2c_defs.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default ACL buffer flow control watermark levels */
|
||||
#ifndef HCI_ACL_QUEUE_HI
|
||||
#define HCI_ACL_QUEUE_HI 5 /* Disable flow when this many buffers queued */
|
||||
#endif
|
||||
#ifndef HCI_ACL_QUEUE_LO
|
||||
#define HCI_ACL_QUEUE_LO 1 /* Enable flow when this many buffers queued */
|
||||
#endif
|
||||
|
||||
/* Default maximum ACL packet size for reassembly */
|
||||
#ifndef HCI_MAX_RX_ACL_LEN
|
||||
#define HCI_MAX_RX_ACL_LEN HCI_ACL_DEFAULT_LEN
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Event mask */
|
||||
const uint8_t hciEventMask[HCI_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_DISCONNECT_CMPL | /* Byte 0 */
|
||||
HCI_EVT_MASK_ENC_CHANGE, /* Byte 0 */
|
||||
HCI_EVT_MASK_READ_REMOTE_VER_INFO_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_HW_ERROR, /* Byte 1 */
|
||||
0, /* Byte 2 */
|
||||
HCI_EVT_MASK_DATA_BUF_OVERFLOW, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
HCI_EVT_MASK_ENC_KEY_REFRESH_CMPL, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
HCI_EVT_MASK_LE_META /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE event mask */
|
||||
const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN] =
|
||||
{
|
||||
HCI_EVT_MASK_LE_CONN_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_ADV_REPORT_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_CONN_UPDATE_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_REMOTE_FEAT_CMPL_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_LTK_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_REMOTE_CONN_PARAM_REQ_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_DATA_LEN_CHANGE_EVT | /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_READ_LOCAL_P256_PUB_KEY_CMPL, /* Byte 0 */
|
||||
HCI_EVT_MASK_LE_GENERATE_DHKEY_CMPL | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_ENHANCED_CONN_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_DIRECT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PHY_UPDATE_CMPL_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_EXT_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_EST_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_REPORT_EVT | /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_PER_ADV_SYNC_LOST_EVT, /* Byte 1 */
|
||||
HCI_EVT_MASK_LE_SCAN_TIMEOUT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_ADV_SET_TERM_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_SCAN_REQ_RCVD_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CH_SEL_ALGO_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CONN_IQ_REPORT_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_CTE_REQ_FAILED_EVT | /* Byte 2 */
|
||||
HCI_EVT_MASK_LE_PER_SYNC_TRSF_RCVT_EVT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* event mask page 2 */
|
||||
const uint8_t hciEventMaskPage2[HCI_EVT_MASK_PAGE_2_LEN] =
|
||||
{
|
||||
0, /* Byte 0 */
|
||||
0, /* Byte 1 */
|
||||
HCI_EVT_MASK_AUTH_PAYLOAD_TIMEOUT, /* Byte 2 */
|
||||
0, /* Byte 3 */
|
||||
0, /* Byte 4 */
|
||||
0, /* Byte 5 */
|
||||
0, /* Byte 6 */
|
||||
0 /* Byte 7 */
|
||||
};
|
||||
|
||||
/* LE supported features configuration mask */
|
||||
uint32_t hciLeSupFeatCfg =
|
||||
HCI_LE_SUP_FEAT_ENCRYPTION | /* LE Encryption */
|
||||
HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC | /* Connection Parameters Request Procedure */
|
||||
HCI_LE_SUP_FEAT_EXT_REJECT_IND | /* Extended Reject Indication */
|
||||
HCI_LE_SUP_FEAT_SLV_INIT_FEAT_EXCH | /* Slave-initiated Features Exchange */
|
||||
HCI_LE_SUP_FEAT_LE_PING | /* LE Ping */
|
||||
HCI_LE_SUP_FEAT_DATA_LEN_EXT | /* LE Data Packet Length Extension */
|
||||
HCI_LE_SUP_FEAT_PRIVACY | /* LL Privacy */
|
||||
HCI_LE_SUP_FEAT_EXT_SCAN_FILT_POLICY | /* Extended Scanner Filter Policies */
|
||||
HCI_LE_SUP_FEAT_LE_2M_PHY | /* LE 2M PHY supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_TRANSMITTER | /* Stable Modulation Index - Transmitter supported */
|
||||
HCI_LE_SUP_FEAT_STABLE_MOD_IDX_RECEIVER | /* Stable Modulation Index - Receiver supported */
|
||||
HCI_LE_SUP_FEAT_LE_EXT_ADV | /* LE Extended Advertising */
|
||||
HCI_LE_SUP_FEAT_LE_PER_ADV; /* LE Periodic Advertising */
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
hciCoreCb_t hciCoreCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnAlloc(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == HCI_HANDLE_NONE)
|
||||
{
|
||||
/* allocate and initialize */
|
||||
pConn->handle = handle;
|
||||
pConn->flowDisabled = FALSE;
|
||||
pConn->outBufs = 0;
|
||||
pConn->queuedBufs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN0("HCI conn struct alloc failure");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free a connection structure.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hciCoreConnFree(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
/* free any fragmenting ACL packet */
|
||||
if (pConn->pTxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
}
|
||||
pConn->fragmenting = FALSE;
|
||||
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
|
||||
/* free structure */
|
||||
pConn->handle = HCI_HANDLE_NONE;
|
||||
|
||||
/* optional: iterate through tx ACL queue and free any buffers with this handle */
|
||||
|
||||
/* outstanding buffers are now available; service TX data path */
|
||||
hciCoreTxReady(pConn->outBufs);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreConnFree handle not found:%u", handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get a connection structure by handle
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find available connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle == handle)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next connection structure with a packet fragment to send.
|
||||
*
|
||||
* \return Pointer to connection structure or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hciCoreConn_t *hciCoreNextConnFragment(void)
|
||||
{
|
||||
uint8_t i;
|
||||
hciCoreConn_t *pConn = hciCoreCb.conn;
|
||||
|
||||
/* find connection struct */
|
||||
for (i = DM_CONN_MAX; i > 0; i--, pConn++)
|
||||
{
|
||||
if (pConn->handle != HCI_HANDLE_NONE && pConn->fragmenting)
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection open.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnOpen(uint16_t handle)
|
||||
{
|
||||
/* allocate connection structure */
|
||||
hciCoreConnAlloc(handle);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform internal processing on HCI connection close.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreConnClose(uint16_t handle)
|
||||
{
|
||||
/* free connection structure */
|
||||
hciCoreConnFree(handle);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL data to transport.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* increment outstanding buf count for handle */
|
||||
pConn->outBufs++;
|
||||
|
||||
/* send to transport */
|
||||
hciTrSendAclData(pConn, pData);
|
||||
|
||||
/* decrement available buffer count */
|
||||
if (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN0("hciCoreSendAclData availBufs=0");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Service the TX data path.
|
||||
*
|
||||
* \param bufs Number of new buffers now available.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxReady(uint8_t bufs)
|
||||
{
|
||||
uint8_t *pData;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* increment available buffers, with ceiling */
|
||||
if (bufs > 0)
|
||||
{
|
||||
hciCoreCb.availBufs += bufs;
|
||||
if (hciCoreCb.availBufs > hciCoreCb.numBufs)
|
||||
{
|
||||
hciCoreCb.availBufs = hciCoreCb.numBufs;
|
||||
}
|
||||
}
|
||||
|
||||
/* service ACL data queue and send as many buffers as we can */
|
||||
while (hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send continuation of any fragments first */
|
||||
if (hciCoreTxAclContinue(NULL) == FALSE)
|
||||
{
|
||||
/* if no fragments then check for any queued ACL data */
|
||||
if ((pData = WsfMsgDeq(&hciCoreCb.aclQueue, &handlerId)) != NULL)
|
||||
{
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up conn structure and send data */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
/* handle not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("hciCoreTxReady discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragments or queued data to send; we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, start of packet.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param len ACL packet length.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData)
|
||||
{
|
||||
uint16_t hciLen;
|
||||
|
||||
/* make sure not already fragmenting on this connection */
|
||||
WSF_ASSERT(pConn->fragmenting == FALSE);
|
||||
|
||||
hciLen = HciGetBufSize();
|
||||
|
||||
HCI_TRACE_INFO1("hciCoreTxAclStart len=%u", len);
|
||||
|
||||
/* if acl len > controller acl buf len */
|
||||
if (len > hciLen)
|
||||
{
|
||||
/* store remaining acl len = acl len - hci acl buf len */
|
||||
pConn->txAclRemLen = len - hciLen;
|
||||
|
||||
/* store position for next fragment */
|
||||
pConn->pNextTxFrag = pData + hciLen;
|
||||
|
||||
/* store information required for fragmentation */
|
||||
pConn->pTxAclPkt = pData;
|
||||
pConn->fragmenting = TRUE;
|
||||
|
||||
/* set acl len in packet to hci acl buf len */
|
||||
UINT16_TO_BUF(&pData[2], hciLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
|
||||
/* send additional fragments while there are HCI buffers available */
|
||||
while ((hciCoreCb.availBufs > 0) && hciCoreTxAclContinue(pConn));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no fragmentation, just send the packet */
|
||||
hciCoreSendAclData(pConn, pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send ACL packets, continuation of fragmented packets.
|
||||
*
|
||||
* \param pConn Pointer to connection structure. If set non-NULL, then a fragment is
|
||||
* sent from this connection structure. If NULL the function finds the next
|
||||
* connection structure with a fragment to be sent.
|
||||
*
|
||||
* \return TRUE if packet sent, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn)
|
||||
{
|
||||
uint16_t aclLen;
|
||||
|
||||
if (pConn == NULL)
|
||||
{
|
||||
pConn = hciCoreNextConnFragment();
|
||||
}
|
||||
|
||||
if (pConn != NULL)
|
||||
{
|
||||
/* get next fragment length */
|
||||
aclLen = (pConn->txAclRemLen < HciGetBufSize()) ? pConn->txAclRemLen : HciGetBufSize();
|
||||
|
||||
if (aclLen > 0)
|
||||
{
|
||||
/* decrement remaining length */
|
||||
pConn->txAclRemLen -= aclLen;
|
||||
|
||||
/* set handle in packet with continuation bit set */
|
||||
UINT16_TO_BUF(pConn->pNextTxFrag, (pConn->handle | HCI_PB_CONTINUE));
|
||||
|
||||
/* set acl len in packet */
|
||||
UINT16_TO_BUF(&(pConn->pNextTxFrag[2]), aclLen);
|
||||
|
||||
HCI_TRACE_INFO2("hciCoreTxAclContinue aclLen=%u remLen=%u", aclLen, pConn->txAclRemLen);
|
||||
|
||||
/* send the packet */
|
||||
hciCoreSendAclData(pConn, pConn->pNextTxFrag);
|
||||
|
||||
/* set up pointer to next fragment */
|
||||
if (pConn->txAclRemLen > 0)
|
||||
{
|
||||
pConn->pNextTxFrag += aclLen;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called from the HCI transport layer when transmission of an ACL
|
||||
* packet is complete.
|
||||
*
|
||||
* \param pConn Pointer to connection structure.
|
||||
* \param pData WSF buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData)
|
||||
{
|
||||
/* if fragmenting */
|
||||
if (pConn->fragmenting)
|
||||
{
|
||||
/* check if all fragments sent */
|
||||
if (pConn->txAclRemLen == 0)
|
||||
{
|
||||
/* free original buffer */
|
||||
WsfMsgFree(pConn->pTxAclPkt);
|
||||
pConn->pTxAclPkt = NULL;
|
||||
pConn->fragmenting = FALSE;
|
||||
HCI_TRACE_INFO0("hciCoreTxAclComplete free pTxAclPkt");
|
||||
}
|
||||
}
|
||||
else if (pData != NULL)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reassemble an ACL packet.
|
||||
*
|
||||
* \param pData Input ACL packet.
|
||||
*
|
||||
* \return pointer to ACL packet to send, or NULL if no packet to send.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *hciCoreAclReassembly(uint8_t *pData)
|
||||
{
|
||||
hciCoreConn_t *pConn;
|
||||
uint8_t *pDataRtn = NULL;
|
||||
uint16_t handle;
|
||||
uint16_t aclLen;
|
||||
uint16_t l2cLen;
|
||||
uint16_t pbf;
|
||||
bool_t freeData = TRUE;
|
||||
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
pbf = handle & HCI_PB_FLAG_MASK;
|
||||
handle &= HCI_HANDLE_MASK;
|
||||
BYTES_TO_UINT16(aclLen, &pData[2]);
|
||||
|
||||
/* look up connection */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if this is a start packet */
|
||||
if (pbf == HCI_PB_START_C2H)
|
||||
{
|
||||
/* if currently reassembled packet not complete */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
/* discard currently reassembled packet */
|
||||
WsfMsgFree(pConn->pRxAclPkt);
|
||||
pConn->pRxAclPkt = NULL;
|
||||
HCI_TRACE_WARN1("disarded hci rx pkt handle=0x%04x", handle);
|
||||
}
|
||||
|
||||
/* read l2cap length */
|
||||
if (aclLen >= L2C_HDR_LEN)
|
||||
{
|
||||
BYTES_TO_UINT16(l2cLen, &pData[4]);
|
||||
|
||||
/* check length vs. configured maximum */
|
||||
if ((l2cLen + L2C_HDR_LEN) > hciCoreCb.maxRxAclLen)
|
||||
{
|
||||
HCI_TRACE_WARN1("l2c len=0x%04x to large for reassembly", l2cLen);
|
||||
}
|
||||
/* if reassembly required */
|
||||
else if ((l2cLen + L2C_HDR_LEN) > aclLen)
|
||||
{
|
||||
/* allocate buffer to store complete l2cap packet */
|
||||
if ((pConn->pRxAclPkt = WsfMsgDataAlloc(l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN, 0)) != NULL)
|
||||
{
|
||||
/* store buffer for reassembly */
|
||||
pConn->pNextRxFrag = pConn->pRxAclPkt;
|
||||
|
||||
/* build acl header and copy data */
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, handle);
|
||||
UINT16_TO_BSTREAM(pConn->pNextRxFrag, l2cLen + L2C_HDR_LEN);
|
||||
memcpy(pConn->pNextRxFrag, &pData[4], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* store remaining length */
|
||||
pConn->rxAclRemLen = l2cLen + L2C_HDR_LEN - aclLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* alloc failed; discard */
|
||||
HCI_TRACE_WARN1("reassembly alloc failed len=%u", (l2cLen + L2C_HDR_LEN + HCI_ACL_HDR_LEN));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no reassembly required, pData is ready to go */
|
||||
pDataRtn = pData;
|
||||
freeData = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid l2cap packet; discard */
|
||||
HCI_TRACE_WARN1("invalid l2c pkt aclLen=%u", aclLen);
|
||||
}
|
||||
}
|
||||
/* else if this is a continuation packet */
|
||||
else if (pbf == HCI_PB_CONTINUE)
|
||||
{
|
||||
/* if expecting a continuation */
|
||||
if (pConn->pRxAclPkt != NULL)
|
||||
{
|
||||
if (aclLen <= pConn->rxAclRemLen)
|
||||
{
|
||||
/* copy data to start of next fragment */
|
||||
memcpy(pConn->pNextRxFrag, &pData[HCI_ACL_HDR_LEN], aclLen);
|
||||
pConn->pNextRxFrag += aclLen;
|
||||
|
||||
/* update remaining length */
|
||||
pConn->rxAclRemLen -= aclLen;
|
||||
|
||||
/* if reassembly complete return reassembled packet */
|
||||
if (pConn->rxAclRemLen == 0)
|
||||
{
|
||||
pDataRtn = pConn->pRxAclPkt;
|
||||
pConn->pRxAclPkt = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN2("continuation pkt too long len=%u RemLen=%u", aclLen, pConn->rxAclRemLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unexpected continuation pkt handle=0x%04x", handle);
|
||||
}
|
||||
}
|
||||
/* else unknown packet type */
|
||||
else
|
||||
{
|
||||
HCI_TRACE_WARN1("unknown pb flags=0x%04x", pbf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* connection not found */
|
||||
HCI_TRACE_WARN1("pkt rcvd on unknown handle=0x%04x", (handle & HCI_HANDLE_MASK));
|
||||
}
|
||||
|
||||
if (freeData)
|
||||
{
|
||||
WsfMsgFree(pData);
|
||||
}
|
||||
|
||||
return pDataRtn;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a TX ACL packet is being fragmented.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
*
|
||||
* \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn)
|
||||
{
|
||||
return pConn->fragmenting;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI core initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciCoreInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
WSF_QUEUE_INIT(&hciCoreCb.aclQueue);
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
hciCoreCb.conn[i].handle = HCI_HANDLE_NONE;
|
||||
}
|
||||
|
||||
hciCoreCb.maxRxAclLen = HCI_MAX_RX_ACL_LEN;
|
||||
hciCoreCb.aclQueueHi = HCI_ACL_QUEUE_HI;
|
||||
hciCoreCb.aclQueueLo = HCI_ACL_QUEUE_LO;
|
||||
hciCoreCb.extResetSeq = NULL;
|
||||
|
||||
hciCoreInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an HCI reset sequence.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciResetSequence(void)
|
||||
{
|
||||
/* set resetting state */
|
||||
hciCb.resetting = TRUE;
|
||||
|
||||
/* start the reset sequence */
|
||||
hciCoreResetStart();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the maximum reassembled RX ACL packet length. Minimum value is 27.
|
||||
*
|
||||
* \param len ACL packet length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetMaxRxAclLen(uint16_t len)
|
||||
{
|
||||
hciCoreCb.maxRxAclLen = len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set TX ACL queue high and low watermarks.
|
||||
*
|
||||
* \param queueHi Disable flow on a connection when this many ACL buffers are queued.
|
||||
* queueLo Disable flow on a connection when this many ACL buffers are queued.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetAclQueueWatermarks(uint8_t queueHi, uint8_t queueLo)
|
||||
{
|
||||
hciCoreCb.aclQueueHi = queueHi;
|
||||
hciCoreCb.aclQueueLo = queueLo;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set LE supported features configuration mask.
|
||||
*
|
||||
* \param feat Feature bit to set or clear
|
||||
* \param flag TRUE to set feature bit and FALSE to clear it
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSetLeSupFeat(uint32_t feat, bool_t flag)
|
||||
{
|
||||
/* if asked to include feature */
|
||||
if (flag)
|
||||
{
|
||||
/* set feature bit */
|
||||
hciLeSupFeatCfg |= feat;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear feature bit */
|
||||
hciLeSupFeatCfg &= ~feat;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send data from the stack to HCI.
|
||||
*
|
||||
* \param pData WSF buffer containing an ACL packet
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HciSendAclData(uint8_t *pData)
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
hciCoreConn_t *pConn;
|
||||
|
||||
/* parse handle and length */
|
||||
BYTES_TO_UINT16(handle, pData);
|
||||
BYTES_TO_UINT16(len, &pData[2]);
|
||||
|
||||
/* look up connection structure */
|
||||
if ((pConn = hciCoreConnByHandle(handle)) != NULL)
|
||||
{
|
||||
/* if queue empty and buffers available */
|
||||
if (WsfQueueEmpty(&hciCoreCb.aclQueue) && hciCoreCb.availBufs > 0)
|
||||
{
|
||||
/* send data */
|
||||
hciCoreTxAclStart(pConn, len, pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* queue data - message handler ID 'handerId' not used */
|
||||
WsfMsgEnq(&hciCoreCb.aclQueue, 0, pData);
|
||||
}
|
||||
|
||||
/* increment buffer queue count for this connection with consideration for HCI fragmentation */
|
||||
pConn->queuedBufs += ((len - 1) / HciGetBufSize()) + 1;
|
||||
|
||||
/* manage flow control to stack */
|
||||
if (pConn->queuedBufs >= hciCoreCb.aclQueueHi && pConn->flowDisabled == FALSE)
|
||||
{
|
||||
pConn->flowDisabled = TRUE;
|
||||
(*hciCb.flowCback)(handle, TRUE);
|
||||
}
|
||||
}
|
||||
/* connection not found, connection must be closed */
|
||||
else
|
||||
{
|
||||
/* discard buffer */
|
||||
WsfMsgFree(pData);
|
||||
|
||||
HCI_TRACE_WARN1("HciSendAclData discarding buffer, handle=%u", handle);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file hci_tr.c
|
||||
*
|
||||
* \brief HCI transport 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_api.h"
|
||||
#include "hci_core.h"
|
||||
#include "hci_tr.h"
|
||||
#include "ll_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn hciTrSendAclData
|
||||
*
|
||||
* \brief Send a complete HCI ACL packet to the transport.
|
||||
*
|
||||
* \param pContext Connection context.
|
||||
* \param pData WSF msg buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hciTrSendAclData(void *pContext, uint8_t *pData)
|
||||
{
|
||||
uint16_t len;
|
||||
uint8_t *p;
|
||||
|
||||
/* if fragmenting */
|
||||
if (hciCoreTxAclDataFragmented(pContext))
|
||||
{
|
||||
/* get 16-bit length */
|
||||
BYTES_TO_UINT16(len, (pData + 2))
|
||||
len += HCI_ACL_HDR_LEN;
|
||||
|
||||
/* allocate LL buffer */
|
||||
if ((p = WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM)) != NULL)
|
||||
{
|
||||
/* copy data */
|
||||
memcpy(p, pData, len);
|
||||
|
||||
/* send to LL */
|
||||
LlSendAclData(p);
|
||||
|
||||
/* free HCI buffer */
|
||||
hciCoreTxAclComplete(pContext, pData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send to LL */
|
||||
LlSendAclData(pData);
|
||||
|
||||
/* LL will free HCI buffer */
|
||||
hciCoreTxAclComplete(pContext, NULL);
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief AES and random number security service implemented using HCI.
|
||||
*
|
||||
* 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_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Returns the next token.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t getNextToken()
|
||||
{
|
||||
uint8_t token = secCb.token++;
|
||||
|
||||
if (token == SEC_TOKEN_INVALID)
|
||||
{
|
||||
token = secCb.token++;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
|
||||
* sent to the specified handler. This function returns a token value that
|
||||
* the client can use to match calls to this function with messages.
|
||||
*
|
||||
* \param pKey Pointer to 16 byte key.
|
||||
* \param pPlaintext Pointer to 16 byte plaintext.
|
||||
* \param handlerId WSF handler ID.
|
||||
* \param param Client-defined parameter returned in message.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t SecAes(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
|
||||
/* allocate a buffer */
|
||||
if ((pBuf = WsfMsgAlloc(sizeof(secQueueBuf_t))) != NULL)
|
||||
{
|
||||
pBuf->msg.hdr.status = getNextToken();
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
|
||||
pBuf->type = SEC_TYPE_AES;
|
||||
|
||||
/* queue buffer */
|
||||
WsfMsgEnq(&secCb.aesEncQueue, handlerId, pBuf);
|
||||
|
||||
/* call HCI encrypt function */
|
||||
HciLeEncryptCmd(pKey, pPlaintext);
|
||||
|
||||
return pBuf->msg.hdr.status;
|
||||
}
|
||||
|
||||
return SEC_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for AES operations.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
secAes_t *pAes = (secAes_t *) &pBuf->msg;
|
||||
|
||||
/* set encrypted data pointer and copy */
|
||||
pAes->pCiphertext = pBuf->ciphertext;
|
||||
Calc128Cpy(pAes->pCiphertext, pEvent->leEncryptCmdCmpl.data);
|
||||
|
||||
/* send message */
|
||||
WsfMsgSend(handlerId, pAes);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize AES secuirity.
|
||||
*
|
||||
* \param none.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesInit()
|
||||
{
|
||||
secCb.hciCbackTbl[SEC_TYPE_AES] = SecAesHciCback;
|
||||
}
|
||||
Vendored
+137
@@ -0,0 +1,137 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief AES and random number security service implemented using HCI.
|
||||
*
|
||||
* 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_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Returns the next token.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t getNextToken()
|
||||
{
|
||||
uint8_t token = secCb.token++;
|
||||
|
||||
if (token == SEC_TOKEN_INVALID)
|
||||
{
|
||||
token = secCb.token++;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute an AES calculation. When the calculation completes, a WSF message will be
|
||||
* sent to the specified handler. This function returns a token value that
|
||||
* the client can use to match calls to this function with messages. Note this version
|
||||
* reverses the key and plaintext bytes.
|
||||
*
|
||||
* \param pKey Pointer to 16 byte key.
|
||||
* \param pPlaintext Pointer to 16 byte plaintext.
|
||||
* \param handlerId WSF handler ID.
|
||||
* \param param Client-defined parameter returned in message.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return Token value.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t SecAesRev(uint8_t *pKey, uint8_t *pPlaintext, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
|
||||
/* allocate a buffer */
|
||||
if ((pBuf = WsfMsgAlloc(sizeof(secQueueBuf_t))) != NULL)
|
||||
{
|
||||
pBuf->msg.hdr.status = getNextToken();
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
|
||||
pBuf->type = SEC_TYPE_AES_REV;
|
||||
|
||||
/* call HCI encrypt function */
|
||||
SecLeEncryptCmd(pKey, pPlaintext, pBuf, handlerId);
|
||||
|
||||
return pBuf->msg.hdr.status;
|
||||
}
|
||||
|
||||
return SEC_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for AES operations. Note this version reverses the
|
||||
* ciphertext bytes.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesRevHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
secAes_t *pAes = (secAes_t *) &pBuf->msg;
|
||||
|
||||
/* set encrypted data pointer and copy */
|
||||
pAes->pCiphertext = pBuf->ciphertext;
|
||||
|
||||
Calc128Cpy(pAes->pCiphertext, pEvent->leEncryptCmdCmpl.data);
|
||||
|
||||
/* send message */
|
||||
WsfMsgSend(handlerId, pAes);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize AES secuirity.
|
||||
*
|
||||
* \param none.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecAesRevInit()
|
||||
{
|
||||
secCb.hciCbackTbl[SEC_TYPE_AES_REV] = SecAesRevHciCback;
|
||||
}
|
||||
Vendored
+595
@@ -0,0 +1,595 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Counter with CBC-MAC (CCM) mode security - HCI AES.
|
||||
*
|
||||
* 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_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
|
||||
#ifndef SEC_CCM_CFG
|
||||
#define SEC_CCM_CFG SEC_CCM_CFG_HCI
|
||||
#endif
|
||||
|
||||
#if SEC_CCM_CFG == SEC_CCM_CFG_HCI
|
||||
|
||||
/**************************************************************************************************
|
||||
Constants
|
||||
**************************************************************************************************/
|
||||
|
||||
/* State machine states */
|
||||
enum
|
||||
{
|
||||
SEC_CCM_STATE_XI_HDR,
|
||||
SEC_CCM_STATE_XI_MSG,
|
||||
SEC_CCM_STATE_S0,
|
||||
SEC_CCM_STATE_SI,
|
||||
SEC_CCM_STATE_MIC_COMPLETE,
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Global security control block */
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Exclusive-or two 128-bit integers and return the result in pDst.
|
||||
*
|
||||
* \param pDst Pointer to destination.
|
||||
* \param pSrc Pointer to source.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmCalcXor(uint8_t *pDst, uint8_t *pSrc, uint8_t size)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
*pDst++ ^= *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmBlockEncrypt
|
||||
*
|
||||
* \brief Perform a 16-byte block encryption (HCI AES)
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param pText Pointer to text to encrypt (16 bytes).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmBlockEncrypt(secQueueBuf_t *pBuf, uint8_t *pText)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
SecLeEncryptCmd(pCcm->key, pText, pBuf, pCcm->handlerId);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenX0
|
||||
*
|
||||
* \brief Generate X_0 := E(K, B_0)
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenX0(secQueueBuf_t *pBuf)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
|
||||
/* Scratch buffer contains nonce, add flags and message length */
|
||||
pCcm->scratch[0] = (SEC_CCM_L - 1) | (((pCcm->micLen - 2) / 2) << 3) | ((pCcm->clearLen > 0? 1:0) << 6);
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->textLen >> 8;
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 1] = pCcm->textLen & 0xFF;
|
||||
|
||||
pCcm->state = pCcm->clearLen > 0 ? SEC_CCM_STATE_XI_HDR : SEC_CCM_STATE_XI_MSG;
|
||||
pCcm->position = 0;
|
||||
|
||||
/* AES Operation */
|
||||
secCcmBlockEncrypt(pBuf, pCcm->scratch);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenXiHdr
|
||||
*
|
||||
* \brief Generate X_i header if clear text (additional data) is present.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param pPriorX 16 byte buffer containing X_i-1.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenXiHdr(secQueueBuf_t *pBuf, uint8_t *pPriorX)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
uint8_t b_i[SEC_BLOCK_LEN];
|
||||
uint16_t remaining;
|
||||
uint16_t offset = 0;
|
||||
|
||||
if (pCcm->position == 0)
|
||||
{
|
||||
/* Copy additional data into working buffer */
|
||||
memcpy(pCcm->pWorking, pCcm->pClear, pCcm->clearLen);
|
||||
|
||||
/* First two bytes of b_0 contain length of additional data */
|
||||
b_i[0] = pCcm->clearLen >> 8;
|
||||
b_i[1] = pCcm->clearLen & 0xFF;
|
||||
pCcm->position = offset = 2;
|
||||
}
|
||||
|
||||
remaining = (int16_t) pCcm->clearLen - pCcm->position + 2;
|
||||
|
||||
/* Copy additional to b_i */
|
||||
if (remaining >= SEC_BLOCK_LEN - offset)
|
||||
{
|
||||
memcpy(b_i + offset, pCcm->pClear + pCcm->position - 2, SEC_BLOCK_LEN - offset);
|
||||
pCcm->position += SEC_BLOCK_LEN - offset;
|
||||
|
||||
if (remaining == SEC_BLOCK_LEN - offset)
|
||||
{
|
||||
pCcm->state = SEC_CCM_STATE_XI_MSG;
|
||||
pCcm->position = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(b_i + offset, pCcm->pClear + pCcm->position - 2, remaining);
|
||||
memset(b_i + offset + remaining, 0, SEC_BLOCK_LEN - remaining - offset);
|
||||
pCcm->state = SEC_CCM_STATE_XI_MSG;
|
||||
pCcm->position = 0;
|
||||
}
|
||||
|
||||
/* X_i XOR B_i */
|
||||
Calc128Xor(b_i, pPriorX);
|
||||
|
||||
/* AES Operation */
|
||||
secCcmBlockEncrypt(pBuf, b_i);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenXiMsg
|
||||
*
|
||||
* \brief Generate X_i for the message text.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param pPriorX 16 byte buffer containing X_i-1.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenXiMsg(secQueueBuf_t *pBuf, uint8_t *pPriorX)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
uint8_t b_i[SEC_BLOCK_LEN];
|
||||
uint16_t remaining = (int16_t) pCcm->textLen - pCcm->position;
|
||||
|
||||
/* Copy data to b_i */
|
||||
if (remaining >= SEC_BLOCK_LEN)
|
||||
{
|
||||
Calc128Cpy(b_i, pCcm->pText + pCcm->position);
|
||||
pCcm->position += SEC_BLOCK_LEN;
|
||||
|
||||
if (remaining == SEC_BLOCK_LEN)
|
||||
{
|
||||
pCcm->state = SEC_CCM_STATE_S0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(b_i, pCcm->pText + pCcm->position, remaining);
|
||||
memset(b_i + remaining, 0, SEC_BLOCK_LEN - remaining);
|
||||
pCcm->state = SEC_CCM_STATE_S0;
|
||||
}
|
||||
|
||||
/* X_i XOR B_i */
|
||||
Calc128Xor(b_i, pPriorX);
|
||||
|
||||
/* AES Operation */
|
||||
secCcmBlockEncrypt(pBuf, b_i);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenS0
|
||||
*
|
||||
* \brief Generate S_0 := E(K, A_0)
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param x_n 16 byte buffer containing X_n (containing T).
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenS0(secQueueBuf_t *pBuf, uint8_t *x_n)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
uint16_t offset = pCcm->textLen + pCcm->clearLen;
|
||||
|
||||
/* Copy T to working buffer */
|
||||
memcpy(pCcm->pWorking + offset, x_n, pCcm->micLen);
|
||||
|
||||
/* Scratch buffer contains nonce, add flags and counter */
|
||||
pCcm->scratch[0] = (SEC_CCM_L - 1);
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->scratch[SEC_BLOCK_LEN - 1] = 0;
|
||||
|
||||
pCcm->state = SEC_CCM_STATE_MIC_COMPLETE;
|
||||
|
||||
/* AES Operation */
|
||||
secCcmBlockEncrypt(pBuf, pCcm->scratch);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenS1
|
||||
*
|
||||
* \brief Generate S_1 := E(K, A_1)
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenS1(secQueueBuf_t *pBuf)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
|
||||
/* Set counter. */
|
||||
pCcm->counter = 1;
|
||||
|
||||
/* Scratch buffer contains nonce, add flags and counter. */
|
||||
pCcm->scratch[0] = (SEC_CCM_L - 1);
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 2] = 0;
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 1] = 1;
|
||||
|
||||
/* Change state to S_i state. */
|
||||
pCcm->state = SEC_CCM_STATE_SI;
|
||||
|
||||
/* AES Operation. */
|
||||
secCcmBlockEncrypt(pBuf, pCcm->scratch);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmMicComplete
|
||||
*
|
||||
* \brief Called when MIC calculation is complete.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param s_0 16 byte buffer containing S_0.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmMicComplete(secQueueBuf_t *pBuf, uint8_t *s_0)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
int16_t micOffset;
|
||||
|
||||
/* MIC = s_0 XOR T (store in result buffer). */
|
||||
micOffset = pCcm->textLen + pCcm->clearLen;
|
||||
secCcmCalcXor(pCcm->pWorking + micOffset, s_0, pCcm->micLen);
|
||||
|
||||
if (pCcm->operation == SEC_CCM_OP_ENCRYPT)
|
||||
{
|
||||
/* When encrypting, continue S_i calculations */
|
||||
secCcmGenS1(pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Decryption complete. Send notification. */
|
||||
secCcmDecMsg_t *pMsg = (secCcmDecMsg_t *) &pBuf->msg;
|
||||
|
||||
/* Verify MIC value */
|
||||
if (memcmp(pCcm->pRcvMic, pCcm->pWorking + micOffset, pCcm->micLen) == 0)
|
||||
{
|
||||
pMsg->pText = pCcm->pWorking + pCcm->clearLen;
|
||||
pMsg->textLen = pCcm->textLen;
|
||||
pMsg->success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->pText = NULL;
|
||||
pMsg->textLen = 0;
|
||||
pMsg->success = FALSE;
|
||||
}
|
||||
|
||||
WsfMsgSend(pCcm->handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn secCcmGenSi
|
||||
*
|
||||
* \brief Generate S_i := E(K, A_i)
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CCM algorithm control block.
|
||||
* \param pPriorS 16 byte buffer containing S_i-1.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCcmGenSi(secQueueBuf_t *pBuf, uint8_t *pPriorS)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t*) pBuf->pCb;
|
||||
int16_t resultOffset = 0;
|
||||
uint16_t len;
|
||||
|
||||
/* Determine length of XOR operation. */
|
||||
len = pCcm->textLen - ((pCcm->counter - 1) * SEC_BLOCK_LEN);
|
||||
len = len > SEC_BLOCK_LEN? SEC_BLOCK_LEN : len;
|
||||
|
||||
/* m_i XOR s_i+1. */
|
||||
resultOffset = (pCcm->counter - 1) * SEC_BLOCK_LEN + pCcm->clearLen;
|
||||
|
||||
secCcmCalcXor(pCcm->pWorking + resultOffset, pPriorS, (uint8_t) len);
|
||||
|
||||
if (pCcm->counter * SEC_BLOCK_LEN >= pCcm->textLen)
|
||||
{
|
||||
if (pCcm->operation == SEC_CCM_OP_ENCRYPT)
|
||||
{
|
||||
/* Encription complete. Send notification. */
|
||||
secCcmEncMsg_t *pMsg = (secCcmEncMsg_t *) &pBuf->msg;
|
||||
|
||||
pMsg->pCiphertext = pCcm->pWorking;
|
||||
pMsg->textLen = pCcm->textLen + pCcm->clearLen + pCcm->micLen;
|
||||
WsfMsgSend(pCcm->handlerId, pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set pText to point to the decrypted result in pWorking */
|
||||
pCcm->pText = pCcm->pWorking + pCcm->clearLen;
|
||||
|
||||
/* Begin calculating the MIC */
|
||||
secCcmGenX0(pBuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update counter. */
|
||||
pCcm->counter++;
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 2] = pCcm->counter >> 8;
|
||||
pCcm->scratch[SEC_BLOCK_LEN - 1] = pCcm->counter & 0xFF;
|
||||
|
||||
/* AES Operation. */
|
||||
secCcmBlockEncrypt(pBuf, pCcm->scratch);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn SecCcmBlockEncryptCmpl
|
||||
*
|
||||
* \brief Called when a block encryption operation completes.
|
||||
*
|
||||
* \param pParam Pointer to security control block.
|
||||
* \param pCypherText Pointer to encrypt result.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCcmHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) pBuf->pCb;
|
||||
|
||||
switch (pCcm->state)
|
||||
{
|
||||
case SEC_CCM_STATE_XI_HDR:
|
||||
secCcmGenXiHdr(pBuf, pEvent->leEncryptCmdCmpl.data);
|
||||
break;
|
||||
|
||||
case SEC_CCM_STATE_XI_MSG:
|
||||
secCcmGenXiMsg(pBuf, pEvent->leEncryptCmdCmpl.data);
|
||||
break;
|
||||
|
||||
case SEC_CCM_STATE_S0:
|
||||
secCcmGenS0(pBuf, pEvent->leEncryptCmdCmpl.data);
|
||||
break;
|
||||
|
||||
case SEC_CCM_STATE_SI:
|
||||
secCcmGenSi(pBuf, pEvent->leEncryptCmdCmpl.data);
|
||||
break;
|
||||
|
||||
case SEC_CCM_STATE_MIC_COMPLETE:
|
||||
secCcmMicComplete(pBuf, pEvent->leEncryptCmdCmpl.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn SecCcmEnc
|
||||
*
|
||||
* \brief Execute the CCM-Mode encryption algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pPlainText Pointer to text to encrypt.
|
||||
* \param textLen Length of pPlainText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
|
||||
wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCcmSecCb_t);
|
||||
|
||||
WSF_ASSERT(clearLen < SEC_CCM_MAX_ADDITIONAL_LEN);
|
||||
|
||||
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) (pBuf + 1);
|
||||
|
||||
/* Setup queue buffer */
|
||||
pBuf->pCb = pCcm;
|
||||
pBuf->type = SEC_TYPE_CCM;
|
||||
|
||||
pBuf->msg.hdr.status = secCb.token++;
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
|
||||
pCcm->handlerId = handlerId;
|
||||
|
||||
pCcm->pText = pPlainText;
|
||||
pCcm->textLen = textLen;
|
||||
pCcm->pClear = pClear;
|
||||
pCcm->pWorking = pResult;
|
||||
pCcm->clearLen = clearLen;
|
||||
pCcm->micLen = micLen;
|
||||
pCcm->counter = 0;
|
||||
|
||||
memcpy(pCcm->pWorking + clearLen, pPlainText, textLen);
|
||||
memcpy(&pCcm->scratch[1], pNonce, SEC_CCM_NONCE_LEN);
|
||||
Calc128Cpy(pCcm->key, (uint8_t *) pKey);
|
||||
|
||||
pCcm->operation = SEC_CCM_OP_ENCRYPT;
|
||||
|
||||
/* Begin encryption of text by generation of X_0 */
|
||||
secCcmGenX0(pBuf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn SecCcmDec
|
||||
*
|
||||
* \brief Execute the CCM-Mode verify and decrypt algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pCypherText Pointer to text to decrypt.
|
||||
* \param textLen Length of pCypherText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param pMic Pointer to authentication digest.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
|
||||
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCcmSecCb_t);
|
||||
|
||||
WSF_ASSERT(clearLen < SEC_CCM_MAX_ADDITIONAL_LEN);
|
||||
|
||||
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
|
||||
{
|
||||
secCcmSecCb_t *pCcm = (secCcmSecCb_t *) (pBuf + 1);
|
||||
|
||||
/* Setup queue buffer */
|
||||
pBuf->pCb = pCcm;
|
||||
pBuf->type = SEC_TYPE_CCM;
|
||||
|
||||
pBuf->msg.hdr.status = secCb.token++;
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
|
||||
pCcm->handlerId = handlerId;
|
||||
|
||||
pCcm->pClear = pClear;
|
||||
pCcm->pRcvMic = pMic;
|
||||
pCcm->pWorking = pResult;
|
||||
pCcm->textLen = textLen;
|
||||
pCcm->clearLen = clearLen;
|
||||
pCcm->micLen = micLen;
|
||||
pCcm->counter = 0;
|
||||
|
||||
/* Prepare the working buffer */
|
||||
memcpy(pCcm->pWorking, pClear, clearLen);
|
||||
memcpy(pCcm->pWorking + clearLen, pCypherText, textLen);
|
||||
memcpy(pCcm->pWorking + clearLen + textLen, pMic, micLen);
|
||||
|
||||
memcpy(&pCcm->scratch[1], pNonce, SEC_CCM_NONCE_LEN);
|
||||
Calc128Cpy(pCcm->key, (uint8_t *) pKey);
|
||||
|
||||
pCcm->operation = SEC_CCM_OP_DECRYPT;
|
||||
|
||||
/* Begin decryption of text by generation of S_1 */
|
||||
secCcmGenS1(pBuf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn SecCcmInit
|
||||
*
|
||||
* \brief Called to initialize CCM-Mode security.
|
||||
*
|
||||
* \param None.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCcmInit(void)
|
||||
{
|
||||
secCb.hciCbackTbl[SEC_TYPE_CCM] = SecCcmHciCback;
|
||||
}
|
||||
|
||||
#endif /* SEC_CCM_CFG */
|
||||
Vendored
+323
@@ -0,0 +1,323 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief AES and random number security service implemented using HCI.
|
||||
*
|
||||
* Copyright (c) 2010-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_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
|
||||
#ifndef SEC_CMAC_CFG
|
||||
#define SEC_CMAC_CFG SEC_CMAC_CFG_HCI
|
||||
#endif
|
||||
|
||||
#if SEC_CMAC_CFG == SEC_CMAC_CFG_HCI
|
||||
|
||||
enum
|
||||
{
|
||||
SEC_CMAC_STATE_SUBKEY,
|
||||
SEC_CMAC_STATE_BLOCK,
|
||||
SEC_CMAC_STATE_COMPLETE,
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Continue the execution of the CMAC algorithm over the next message block.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CMAC algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCmacProcessBlock(secQueueBuf_t *pBuf)
|
||||
{
|
||||
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
|
||||
uint8_t text[SEC_BLOCK_LEN];
|
||||
uint8_t *pMn = pCmac->pPlainText + pCmac->position;
|
||||
int16_t remaining = (int16_t) pCmac->len - pCmac->position;
|
||||
|
||||
/* Check for Last Block */
|
||||
if (remaining <= SEC_BLOCK_LEN)
|
||||
{
|
||||
memcpy(text, pMn, remaining);
|
||||
|
||||
/* Pad the message if necessary */
|
||||
if (remaining != SEC_BLOCK_LEN)
|
||||
{
|
||||
memset(text + remaining, 0, SEC_BLOCK_LEN - remaining);
|
||||
text[remaining] = 0x80;
|
||||
}
|
||||
|
||||
/* XOr the subkey */
|
||||
Calc128Xor(text, pCmac->subkey);
|
||||
pCmac->state = SEC_CMAC_STATE_COMPLETE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the block to the buffer */
|
||||
Calc128Cpy(text, pMn);
|
||||
}
|
||||
|
||||
if (pCmac->position != 0)
|
||||
{
|
||||
/* Except for first block, XOr the previous AES calculation */
|
||||
Calc128Xor(text, pBuf->ciphertext);
|
||||
}
|
||||
|
||||
pCmac->position += SEC_BLOCK_LEN;
|
||||
|
||||
SecLeEncryptCmd(pCmac->key, text, pBuf, pCmac->handlerId);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Step 1 to generate the subkey used in the CMAC algorithm.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CMAC algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCmacGenSubkey1(secQueueBuf_t *pBuf)
|
||||
{
|
||||
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
|
||||
uint8_t buf[SEC_BLOCK_LEN];
|
||||
|
||||
/* Perform aes on the key with a constant zero */
|
||||
memset(buf, 0, SEC_BLOCK_LEN);
|
||||
|
||||
SecLeEncryptCmd(pCmac->key, buf, pBuf, pCmac->handlerId);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Left shift a buffer of WSF_CMAC_KEY_LEN bytes by N bits.
|
||||
*
|
||||
* \param pBuf Buffer to left shift.
|
||||
* \param shift Number of bits to shift.
|
||||
*
|
||||
* \return The overflow of the operaiton.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t secCmacKeyShift(uint8_t *pBuf, uint8_t shift)
|
||||
{
|
||||
uint8_t overflow, i;
|
||||
uint8_t finalOverflow = pBuf[0] >> (8 - shift);
|
||||
|
||||
for (i = 0; i < SEC_CMAC_KEY_LEN; i++)
|
||||
{
|
||||
/* store shifted bits for next byte */
|
||||
if (i < SEC_CMAC_KEY_LEN-1)
|
||||
{
|
||||
overflow = pBuf[i+1] >> (8 - shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
overflow = 0;
|
||||
}
|
||||
|
||||
/* shift byte and OR in shifted bits from previous byte */
|
||||
pBuf[i] = (pBuf[i] << shift) | overflow;
|
||||
}
|
||||
|
||||
return finalOverflow;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Complete generation of the subkey used in the CMAC algorithm.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CMAC algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCmacGenSubkey2(secQueueBuf_t *pBuf)
|
||||
{
|
||||
secCmacSecCb_t *pCmac = (secCmacSecCb_t*) pBuf->pCb;
|
||||
uint8_t overflow;
|
||||
|
||||
/* Copy the result of the AES oepration */
|
||||
Calc128Cpy(pCmac->subkey, pBuf->ciphertext);
|
||||
|
||||
/* Calculate the K1 subkey */
|
||||
overflow = secCmacKeyShift(pCmac->subkey, 1);
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
pCmac->subkey[SEC_BLOCK_LEN-1] ^= SEC_CMAC_RB;
|
||||
}
|
||||
|
||||
if (pCmac->len % SEC_BLOCK_LEN != 0)
|
||||
{
|
||||
/* If the message len is not a multiple of SEC_BLOCK_LEN */
|
||||
/* Continue with generation of the K2 subkey based on the K1 key */
|
||||
overflow = secCmacKeyShift(pCmac->subkey, 1);
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
pCmac->subkey[SEC_BLOCK_LEN-1] ^= SEC_CMAC_RB;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin CMAC calculation */
|
||||
pCmac->state = SEC_CMAC_STATE_BLOCK;
|
||||
secCmacProcessBlock(pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a message to the handler with CMAC result.
|
||||
*
|
||||
* \param pBuf Security queue buffer containing CMAC algorithm control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secCmacComplete(secQueueBuf_t *pBuf)
|
||||
{
|
||||
/* CMAC is complete, copy and send result to handler */
|
||||
secCmacMsg_t *pMsg = (secCmacMsg_t *) &pBuf->msg;
|
||||
secCmacSecCb_t *pCmac = (secCmacSecCb_t *) pBuf->pCb;
|
||||
|
||||
pMsg->pCiphertext = pBuf->ciphertext;
|
||||
pMsg->pPlainText = pCmac->pPlainText;
|
||||
|
||||
WsfMsgSend(pCmac->handlerId, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for CMAC operations.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCmacHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
secCmacSecCb_t *pCmac = (secCmacSecCb_t *) pBuf->pCb;
|
||||
|
||||
if (pCmac)
|
||||
{
|
||||
Calc128Cpy(pBuf->ciphertext, pEvent->leEncryptCmdCmpl.data);
|
||||
|
||||
switch (pCmac->state)
|
||||
{
|
||||
case SEC_CMAC_STATE_SUBKEY:
|
||||
secCmacGenSubkey2(pBuf);
|
||||
break;
|
||||
|
||||
case SEC_CMAC_STATE_BLOCK:
|
||||
secCmacProcessBlock(pBuf);
|
||||
break;
|
||||
|
||||
case SEC_CMAC_STATE_COMPLETE:
|
||||
secCmacComplete(pBuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the CMAC algorithm.
|
||||
*
|
||||
* \param pKey Key used in CMAC operation.
|
||||
* \param pPlainText Data to perform CMAC operation over
|
||||
* \param len Size of pPlaintext in bytes.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCmac(const uint8_t *pKey, uint8_t *pPlainText, uint16_t textLen, wsfHandlerId_t handlerId,
|
||||
uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secCmacSecCb_t);
|
||||
|
||||
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
|
||||
{
|
||||
secCmacSecCb_t *pCmacCb = (secCmacSecCb_t *) (pBuf + 1);
|
||||
|
||||
/* Setup queue buffer */
|
||||
pBuf->pCb = pCmacCb;
|
||||
pBuf->type = SEC_TYPE_CMAC;
|
||||
|
||||
pBuf->msg.hdr.status = secCb.token++;
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
|
||||
pCmacCb->pPlainText = pPlainText;
|
||||
|
||||
pCmacCb->len = textLen;
|
||||
pCmacCb->position = 0;
|
||||
pCmacCb->handlerId = handlerId;
|
||||
pCmacCb->state = SEC_CMAC_STATE_SUBKEY;
|
||||
|
||||
/* Copy key */
|
||||
Calc128Cpy(pCmacCb->key, (uint8_t *) pKey);
|
||||
|
||||
/* Start the CMAC process by calculating the subkey */
|
||||
secCmacGenSubkey1(pBuf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize CMAC security.
|
||||
*
|
||||
* \param None.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCmacInit()
|
||||
{
|
||||
secCb.hciCbackTbl[SEC_TYPE_CMAC] = SecCmacHciCback;
|
||||
}
|
||||
|
||||
#endif /* SEC_CMAC_CFG */
|
||||
Vendored
+160
@@ -0,0 +1,160 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Security ECC implementation using debug keys.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
|
||||
#ifndef SEC_ECC_CFG
|
||||
#define SEC_ECC_CFG SEC_ECC_CFG_DEBUG
|
||||
#endif
|
||||
|
||||
#if SEC_ECC_CFG == SEC_ECC_CFG_DEBUG
|
||||
|
||||
/* Debug Keys */
|
||||
static const uint8_t debugPrivateKey[] = {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};
|
||||
|
||||
static const uint8_t debugPublicKeyX[] = {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};
|
||||
|
||||
static const uint8_t debugPublicKeyY[] = {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};
|
||||
|
||||
static const uint8_t debugSharedSecret[] = {0x49, 0x4c, 0xfd, 0x99, 0x6f, 0x40, 0x17, 0xf5,
|
||||
0xb5, 0x48, 0xba, 0x66, 0x99, 0x60, 0x64, 0x08,
|
||||
0x62, 0x75, 0xd5, 0x1f, 0xe0, 0x8e, 0x56, 0x36,
|
||||
0xb9, 0x36, 0xd1, 0xe4, 0x57, 0x46, 0x4b, 0xed};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for ECC operations.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
|
||||
|
||||
if (pMsg)
|
||||
{
|
||||
/* Generate the keys */
|
||||
memcpy(pMsg->data.key.pubKey_x, debugPublicKeyX, SEC_ECC_KEY_LEN);
|
||||
memcpy(pMsg->data.key.pubKey_y, debugPublicKeyY, SEC_ECC_KEY_LEN);
|
||||
memcpy(pMsg->data.key.privKey, debugPrivateKey, SEC_ECC_KEY_LEN);
|
||||
|
||||
/* Send shared secret to handler */
|
||||
pMsg->hdr.event = event;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param pKey ECC Key structure.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
|
||||
|
||||
if (pMsg)
|
||||
{
|
||||
memcpy(pMsg->data.sharedSecret.secret, debugSharedSecret, SEC_ECC_KEY_LEN);
|
||||
|
||||
/* Send shared secret to handler */
|
||||
pMsg->hdr.event = event;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize ECC security.
|
||||
*
|
||||
* \param None.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccInit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif /* SEC_ECC_CFG */
|
||||
Vendored
+183
@@ -0,0 +1,183 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief WSF Security ECC implementation using HCI.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
|
||||
#ifndef SEC_ECC_CFG
|
||||
#define SEC_ECC_CFG SEC_ECC_CFG_HCI
|
||||
#endif
|
||||
|
||||
#if SEC_ECC_CFG == SEC_ECC_CFG_HCI
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
extern secCb_t secCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for ECC operations.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
secEccMsg_t *pMsg = (secEccMsg_t *) &pBuf->msg;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT)
|
||||
{
|
||||
/* Reverse copy the public key (to big endian) */
|
||||
WStrReverseCpy(pMsg->data.key.pubKey_x, pEvent->leP256.key, SEC_ECC_KEY_LEN);
|
||||
WStrReverseCpy(pMsg->data.key.pubKey_y, pEvent->leP256.key + SEC_ECC_KEY_LEN, SEC_ECC_KEY_LEN);
|
||||
|
||||
/* Send shared secret to handler */
|
||||
pMsg->hdr.status = pEvent->leP256.status;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT)
|
||||
{
|
||||
/* Reverse copy the DH key (to big endian) */
|
||||
WStrReverseCpy(pMsg->data.sharedSecret.secret, pEvent->leGenDHKey.key, SEC_ECC_KEY_LEN);
|
||||
|
||||
/* Send shared secret to handler */
|
||||
pMsg->hdr.status = pEvent->leGenDHKey.status;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secEccMsg_t);
|
||||
|
||||
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
|
||||
{
|
||||
/* Record the event and parameter for use in the HCI response */
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
pBuf->type = SEC_TYPE_DH;
|
||||
|
||||
/* queue buffer */
|
||||
WsfMsgEnq(&secCb.pubKeyQueue, handlerId, pBuf);
|
||||
|
||||
/* Request the local public key via HCI */
|
||||
HciLeReadLocalP256PubKey();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param pKey ECC Key structure.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secQueueBuf_t *pBuf;
|
||||
uint16_t bufSize = sizeof(secQueueBuf_t) + sizeof(secEccMsg_t);
|
||||
|
||||
if ((pBuf = WsfMsgAlloc(bufSize)) != NULL)
|
||||
{
|
||||
uint8_t pubKeyX[SEC_ECC_KEY_LEN];
|
||||
uint8_t pubKeyY[SEC_ECC_KEY_LEN];
|
||||
|
||||
/* Record the event and parameter for use in the HCI response */
|
||||
pBuf->msg.hdr.param = param;
|
||||
pBuf->msg.hdr.event = event;
|
||||
pBuf->type = SEC_TYPE_DH;
|
||||
|
||||
/* queue buffer */
|
||||
WsfMsgEnq(&secCb.dhKeyQueue, handlerId, pBuf);
|
||||
|
||||
/* Reverse keys (to little endian) */
|
||||
WStrReverseCpy(pubKeyX, pKey->pubKey_x, SEC_ECC_KEY_LEN);
|
||||
WStrReverseCpy(pubKeyY, pKey->pubKey_y, SEC_ECC_KEY_LEN);
|
||||
|
||||
/* Request the DH Key via HCI */
|
||||
HciLeGenerateDHKey(pubKeyX, pubKeyY);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize ECC security.
|
||||
*
|
||||
* \param None.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccInit()
|
||||
{
|
||||
secCb.hciCbackTbl[SEC_TYPE_DH] = SecEccHciCback;
|
||||
}
|
||||
|
||||
#endif /* SEC_ECC_CFG */
|
||||
Vendored
+195
@@ -0,0 +1,195 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Security service implemented using HCI.
|
||||
*
|
||||
* Copyright (c) 2010-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_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
// #include "pal_crypto.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Security Control block */
|
||||
secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption and random number events.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void secHciCback(hciEvt_t *pEvent)
|
||||
{
|
||||
secQueueBuf_t *pBuf = NULL;
|
||||
wsfHandlerId_t handlerId = 0;
|
||||
|
||||
/* Handle random number event. */
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_RAND_CMD_CMPL_CBACK_EVT:
|
||||
|
||||
/* Copy new data to circular buffer of random data. */
|
||||
memcpy(&secCb.rand[HCI_RAND_LEN * secCb.randTop], pEvent->leRandCmdCmpl.randNum, HCI_RAND_LEN);
|
||||
secCb.randTop = (secCb.randTop >= SEC_HCI_RAND_MULT - 1) ? 0 : secCb.randTop + 1;
|
||||
break;
|
||||
|
||||
case HCI_LE_ENCRYPT_CMD_CMPL_CBACK_EVT:
|
||||
pBuf = WsfMsgDeq(&secCb.aesEncQueue, &handlerId);
|
||||
|
||||
WSF_ASSERT(pBuf != NULL);
|
||||
|
||||
/* note: pBuf should never be NULL and is checked by assert above. */
|
||||
/* coverity[dereference] */
|
||||
if (pBuf->type == SEC_TYPE_CCM || pBuf->type == SEC_TYPE_CMAC || pBuf->type == SEC_TYPE_AES_REV)
|
||||
{
|
||||
WStrReverse(pEvent->leEncryptCmdCmpl.data, HCI_ENCRYPT_DATA_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT:
|
||||
pBuf = WsfMsgDeq(&secCb.pubKeyQueue, &handlerId);
|
||||
break;
|
||||
|
||||
case HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT:
|
||||
pBuf = WsfMsgDeq(&secCb.dhKeyQueue, &handlerId);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pBuf)
|
||||
{
|
||||
WSF_ASSERT(secCb.hciCbackTbl[pBuf->type]);
|
||||
secCb.hciCbackTbl[pBuf->type](pBuf, pEvent, handlerId);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the security service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecInit(void)
|
||||
{
|
||||
WSF_QUEUE_INIT(&secCb.aesEncQueue);
|
||||
WSF_QUEUE_INIT(&secCb.pubKeyQueue);
|
||||
WSF_QUEUE_INIT(&secCb.dhKeyQueue);
|
||||
|
||||
secCb.token = 0;
|
||||
|
||||
/* Register callback with HCI */
|
||||
HciSecRegister(secHciCback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the random number service. This function should only be called once
|
||||
* upon system initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecRandInit(void)
|
||||
{
|
||||
int8_t i;
|
||||
|
||||
/* get new random numbers */
|
||||
for (i=0; i<SEC_HCI_RAND_MULT; i++)
|
||||
{
|
||||
HciLeRandCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function returns up to HCI_RAND_LEN * SEC_HCI_RAND_MULT bytes of random data to
|
||||
* a buffer provided by the client.
|
||||
*
|
||||
* \param pRand Pointer to returned random data.
|
||||
* \param randLen Length of random data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecRand(uint8_t *pRand, uint8_t randLen)
|
||||
{
|
||||
int8_t count = (randLen + HCI_RAND_LEN - 1) / HCI_RAND_LEN;
|
||||
uint8_t index = secCb.randBtm * HCI_RAND_LEN;
|
||||
|
||||
WSF_ASSERT(randLen <= SEC_RAND_DATA_LEN);
|
||||
|
||||
/* Copy from circular buffer of random data. */
|
||||
while (randLen--)
|
||||
{
|
||||
*pRand++ = secCb.rand[index];
|
||||
index = (index == SEC_RAND_DATA_LEN - 1) ? 0 : index + 1;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
/* Request more random data. */
|
||||
HciLeRandCmd();
|
||||
|
||||
/* Update copy index. */
|
||||
secCb.randBtm = (secCb.randBtm >= SEC_HCI_RAND_MULT - 1) ? 0 : secCb.randBtm + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Queue callback and call LE encrypt given most significant byte ordered key and data.
|
||||
*
|
||||
* \param pKey Pointer to key.
|
||||
* \param pText Pointer to text to encrypt.
|
||||
* \param pBuf Pointer to queue block.
|
||||
* \param handlerId Handler ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecLeEncryptCmd(uint8_t *pKey, uint8_t *pText, void *pBuf, wsfHandlerId_t handlerId)
|
||||
{
|
||||
uint8_t revKey[HCI_KEY_LEN];
|
||||
uint8_t revText[HCI_ENCRYPT_DATA_LEN];
|
||||
|
||||
WStrReverseCpy(revKey, pKey, HCI_KEY_LEN);
|
||||
WStrReverseCpy(revText, pText, HCI_ENCRYPT_DATA_LEN);
|
||||
|
||||
WsfMsgEnq(&secCb.aesEncQueue, handlerId, pBuf);
|
||||
HciLeEncryptCmd(revKey, revText);
|
||||
}
|
||||
Vendored
+162
@@ -0,0 +1,162 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Internal security service structures.
|
||||
*
|
||||
* Copyright (c) 2010-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef SEC_MAIN_H
|
||||
#define SEC_MAIN_H
|
||||
|
||||
#include "hci_api.h"
|
||||
// #include "pal_crypto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
/*! AES, CMAC and HCI algorithm block length */
|
||||
#define SEC_BLOCK_LEN 16
|
||||
|
||||
/* CMAC constant Rb */
|
||||
#define SEC_CMAC_RB 0x87
|
||||
|
||||
/*! Number or random bytes to keep in the secCb_t rand data buffer */
|
||||
#define SEC_RAND_DATA_LEN 32
|
||||
|
||||
/*! Multiple of HCI_RAND_LEN kept in the secCb_t rand data buffer */
|
||||
#define SEC_HCI_RAND_MULT (SEC_RAND_DATA_LEN / HCI_RAND_LEN)
|
||||
|
||||
/*! Compile time ECC configuration */
|
||||
#define SEC_ECC_CFG_DEBUG 0
|
||||
#define SEC_ECC_CFG_UECC 1
|
||||
#define SEC_ECC_CFG_HCI 2
|
||||
|
||||
/*! Compile time CMAC configuration */
|
||||
#define SEC_CMAC_CFG_PLATFORM 0
|
||||
#define SEC_CMAC_CFG_HCI 1
|
||||
|
||||
/*! Compile time CCM configuration */
|
||||
#define SEC_CCM_CFG_PLATFORM 0
|
||||
#define SEC_CCM_CFG_HCI 1
|
||||
|
||||
/*! CCM Operation (Encryption or Decryption) */
|
||||
#define SEC_CCM_OP_ENCRYPT 0
|
||||
#define SEC_CCM_OP_DECRYPT 1
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Enumeration of security operation types */
|
||||
enum
|
||||
{
|
||||
SEC_TYPE_AES,
|
||||
SEC_TYPE_CMAC,
|
||||
SEC_TYPE_DH,
|
||||
SEC_TYPE_CCM,
|
||||
SEC_TYPE_AES_REV,
|
||||
SEC_NUM_TYPES
|
||||
};
|
||||
|
||||
/*! Security queue element for CMAC operations */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *pPlainText;
|
||||
uint8_t key[SEC_CMAC_KEY_LEN];
|
||||
uint8_t subkey[SEC_CMAC_KEY_LEN];
|
||||
uint16_t position;
|
||||
uint16_t len;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint8_t state;
|
||||
} secCmacSecCb_t;
|
||||
|
||||
/*! Security queue element for CCM-Mode operations */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t operation;
|
||||
uint8_t *pText;
|
||||
uint8_t *pClear;
|
||||
uint8_t *pRcvMic;
|
||||
uint16_t textLen;
|
||||
uint16_t clearLen;
|
||||
uint8_t micLen;
|
||||
uint8_t key[SEC_CCM_KEY_LEN];
|
||||
uint8_t scratch[SEC_BLOCK_LEN];
|
||||
uint16_t counter;
|
||||
uint16_t position;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint8_t state;
|
||||
uint8_t *pWorking;
|
||||
} secCcmSecCb_t;
|
||||
|
||||
/*! Security queue element */
|
||||
typedef struct
|
||||
{
|
||||
secMsg_t msg;
|
||||
uint8_t ciphertext[SEC_BLOCK_LEN];
|
||||
uint8_t reserved[SEC_BLOCK_LEN];
|
||||
void *pCb;
|
||||
uint8_t type;
|
||||
} secQueueBuf_t;
|
||||
|
||||
typedef void secHciCback_t(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId);
|
||||
typedef secHciCback_t *pSecHciCback_t;
|
||||
|
||||
/* Control block */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rand[SEC_RAND_DATA_LEN]; /* Random data buffer */
|
||||
wsfQueue_t aesEncQueue; /* Queue for AES encrypt requests */
|
||||
wsfQueue_t pubKeyQueue; /* Queue for read p256 public key requests */
|
||||
wsfQueue_t dhKeyQueue; /* Queue for generate dh key requests */
|
||||
uint8_t token; /* Token value */
|
||||
uint8_t randTop; /* Random buffer insert point (HCI_RAND_LEN bytes) */
|
||||
uint8_t randBtm; /* Random buffer copy point (HCI_RAND_LEN bytes) */
|
||||
pSecHciCback_t hciCbackTbl[SEC_NUM_TYPES];
|
||||
} secCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Queue callback and call LE encrypt given most significant byte ordered key and data.
|
||||
*
|
||||
* \param pKey Pointer to key.
|
||||
* \param pText Pointer to text to encrypt.
|
||||
* \param pBuf Pointer to queue block.
|
||||
* \param handlerId Handler ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecLeEncryptCmd(uint8_t *pKey, uint8_t *pText, void *pBuf, wsfHandlerId_t handlerId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SEC_MAIN_H */
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Counter with CBC-MAC (CCM) mode security - Native AES.
|
||||
*
|
||||
* Copyright (c) 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_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
|
||||
#ifndef SEC_CCM_CFG
|
||||
#define SEC_CCM_CFG SEC_CCM_CFG_PLATFORM
|
||||
#endif
|
||||
|
||||
#if SEC_CCM_CFG == SEC_CCM_CFG_PLATFORM
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Global security control block */
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the CCM-Mode encryption algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pPlainText Pointer to text to encrypt.
|
||||
* \param textLen Length of pPlainText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmEnc(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pPlainText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t micLen, uint8_t *pResult,
|
||||
wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secCcmEncMsg_t *pCcmMsg;
|
||||
|
||||
if ((pCcmMsg = WsfMsgAlloc(sizeof(secCcmEncMsg_t))) != NULL)
|
||||
{
|
||||
/* Encrypt. */
|
||||
PalCryptoCcmEnc(pKey, pNonce, pPlainText, textLen, pClear, clearLen, micLen, pResult,
|
||||
handlerId, param, event);
|
||||
|
||||
memcpy(pResult, pClear, clearLen);
|
||||
|
||||
/* Send notification of encryption complete. */
|
||||
pCcmMsg->hdr.status = secCb.token++;
|
||||
pCcmMsg->hdr.param = param;
|
||||
pCcmMsg->hdr.event = event;
|
||||
pCcmMsg->pCiphertext = pResult;
|
||||
pCcmMsg->textLen = textLen + clearLen + micLen;
|
||||
WsfMsgSend(handlerId, pCcmMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn SecCcmDec
|
||||
*
|
||||
* \brief Execute the CCM-Mode verify and decrypt algorithm.
|
||||
*
|
||||
* \param pKey Pointer to encryption key (SEC_CCM_KEY_LEN bytes).
|
||||
* \param pNonce Pointer to nonce (SEC_CCM_NONCE_LEN bytes).
|
||||
* \param pCypherText Pointer to text to decrypt.
|
||||
* \param textLen Length of pCypherText in bytes.
|
||||
* \param pClear Pointer to additional, unencrypted authentication text.
|
||||
* \param clearLen Length of pClear in bytes.
|
||||
* \param pMic Pointer to authentication digest.
|
||||
* \param micLen Size of MIC in bytes (4, 8 or 16).
|
||||
* \param pResult Buffer to hold result (returned in complete event).
|
||||
* \param handlerId Task handler ID to receive complete event.
|
||||
* \param param Optional parameter passed in complete event.
|
||||
* \param event Event ID of complete event.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecCcmDec(const uint8_t *pKey, uint8_t *pNonce, uint8_t *pCypherText, uint16_t textLen,
|
||||
uint8_t *pClear, uint16_t clearLen, uint8_t *pMic, uint8_t micLen,
|
||||
uint8_t *pResult, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secCcmDecMsg_t *pCcmMsg;
|
||||
|
||||
if ((pCcmMsg = WsfMsgAlloc(sizeof(secCcmDecMsg_t))) != NULL)
|
||||
{
|
||||
/* Decrypt. */
|
||||
uint32_t error;
|
||||
|
||||
error = PalCryptoCcmDec(pKey, pNonce, pCypherText, textLen, pClear, clearLen, pMic, micLen,
|
||||
pResult, handlerId, param, event);
|
||||
|
||||
/* Send notification of decryption complete. */
|
||||
pCcmMsg->hdr.status = secCb.token++;
|
||||
pCcmMsg->hdr.param = param;
|
||||
pCcmMsg->hdr.event = event;
|
||||
|
||||
/* Compare MIC with computed MIC. */
|
||||
if (error)
|
||||
{
|
||||
/* MIC not authentic. */
|
||||
pCcmMsg->success = FALSE;
|
||||
pCcmMsg->pResult = NULL;
|
||||
pCcmMsg->pText = NULL;
|
||||
pCcmMsg->textLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* MIC authentic. */
|
||||
pCcmMsg->success = TRUE;
|
||||
pCcmMsg->pResult = pResult;
|
||||
pCcmMsg->pText = pResult;
|
||||
pCcmMsg->textLen = textLen;
|
||||
}
|
||||
|
||||
WsfMsgSend(handlerId, pCcmMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize CCM-Mode security.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecCcmInit()
|
||||
{
|
||||
PalCryptoInit();
|
||||
|
||||
secCb.hciCbackTbl[SEC_TYPE_CCM] = NULL;
|
||||
}
|
||||
|
||||
#endif /* SEC_CCM_CFG */
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Security ECC implementation using uECC.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "sec_api.h"
|
||||
#include "sec_main.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "hci_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "uECC.h"
|
||||
|
||||
#ifndef SEC_ECC_CFG
|
||||
#define SEC_ECC_CFG SEC_ECC_CFG_UECC
|
||||
#endif
|
||||
|
||||
#if SEC_ECC_CFG == SEC_ECC_CFG_UECC
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
extern secCb_t secCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Random number generator used by uECC.
|
||||
*
|
||||
* \param p_dest Buffer to hold random number
|
||||
* \param p_size Size of p_dest in bytes .
|
||||
*
|
||||
* \return TRUE if successful.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static int secEccRng(uint8_t *p_dest, unsigned p_size)
|
||||
{
|
||||
SecRand(p_dest, p_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Callback for HCI encryption for ECC operations.
|
||||
*
|
||||
* \param pBuf Pointer to sec queue element.
|
||||
* \param pEvent Pointer to HCI event.
|
||||
* \param handlerId WSF handler ID.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccHciCback(secQueueBuf_t *pBuf, hciEvt_t *pEvent, wsfHandlerId_t handlerId)
|
||||
{
|
||||
/* TBD */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenKey(wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
|
||||
|
||||
if (pMsg)
|
||||
{
|
||||
/* Generate the keys */
|
||||
uECC_make_key(pMsg->data.key.pubKey_x, pMsg->data.key.privKey);
|
||||
|
||||
/* Send shared secret to handler */
|
||||
pMsg->hdr.event = event;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an ECC key.
|
||||
*
|
||||
* \param pKey ECC Key structure.
|
||||
* \param handlerId WSF handler ID for client.
|
||||
* \param param Optional parameter sent to client's WSF handler.
|
||||
* \param event Event for client's WSF handler.
|
||||
*
|
||||
* \return TRUE if successful, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SecEccGenSharedSecret(secEccKey_t *pKey, wsfHandlerId_t handlerId, uint16_t param, uint8_t event)
|
||||
{
|
||||
secEccMsg_t *pMsg = WsfMsgAlloc(sizeof(secEccMsg_t));
|
||||
|
||||
if (pMsg)
|
||||
{
|
||||
bool_t keyValid = uECC_valid_public_key(pKey->pubKey_x);
|
||||
|
||||
if (keyValid)
|
||||
{
|
||||
uECC_shared_secret(pKey->pubKey_x, pKey->privKey, pMsg->data.sharedSecret.secret);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(pMsg->data.sharedSecret.secret, 0xFF, SEC_ECC_KEY_LEN);
|
||||
}
|
||||
|
||||
/* Send shared secret to handler. */
|
||||
pMsg->hdr.event = event;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->hdr.status = keyValid ? HCI_SUCCESS : HCI_ERR_INVALID_PARAM;
|
||||
WsfMsgSend(handlerId, pMsg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to initialize ECC security.
|
||||
*
|
||||
* \param None.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SecEccInit()
|
||||
{
|
||||
//srand((unsigned int)time(NULL));
|
||||
uECC_set_rng(secEccRng);
|
||||
}
|
||||
|
||||
#endif /* SEC_ECC_CFG */
|
||||
+552
@@ -0,0 +1,552 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT main 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_buf.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_math.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* indexes into base UUID for 16-to-128 bit UUID conversion */
|
||||
#define ATT_BASE_UUID_POS_0 12
|
||||
#define ATT_BASE_UUID_POS_1 13
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
static uint8_t attBaseUuid[] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default component function inteface */
|
||||
const attFcnIf_t attFcnDefault =
|
||||
{
|
||||
attEmptyDataCback,
|
||||
(l2cCtrlCback_t) attEmptyHandler,
|
||||
(attMsgHandler_t) attEmptyHandler,
|
||||
attEmptyConnCback
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
attCb_t attCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C data callback for ATT.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attL2cDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t pduType;
|
||||
|
||||
/* parse PDU type */
|
||||
pduType = *(pPacket + L2C_PAYLOAD_START);
|
||||
|
||||
/* if from server */
|
||||
if ((pduType & ATT_PDU_MASK_SERVER) != 0)
|
||||
{
|
||||
/* call client data callback */
|
||||
(*attCb.pClient->dataCback)(handle, len, pPacket);
|
||||
}
|
||||
/* else from client */
|
||||
else
|
||||
{
|
||||
/* call server data callback */
|
||||
(*attCb.pServer->dataCback)(handle, len, pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C control callback for ATT.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attL2cCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
attCcb_t *pCcb;
|
||||
|
||||
/* get connection control block */
|
||||
pCcb = attCcbByConnId((dmConnId_t) pMsg->param);
|
||||
|
||||
/* verify connection is open */
|
||||
if (pCcb->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
if (pMsg->event == L2C_CTRL_FLOW_DISABLE_IND)
|
||||
{
|
||||
/* flow disabled */
|
||||
pCcb->control |= ATT_CCB_STATUS_FLOW_DISABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* flow enabled */
|
||||
pCcb->control &= ~ATT_CCB_STATUS_FLOW_DISABLED;
|
||||
|
||||
/* call server control callback */
|
||||
(*attCb.pServer->ctrlCback)(pMsg);
|
||||
|
||||
/* check flow again; could be changed recursively */
|
||||
if (!(pCcb->control & ATT_CCB_STATUS_FLOW_DISABLED))
|
||||
{
|
||||
/* call client control callback */
|
||||
(*attCb.pClient->ctrlCback)(pMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM connection callback for ATT.
|
||||
*
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attDmConnCback(dmEvt_t *pDmEvt)
|
||||
{
|
||||
attCcb_t *pCcb;
|
||||
|
||||
pCcb = attCcbByConnId((dmConnId_t) pDmEvt->hdr.param);
|
||||
|
||||
/* if new connection created */
|
||||
if (pDmEvt->hdr.event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
/* initialize control block before handling event */
|
||||
pCcb->handle = pDmEvt->connOpen.handle;
|
||||
pCcb->mtu = ATT_DEFAULT_MTU;
|
||||
pCcb->connId = (dmConnId_t) pDmEvt->hdr.param;
|
||||
pCcb->control = 0;
|
||||
pCcb->pPendDbHashRsp = NULL;
|
||||
}
|
||||
|
||||
/* if connection has been opened */
|
||||
if (pCcb->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* pass event to server */
|
||||
(*attCb.pServer->connCback)(pCcb, pDmEvt);
|
||||
|
||||
/* pass event to client */
|
||||
(*attCb.pClient->connCback)(pCcb, pDmEvt);
|
||||
|
||||
/* if connection closed */
|
||||
if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* clear control block after handling event */
|
||||
pCcb->connId = DM_CONN_ID_NONE;
|
||||
|
||||
if (pCcb->pPendDbHashRsp)
|
||||
{
|
||||
WsfBufFree(pCcb->pPendDbHashRsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* execute ATT connection callback */
|
||||
if (attCb.connCback != NULL)
|
||||
{
|
||||
(*attCb.connCback)(pDmEvt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATT empty event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attEmptyHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Empty connection callback for ATT.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attEmptyConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Empty data callback for ATT.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attEmptyDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the connection control block for the given handle.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
*
|
||||
* \return Pointer to connection control block or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
attCcb_t *attCcbByHandle(uint16_t handle)
|
||||
{
|
||||
dmConnId_t connId;
|
||||
|
||||
if ((connId = DmConnIdByHandle(handle)) != DM_CONN_ID_NONE)
|
||||
{
|
||||
return &attCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the connection control block for the connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to connection control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
attCcb_t *attCcbByConnId(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
return &attCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Compare a 16 bit UUID to a 128 bit UUID.
|
||||
*
|
||||
* \param pUuid16 Pointer to 16 bit UUID.
|
||||
* \param pUuid128 Pointer to 128 bit UUID.
|
||||
*
|
||||
* \return TRUE of UUIDs match, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t attUuidCmp16to128(const uint8_t *pUuid16, const uint8_t *pUuid128)
|
||||
{
|
||||
attBaseUuid[ATT_BASE_UUID_POS_0] = pUuid16[0];
|
||||
attBaseUuid[ATT_BASE_UUID_POS_1] = pUuid16[1];
|
||||
|
||||
return (memcmp(attBaseUuid, pUuid128, ATT_128_UUID_LEN) == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the attribute protocol MTU of a connection.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param peerMtu Peer MTU.
|
||||
* \param localMtu Local MTU.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attSetMtu(attCcb_t *pCcb, uint16_t peerMtu, uint16_t localMtu)
|
||||
{
|
||||
uint16_t mtu;
|
||||
|
||||
/* set negotiated mtu for the connection to the lesser of ours and theirs */
|
||||
mtu = WSF_MIN(peerMtu, localMtu);
|
||||
|
||||
/* if current mtu is not the same as the negotiated value */
|
||||
if (pCcb->mtu != mtu)
|
||||
{
|
||||
/* set mtu to the new value */
|
||||
pCcb->mtu = mtu;
|
||||
|
||||
/* notify app about the new value */
|
||||
attExecCallback(pCcb->connId, ATT_MTU_UPDATE_IND, 0, ATT_SUCCESS, mtu);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute application callback function.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param event Callback event ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param status Callback event status.
|
||||
* \param mtu Negotiated MTU value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attExecCallback(dmConnId_t connId, uint8_t event, uint16_t handle, uint8_t status, uint16_t mtu)
|
||||
{
|
||||
if (attCb.cback)
|
||||
{
|
||||
attEvt_t evt;
|
||||
|
||||
evt.hdr.param = connId;
|
||||
evt.hdr.event = event;
|
||||
evt.hdr.status = status;
|
||||
evt.valueLen = 0;
|
||||
evt.handle = handle;
|
||||
evt.continuing = 0;
|
||||
evt.mtu = mtu;
|
||||
|
||||
(*attCb.cback)(&evt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate an ATT data message buffer to be used for the ATT attribute protocol messages.
|
||||
*
|
||||
* \param len Message length in bytes.
|
||||
*
|
||||
* \return Pointer to data message buffer or NULL if allocation failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void *attMsgAlloc(uint16_t len)
|
||||
{
|
||||
return WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATT handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID for ATT.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
/* store handler ID */
|
||||
attCb.handlerId = handlerId;
|
||||
|
||||
/* initialize control block */
|
||||
attCb.pClient = &attFcnDefault;
|
||||
attCb.pServer = &attFcnDefault;
|
||||
|
||||
/* Register with L2C */
|
||||
L2cRegister(L2C_CID_ATT, attL2cDataCback, attL2cCtrlCback);
|
||||
|
||||
/* Register with DM */
|
||||
DmConnRegister(DM_CLIENT_ID_ATT, attDmConnCback);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for ATT.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
if (pMsg->event >= ATTS_MSG_START)
|
||||
{
|
||||
/* pass event to server */
|
||||
(*attCb.pServer->msgCback)(pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pass event to client */
|
||||
(*attCb.pClient->msgCback)(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a callback with ATT.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttRegister(attCback_t cback)
|
||||
{
|
||||
attCb.cback = cback;
|
||||
|
||||
/* if configured MTU size is larger than maximum RX PDU length */
|
||||
if (pAttCfg->mtu > (HciGetMaxRxAclLen() - L2C_HDR_LEN))
|
||||
{
|
||||
/* notify app about MTU misconfiguration */
|
||||
attExecCallback(0, DM_ERROR_IND, 0, DM_ERR_ATT_RX_PDU_LEN_EXCEEDED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a connection callback with ATT. The callback is typically used to
|
||||
* manage the attribute server database.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttConnRegister(dmCback_t cback)
|
||||
{
|
||||
attCb.connCback = cback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the attribute protocol MTU of a connection.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return MTU of the connection.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t AttGetMtu(dmConnId_t connId)
|
||||
{
|
||||
return (attCcbByConnId(connId)->mtu);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate an ATT message buffer to be sent with the ATT attribute protocol
|
||||
* zero-copy APIs.
|
||||
*
|
||||
* \param len Message length in bytes.
|
||||
* \param opcode Opcode for ATT message.
|
||||
*
|
||||
* \return Pointer to message buffer or NULL if allocation failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void *AttMsgAlloc(uint16_t len, uint8_t opcode)
|
||||
{
|
||||
uint8_t *pMsg;
|
||||
uint8_t hdrLen;
|
||||
|
||||
WSF_ASSERT((opcode == ATT_PDU_VALUE_IND) || (opcode == ATT_PDU_VALUE_NTF));
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case ATT_PDU_VALUE_IND:
|
||||
case ATT_PDU_VALUE_NTF:
|
||||
hdrLen = ATT_VALUE_IND_NTF_BUF_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
hdrLen = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdrLen > 0)
|
||||
{
|
||||
pMsg = attMsgAlloc(hdrLen + len);
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
/* return pointer to attribute value buffer */
|
||||
return (pMsg + hdrLen);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free an ATT message buffer allocated with AttMsgAlloc().
|
||||
*
|
||||
* \param pMsg Pointer to message buffer.
|
||||
* \param opcode Opcode for ATT message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttMsgFree(void *pMsg, uint8_t opcode)
|
||||
{
|
||||
uint8_t hdrLen;
|
||||
|
||||
WSF_ASSERT((opcode == ATT_PDU_VALUE_IND) || (opcode == ATT_PDU_VALUE_NTF));
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case ATT_PDU_VALUE_IND:
|
||||
case ATT_PDU_VALUE_NTF:
|
||||
hdrLen = ATT_VALUE_IND_NTF_BUF_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
hdrLen = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
WsfMsgFree(((uint8_t *)pMsg) - hdrLen);
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT main 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef ATT_MAIN_H
|
||||
#define ATT_MAIN_H
|
||||
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "l2c_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* ATT protocol methods */
|
||||
#define ATT_METHOD_ERR 0 /* Error response */
|
||||
#define ATT_METHOD_MTU 1 /* Exchange mtu */
|
||||
#define ATT_METHOD_FIND_INFO 2 /* Find information */
|
||||
#define ATT_METHOD_FIND_TYPE 3 /* Find by type value */
|
||||
#define ATT_METHOD_READ_TYPE 4 /* Read by type value */
|
||||
#define ATT_METHOD_READ 5 /* Read */
|
||||
#define ATT_METHOD_READ_BLOB 6 /* Read long */
|
||||
#define ATT_METHOD_READ_MULTIPLE 7 /* Read multiple */
|
||||
#define ATT_METHOD_READ_GROUP_TYPE 8 /* Read group type */
|
||||
#define ATT_METHOD_WRITE 9 /* Write */
|
||||
#define ATT_METHOD_WRITE_CMD 10 /* Write command */
|
||||
#define ATT_METHOD_PREPARE_WRITE 11 /* Prepare write */
|
||||
#define ATT_METHOD_EXECUTE_WRITE 12 /* Execute write */
|
||||
#define ATT_METHOD_VALUE_NTF 13 /* Handle value notification */
|
||||
#define ATT_METHOD_VALUE_IND 14 /* Handle value indication */
|
||||
#define ATT_METHOD_VALUE_CNF 15 /* Handle value confirm */
|
||||
#define ATT_METHOD_SIGNED_WRITE_CMD 16 /* Signed write command */
|
||||
|
||||
/* Convert opcode to method */
|
||||
#define ATT_OPCODE_2_METHOD(op) (((op) & ~ATT_PDU_MASK_SERVER) / 2)
|
||||
|
||||
/* Client and server message macros */
|
||||
#define ATTC_MSG_START 0x00
|
||||
#define ATTS_MSG_START 0x20
|
||||
#define ATT_MSG_MASK(msg) ((msg) & 0x1F)
|
||||
|
||||
/* Buffer lengths for messages */
|
||||
#define ATT_VALUE_IND_NTF_BUF_LEN (ATT_VALUE_NTF_LEN + L2C_PAYLOAD_START)
|
||||
|
||||
/* attCcb_t control bits */
|
||||
#define ATT_CCB_STATUS_MTU_SENT (1<<0) /* MTU req or rsp sent */
|
||||
#define ATT_CCB_STATUS_FLOW_DISABLED (1<<1) /* Data flow disabled */
|
||||
#define ATT_CCB_STATUS_TX_TIMEOUT (1<<2) /* ATT transaction timed out */
|
||||
#define ATT_CCB_STATUS_RSP_PENDING (1<<3) /* ATTS write rsp pending */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t startHandle; /* Start handle of the requested operation. Used if an Error Response is sent. */
|
||||
uint16_t handle; /* Attribute handle of pending response. */
|
||||
} attPendDbHashRsp_t;
|
||||
|
||||
/* Connection control block */
|
||||
typedef struct
|
||||
{
|
||||
wsfQueue_t prepWriteQueue; /* prepare write queue */
|
||||
wsfTimer_t idleTimer; /* service discovery idle timer */
|
||||
uint16_t handle; /* connection handle */
|
||||
uint16_t mtu; /* connection mtu */
|
||||
dmConnId_t connId; /* DM connection ID */
|
||||
uint8_t control; /* Control bitfield */
|
||||
attPendDbHashRsp_t *pPendDbHashRsp; /* Pending ATT Response information. */
|
||||
} attCcb_t;
|
||||
|
||||
/* ATT message handling function type */
|
||||
typedef void (*attMsgHandler_t)(void *pMsg);
|
||||
|
||||
/* ATT connection callback type */
|
||||
typedef void (*attConnCback_t)(attCcb_t *pCcb, dmEvt_t *pDmEvt);
|
||||
|
||||
/* Callback interface for client and server */
|
||||
typedef struct
|
||||
{
|
||||
l2cDataCback_t dataCback; /* Data callback */
|
||||
l2cCtrlCback_t ctrlCback; /* Control callback */
|
||||
attMsgHandler_t msgCback; /* Message handling callback */
|
||||
attConnCback_t connCback; /* Connection callback */
|
||||
} attFcnIf_t;
|
||||
|
||||
/* Main control block of the ATT subsystem */
|
||||
typedef struct
|
||||
{
|
||||
attCcb_t ccb[DM_CONN_MAX]; /* Connection control blocks */
|
||||
attFcnIf_t const *pClient; /* Client callback interface */
|
||||
attFcnIf_t const *pServer; /* Server callback interface */
|
||||
attCback_t cback; /* ATT callback function */
|
||||
dmCback_t connCback; /* ATT connection callback function */
|
||||
wsfHandlerId_t handlerId; /* WSF handler ID */
|
||||
uint8_t errTest; /* Status code for error testing */
|
||||
} attCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Default component function inteface */
|
||||
extern const attFcnIf_t attFcnDefault;
|
||||
|
||||
/* Control block */
|
||||
extern attCb_t attCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void attEmptyHandler(wsfMsgHdr_t *pMsg);
|
||||
void attEmptyDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket);
|
||||
void attEmptyConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt);
|
||||
|
||||
attCcb_t *attCcbByHandle(uint16_t handle);
|
||||
attCcb_t *attCcbByConnId(dmConnId_t connId);
|
||||
|
||||
bool_t attUuidCmp16to128(const uint8_t *pUuid16, const uint8_t *pUuid128);
|
||||
void attSetMtu(attCcb_t *pCcb, uint16_t peerMtu, uint16_t localMtu);
|
||||
void attExecCallback(dmConnId_t connId, uint8_t event, uint16_t handle, uint8_t status, uint16_t mtu);
|
||||
void *attMsgAlloc(uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATT_MAIN_H */
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT optional signed PDU processing functions.
|
||||
*
|
||||
* 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 ATT_SIGN_H
|
||||
#define ATT_SIGN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* CMAC algorithm subkey length */
|
||||
#define ATT_CMAC_SUBKEY_LEN 16
|
||||
|
||||
/* CMAC algorithm block length */
|
||||
#define ATT_CMAC_BLOCK_LEN 16
|
||||
|
||||
/* CMAC constant Rb */
|
||||
#define ATT_CMAC_RB 0x87
|
||||
|
||||
/* CMAC signature result length */
|
||||
#define ATT_CMAC_RESULT_LEN 8
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATT_SIGN_H */
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT UUID constants.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_uuid.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Service UUIDs */
|
||||
const uint8_t attGapSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GAP_SERVICE)};
|
||||
const uint8_t attGattSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GATT_SERVICE)};
|
||||
const uint8_t attIasSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_IMMEDIATE_ALERT_SERVICE)};
|
||||
const uint8_t attLlsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_LINK_LOSS_SERVICE)};
|
||||
const uint8_t attTpsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TX_POWER_SERVICE)};
|
||||
const uint8_t attCtsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CURRENT_TIME_SERVICE)};
|
||||
const uint8_t attRtusSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_REF_TIME_UPDATE_SERVICE)};
|
||||
const uint8_t attNdcsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DST_CHANGE_SERVICE)};
|
||||
const uint8_t attGlsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GLUCOSE_SERVICE)};
|
||||
const uint8_t attHtsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HEALTH_THERM_SERVICE)};
|
||||
const uint8_t attDisSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DEVICE_INFO_SERVICE)};
|
||||
const uint8_t attNwaSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_NETWORK_AVAIL_SERVICE)};
|
||||
const uint8_t attWdsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_WATCHDOG_SERVICE)};
|
||||
const uint8_t attHrsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HEART_RATE_SERVICE)};
|
||||
const uint8_t attPassSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PHONE_ALERT_SERVICE)};
|
||||
const uint8_t attBasSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BATTERY_SERVICE)};
|
||||
const uint8_t attBpsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BLOOD_PRESSURE_SERVICE)};
|
||||
const uint8_t attAnsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_NOTIF_SERVICE)};
|
||||
const uint8_t attHidSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_SERVICE)};
|
||||
const uint8_t attSpsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SCAN_PARAM_SERVICE)};
|
||||
const uint8_t attPlxsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PULSE_OXIMITER_SERVICE)};
|
||||
const uint8_t attUdsSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_USER_DATA_SERVICE)};
|
||||
const uint8_t attMprvSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PRV_SERVICE)};
|
||||
const uint8_t attMprxSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PROXY_SERVICE)};
|
||||
|
||||
/*! GATT UUIDs */
|
||||
const uint8_t attPrimSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PRIMARY_SERVICE)};
|
||||
const uint8_t attSecSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SECONDARY_SERVICE)};
|
||||
const uint8_t attIncUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_INCLUDE)};
|
||||
const uint8_t attChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CHARACTERISTIC)};
|
||||
|
||||
/*! Descriptor UUIDs */
|
||||
const uint8_t attChExtUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CHARACTERISTIC_EXT)};
|
||||
const uint8_t attChUserDescUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CHAR_USER_DESC)};
|
||||
const uint8_t attCliChCfgUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CLIENT_CHAR_CONFIG)};
|
||||
const uint8_t attSrvChCfgUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SERVER_CHAR_CONFIG)};
|
||||
const uint8_t attChPresFmtUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CHAR_PRES_FORMAT)};
|
||||
const uint8_t attAggFmtUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_AGGREGATE_FORMAT)};
|
||||
const uint8_t attValRangeUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_VALID_RANGE)};
|
||||
const uint8_t attHidErmUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_EXT_REPORT_MAPPING)};
|
||||
const uint8_t attHidRimUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_REPORT_ID_MAPPING)};
|
||||
|
||||
/*! Characteristic UUIDs */
|
||||
const uint8_t attDnChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DEVICE_NAME)};
|
||||
const uint8_t attApChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_APPEARANCE)};
|
||||
const uint8_t attPpfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PERIPH_PRIVACY_FLAG)};
|
||||
const uint8_t attRaChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RECONN_ADDR)};
|
||||
const uint8_t attPpcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PREF_CONN_PARAM)};
|
||||
const uint8_t attScChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SERVICE_CHANGED)};
|
||||
const uint8_t attAlChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_LEVEL)};
|
||||
const uint8_t attTxpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TX_POWER_LEVEL)};
|
||||
const uint8_t attDtChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DATE_TIME)};
|
||||
const uint8_t attDwChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DAY_OF_WEEK)};
|
||||
const uint8_t attDdtChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DAY_DATE_TIME)};
|
||||
const uint8_t attEt100ChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_EXACT_TIME_100)};
|
||||
const uint8_t attEt256ChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_EXACT_TIME_256)};
|
||||
const uint8_t attDstoChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DST_OFFSET)};
|
||||
const uint8_t attTzChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_ZONE)};
|
||||
const uint8_t attLtiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_LOCAL_TIME_INFO)};
|
||||
const uint8_t attStzChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SECONDARY_TIME_ZONE)};
|
||||
const uint8_t attTdstChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_WITH_DST)};
|
||||
const uint8_t attTaChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_ACCURACY)};
|
||||
const uint8_t attTsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_SOURCE)};
|
||||
const uint8_t attRtiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_REFERENCE_TIME_INFO)};
|
||||
const uint8_t attTbChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_BROADCAST)};
|
||||
const uint8_t attTucpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_UPDATE_CP)};
|
||||
const uint8_t attTusChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TIME_UPDATE_STATE)};
|
||||
const uint8_t attGlmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GLUCOSE_MEAS)};
|
||||
const uint8_t attBlChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BATTERY_LEVEL)};
|
||||
const uint8_t attBpsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BATTERY_POWER_STATE)};
|
||||
const uint8_t attBlsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BATTERY_LEVEL_STATE)};
|
||||
const uint8_t attTmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TEMP_MEAS)};
|
||||
const uint8_t attTtChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TEMP_TYPE)};
|
||||
const uint8_t attItChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_INTERMEDIATE_TEMP)};
|
||||
const uint8_t attTcelChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TEMP_C)};
|
||||
const uint8_t attTfahChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_TEMP_F)};
|
||||
const uint8_t attSidChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SYSTEM_ID)};
|
||||
const uint8_t attMnsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MODEL_NUMBER)};
|
||||
const uint8_t attSnsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SERIAL_NUMBER)};
|
||||
const uint8_t attFrsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_FIRMWARE_REV)};
|
||||
const uint8_t attHrsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HARDWARE_REV)};
|
||||
const uint8_t attSrsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SOFTWARE_REV)};
|
||||
const uint8_t attMfnsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MANUFACTURER_NAME)};
|
||||
const uint8_t attIeeeChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_11073_CERT_DATA)};
|
||||
const uint8_t attCtChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CURRENT_TIME)};
|
||||
const uint8_t attElChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ELEVATION)};
|
||||
const uint8_t attLatChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_LATITUDE)};
|
||||
const uint8_t attLongChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_LONGITUDE)};
|
||||
const uint8_t attP2dChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_POSITION_2D)};
|
||||
const uint8_t attP3dChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_POSITION_3D)};
|
||||
const uint8_t attVidChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_VENDOR_ID)};
|
||||
const uint8_t attHbmiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_BOOT_MOUSE_IN)};
|
||||
const uint8_t attGlmcChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GLUCOSE_MEAS_CONTEXT)};
|
||||
const uint8_t attBpmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BP_MEAS)};
|
||||
const uint8_t attIcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_INTERMEDIATE_BP)};
|
||||
const uint8_t attHrmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HR_MEAS)};
|
||||
const uint8_t attBslChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HR_SENSOR_LOC)};
|
||||
const uint8_t attHrcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HR_CP)};
|
||||
const uint8_t attRemChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_REMOVABLE)};
|
||||
const uint8_t attSrChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SERVICE_REQ)};
|
||||
const uint8_t attStcChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SCI_TEMP_C)};
|
||||
const uint8_t attStrChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_STRING)};
|
||||
const uint8_t attNwaChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_NETWORK_AVAIL)};
|
||||
const uint8_t attAsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_STATUS)};
|
||||
const uint8_t attRcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RINGER_CP)};
|
||||
const uint8_t attRsChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RINGER_SETTING)};
|
||||
const uint8_t attAcbmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_CAT_ID_MASK)};
|
||||
const uint8_t attAcChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_CAT_ID)};
|
||||
const uint8_t attAncpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_ALERT_NOTIF_CP)};
|
||||
const uint8_t attUasChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_UNREAD_ALERT_STATUS)};
|
||||
const uint8_t attNaChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_NEW_ALERT)};
|
||||
const uint8_t attSnacChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SUP_NEW_ALERT_CAT)};
|
||||
const uint8_t attSuacChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SUP_UNREAD_ALERT_CAT)};
|
||||
const uint8_t attBpfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_BP_FEATURE)};
|
||||
const uint8_t attHidBmiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MEAS_INTERVAL)};
|
||||
const uint8_t attHidBkiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_BOOT_KEYBOARD_IN)};
|
||||
const uint8_t attHidBkoChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_BOOT_KEYBOARD_OUT)};
|
||||
const uint8_t attHidiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_INFORMATION)};
|
||||
const uint8_t attHidRmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_REPORT_MAP)};
|
||||
const uint8_t attHidcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_CONTROL_POINT)};
|
||||
const uint8_t attHidRepChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_REPORT)};
|
||||
const uint8_t attHidPmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_HID_PROTOCOL_MODE)};
|
||||
const uint8_t attSiwChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SCAN_INT_WIND)};
|
||||
const uint8_t attPnpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PNP_ID)};
|
||||
const uint8_t attGlfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_GLUCOSE_FEATURE)};
|
||||
const uint8_t attRacpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RACP)};
|
||||
const uint8_t attCarChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CAR)};
|
||||
const uint8_t attRsfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RUNNING_SPEED_FEATURE)};
|
||||
const uint8_t attRsmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RUNNING_SPEED_MEASUREMENT)};
|
||||
const uint8_t attCpfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CYCLING_POWER_FEATURE)};
|
||||
const uint8_t attCpmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CYCLING_POWER_MEASUREMENT)};
|
||||
const uint8_t attCsfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CYCLING_SPEED_FEATURE)};
|
||||
const uint8_t attCsmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CYCLING_SPEED_MEASUREMENT)};
|
||||
const uint8_t attSlChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SENSOR_LOCATION)};
|
||||
const uint8_t attPlxfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PULSE_OX_FEATURES)};
|
||||
const uint8_t attPlxscmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PULSE_OX_SPOT_CHECK)};
|
||||
const uint8_t attPlxcmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PULSE_OX_CONTINUOUS)};
|
||||
const uint8_t attRpaoChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_RPAO)};
|
||||
const uint8_t attDbciChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DB_CHANGE_INCREMENT)};
|
||||
const uint8_t attUiChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_USER_INDEX)};
|
||||
const uint8_t attUcpChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_USER_CONTROL_POINT)};
|
||||
const uint8_t attMprvDinChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PRV_DATA_IN)};
|
||||
const uint8_t attMprvDoutChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PRV_DATA_OUT)};
|
||||
const uint8_t attMprxDinChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PROXY_DATA_IN)};
|
||||
const uint8_t attMprxDoutChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_MESH_PROXY_DATA_OUT)};
|
||||
const uint8_t attWssSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_WEIGHT_SCALE_SERVICE)};
|
||||
const uint8_t attWmChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_WEIGHT_MEAS)};
|
||||
const uint8_t attWsfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_WEIGHT_SCALE_FEATURE)};
|
||||
const uint8_t attGattCsfChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CLIENT_SUPPORTED_FEATURES)};
|
||||
const uint8_t attGattDbhChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_DATABASE_HASH)};
|
||||
const uint8_t attCteSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CONSTANT_TONE_SERVICE)};
|
||||
const uint8_t attCteEnChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CTE_ENABLE)};
|
||||
const uint8_t attCteMinLenChUuid[ATT_16_UUID_LEN] ={UINT16_TO_BYTES(ATT_UUID_CTE_MIN_LEN)};
|
||||
const uint8_t attCteTxCntChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CTE_TX_CNT)};
|
||||
const uint8_t attCteTxDurChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CTE_TX_DURATION)};
|
||||
const uint8_t attCteIntChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CTE_INTERVAL)};
|
||||
const uint8_t attCtePhyChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CTE_PHY)};
|
||||
Vendored
+706
@@ -0,0 +1,706 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client service and characteristic utility functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_uuid.h"
|
||||
#include "att_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#define ATT_DISC_HDL_IDX_NONE 0xFF
|
||||
|
||||
#define ATT_SET_UUID_MASK ATTC_SET_UUID_128
|
||||
|
||||
/* Characteristic declaration lengths */
|
||||
#define ATT_CHAR_DECL_LEN_UUID16 5
|
||||
#define ATT_CHAR_DECL_LEN_UUID128 19
|
||||
|
||||
/* Read by type response lengths for characteristic discovery */
|
||||
#define ATT_READ_RSP_LEN_UUID16 (ATT_CHAR_DECL_LEN_UUID16 + 2)
|
||||
#define ATT_READ_RSP_LEN_UUID128 (ATT_CHAR_DECL_LEN_UUID128 + 2)
|
||||
|
||||
/* Find info response lengths */
|
||||
#define ATT_FIND_RSP_LEN_UUID16 (ATT_16_UUID_LEN + 2)
|
||||
#define ATT_FIND_RSP_LEN_UUID128 (ATT_128_UUID_LEN + 2)
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Compare two UUIDs.
|
||||
*
|
||||
* \param pChar Characteristic that we are looking for.
|
||||
* \param pUuid Pointer to peer UUID data.
|
||||
* \param settings Indicates 16 or 128 bit UUID.
|
||||
*
|
||||
* \return TRUE if UUIDs match.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t attcUuidCmp(attcDiscChar_t *pChar, uint8_t *pUuid, uint8_t settings)
|
||||
{
|
||||
/* if both uuids are the same length */
|
||||
if ((pChar->settings & ATT_SET_UUID_MASK) == settings)
|
||||
{
|
||||
/* simply compare the data */
|
||||
return (memcmp(pChar->pUuid, pUuid, (settings == 0) ? ATT_16_UUID_LEN : ATT_128_UUID_LEN) == 0);
|
||||
}
|
||||
/* if discovered UUID is 128 bit and our UUID is 16 bit */
|
||||
else if ((settings == ATTC_SET_UUID_128) && ((pChar->settings & ATTC_SET_UUID_128) == 0))
|
||||
{
|
||||
/* convert our UUID to 128 bit and compare */
|
||||
return attUuidCmp16to128(pChar->pUuid, pUuid);
|
||||
}
|
||||
/* else discovered UUID is 16 bit and our UUID is 128 bit */
|
||||
else
|
||||
{
|
||||
/* no match */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify that required characterstics and descriptors have been discovered.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
*
|
||||
* \return ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attcDiscVerify(attcDiscCb_t *pCb)
|
||||
{
|
||||
attcDiscChar_t **pChar;
|
||||
uint8_t i;
|
||||
|
||||
/* for each characteristic */
|
||||
for (i = 0, pChar = pCb->pCharList; i < pCb->charListLen; i++, pChar++)
|
||||
{
|
||||
/* if characteristic required */
|
||||
if (((*pChar)->settings & ATTC_SET_REQUIRED) != 0)
|
||||
{
|
||||
/* verify handle was discovered */
|
||||
if (pCb->pHdlList[i] == ATT_HANDLE_NONE)
|
||||
{
|
||||
return ATT_ERR_REQ_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find next characteristic that requires descriptor discovery. If none found,
|
||||
* discovery is complete; verify that required characterstics have been discovered.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attcDiscDescriptors(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
attcDiscChar_t **pChar;
|
||||
uint16_t startHdl = ATT_HANDLE_NONE;
|
||||
uint16_t endHdl = ATT_HANDLE_NONE;
|
||||
|
||||
/* find next descriptor in list */
|
||||
pChar = pCb->pCharList + pCb->charListIdx;
|
||||
while (pCb->charListIdx < pCb->charListLen)
|
||||
{
|
||||
/* if this is a descriptor */
|
||||
if (((*pChar)->settings & ATTC_SET_DESCRIPTOR) != 0)
|
||||
{
|
||||
/* start handle is one greater than characteristic value handle,
|
||||
* which is stored in the previous entry in the list;
|
||||
* end handle is stored at current entry in the list
|
||||
*/
|
||||
startHdl = pCb->pHdlList[pCb->charListIdx - 1] + 1;
|
||||
endHdl = pCb->pHdlList[pCb->charListIdx];
|
||||
|
||||
/* clear temp end handle */
|
||||
pCb->pHdlList[pCb->charListIdx] = ATT_HANDLE_NONE;
|
||||
|
||||
/* if there are descriptors */
|
||||
if (startHdl <= endHdl)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we are looking for descriptors for this characteristic but
|
||||
* there aren't any;
|
||||
* skip over any other descriptors that follow in our list
|
||||
*/
|
||||
while (++pCb->charListIdx < pCb->charListLen)
|
||||
{
|
||||
pChar++;
|
||||
if ((*pChar)->settings & ATTC_SET_DESCRIPTOR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* go to next in list */
|
||||
pChar++;
|
||||
pCb->charListIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no more descriptors to be discovered */
|
||||
if (pCb->charListIdx == pCb->charListLen)
|
||||
{
|
||||
/* we're done; verify required characteristics and descriptors were discovered */
|
||||
return attcDiscVerify(pCb);
|
||||
}
|
||||
/* else initiate characteristic descriptor discovery */
|
||||
else
|
||||
{
|
||||
AttcFindInfoReq(connId, startHdl, endHdl, TRUE);
|
||||
return ATT_CONTINUING;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a descriptor handle/UUID pair.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param settings Indicates 16 or 128 bit UUID.
|
||||
* \param pPair Pointer to handle/UUID pair.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcDiscProcDescPair(attcDiscCb_t *pCb, uint8_t settings, uint8_t *pPair)
|
||||
{
|
||||
attcDiscChar_t **pDesc;
|
||||
uint16_t hdl;
|
||||
uint8_t i;
|
||||
|
||||
/* parse handle */
|
||||
BSTREAM_TO_UINT16(hdl, pPair);
|
||||
|
||||
/* now pPair points to UUID; find descriptor with matching UUID */
|
||||
pDesc = &pCb->pCharList[pCb->charListIdx];
|
||||
for (i = pCb->charListIdx;
|
||||
(i < pCb->charListLen) && (((*pDesc)->settings & ATTC_SET_DESCRIPTOR) != 0);
|
||||
i++, pDesc++)
|
||||
{
|
||||
/* if characteristic not already found */
|
||||
if (pCb->pHdlList[i] == 0)
|
||||
{
|
||||
/* if UUIDs match */
|
||||
if (attcUuidCmp(*pDesc, pPair, settings))
|
||||
{
|
||||
/* match found; store handle */
|
||||
pCb->pHdlList[i] = hdl;
|
||||
|
||||
ATT_TRACE_INFO1("descriptor found handle:0x%x", hdl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a ATTC_FIND_INFO_RSP received while performing characteristic discovery.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param pMsg ATT callback event message.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attcDiscProcDesc(attcDiscCb_t *pCb, attEvt_t *pMsg)
|
||||
{
|
||||
attcDiscChar_t **pChar;
|
||||
uint8_t *p;
|
||||
uint8_t *pEnd;
|
||||
uint8_t format;
|
||||
uint8_t pairLen;
|
||||
uint8_t settings;
|
||||
|
||||
/* if find info successful */
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
p = pMsg->pValue;
|
||||
pEnd = pMsg->pValue + pMsg->valueLen;
|
||||
|
||||
/* determine UUID format */
|
||||
BSTREAM_TO_UINT8(format, p);
|
||||
if (format == ATT_FIND_HANDLE_16_UUID)
|
||||
{
|
||||
settings = 0;
|
||||
pairLen = ATT_FIND_RSP_LEN_UUID16;
|
||||
}
|
||||
else if (format == ATT_FIND_HANDLE_128_UUID)
|
||||
{
|
||||
settings = ATTC_SET_UUID_128;
|
||||
pairLen = ATT_FIND_RSP_LEN_UUID128;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATT_ERR_INVALID_RSP;
|
||||
}
|
||||
|
||||
/* for each handle/UUID pair */
|
||||
while (p < pEnd)
|
||||
{
|
||||
/* process descriptor handle/UUID pair */
|
||||
attcDiscProcDescPair(pCb, settings, p);
|
||||
|
||||
/* go to next */
|
||||
p += pairLen;
|
||||
}
|
||||
}
|
||||
|
||||
/* if descriptor discovery complete for this characteristic */
|
||||
if (pMsg->hdr.status != ATT_SUCCESS || pMsg->continuing == FALSE)
|
||||
{
|
||||
/* go to next entry in list */
|
||||
pChar = &pCb->pCharList[pCb->charListIdx];
|
||||
do
|
||||
{
|
||||
/* check if at end of list */
|
||||
pCb->charListIdx++;
|
||||
if (pCb->charListIdx == pCb->charListLen)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip over descriptors that follow current characteristic */
|
||||
pChar++;
|
||||
} while ((*pChar)->settings & ATTC_SET_DESCRIPTOR);
|
||||
|
||||
/* proceed with descriptor discovery for the next characteristic */
|
||||
return attcDiscDescriptors((dmConnId_t) pMsg->hdr.param, pCb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* still more to do */
|
||||
return ATT_CONTINUING;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a characteristic declaration.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param settings Indicates 16 or 128 bit UUID.
|
||||
* \param pDecl Pointer to declaration.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcDiscProcCharDecl(attcDiscCb_t *pCb, uint8_t settings, uint8_t *pDecl)
|
||||
{
|
||||
attcDiscChar_t **pChar;
|
||||
uint16_t hdl;
|
||||
uint16_t declHdl;
|
||||
uint8_t i;
|
||||
|
||||
/* parse it */
|
||||
BSTREAM_TO_UINT16(declHdl, pDecl);
|
||||
pDecl++; /* skip properties field */
|
||||
BSTREAM_TO_UINT16(hdl, pDecl);
|
||||
|
||||
/* if looking for end handle of previous characteristic */
|
||||
if (pCb->endHdlIdx != ATT_DISC_HDL_IDX_NONE)
|
||||
{
|
||||
/* end handle of previous characteristic is one less than
|
||||
* the handle of the current characteristic declaration
|
||||
*/
|
||||
pCb->pHdlList[pCb->endHdlIdx] = declHdl - 1;
|
||||
pCb->endHdlIdx = ATT_DISC_HDL_IDX_NONE;
|
||||
}
|
||||
|
||||
/* check handle */
|
||||
if (hdl > declHdl && hdl <= pCb->svcEndHdl)
|
||||
{
|
||||
/* now pDecl points to UUID; search for UUID in characteristic list */
|
||||
for (i = 0, pChar = pCb->pCharList; i < pCb->charListLen; i++, pChar++)
|
||||
{
|
||||
/* if characteristic not already found */
|
||||
if (pCb->pHdlList[i] == 0)
|
||||
{
|
||||
/* if UUIDs match */
|
||||
if (attcUuidCmp(*pChar, pDecl, settings))
|
||||
{
|
||||
/* match found; store handle */
|
||||
pCb->pHdlList[i] = hdl;
|
||||
|
||||
/* if not at end of list and next in list is a descriptor */
|
||||
if (i < (pCb->charListLen - 1) &&
|
||||
((*(pChar + 1))->settings & ATTC_SET_DESCRIPTOR) == ATTC_SET_DESCRIPTOR)
|
||||
{
|
||||
/* characteristic has descriptors, we need to find end handle
|
||||
* store end handle temporarily in handle list location
|
||||
* for the first descriptor
|
||||
*/
|
||||
pCb->endHdlIdx = i + 1;
|
||||
}
|
||||
|
||||
ATT_TRACE_INFO1("characteristic found handle:0x%x", hdl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid handle; skip this declaration */
|
||||
ATT_TRACE_WARN1("invalid handle:0x%x", hdl);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a ATTC_READ_BY_TYPE_RSP received while performing characteristic discovery.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param pMsg ATT callback event message.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attcDiscProcChar(attcDiscCb_t *pCb, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t *pEnd;
|
||||
uint8_t pairLen;
|
||||
uint8_t settings;
|
||||
|
||||
/* if read by type successful */
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
p = pMsg->pValue;
|
||||
pEnd = pMsg->pValue + pMsg->valueLen;
|
||||
|
||||
/* verify attribute-handle pair length and determine UUID length */
|
||||
BSTREAM_TO_UINT8(pairLen, p);
|
||||
if (pairLen == ATT_READ_RSP_LEN_UUID16)
|
||||
{
|
||||
settings = 0;
|
||||
}
|
||||
else if (pairLen == ATT_READ_RSP_LEN_UUID128)
|
||||
{
|
||||
settings = ATTC_SET_UUID_128;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATT_ERR_INVALID_RSP;
|
||||
}
|
||||
|
||||
/* Note that ATT already verifies response length and handle values */
|
||||
|
||||
/* for each characteristic declaration */
|
||||
while (p < pEnd)
|
||||
{
|
||||
/* process characteristic declaration */
|
||||
attcDiscProcCharDecl(pCb, settings, p);
|
||||
|
||||
/* go to next */
|
||||
p += pairLen;
|
||||
}
|
||||
}
|
||||
|
||||
/* if characteristic discovery complete */
|
||||
if (pMsg->hdr.status != ATT_SUCCESS || pMsg->continuing == FALSE)
|
||||
{
|
||||
/* check if characteristic end handle needs to be set */
|
||||
if (pCb->endHdlIdx != ATT_DISC_HDL_IDX_NONE)
|
||||
{
|
||||
/* end handle of characteristic declaration is end handle of service */
|
||||
pCb->pHdlList[pCb->endHdlIdx] = pCb->svcEndHdl;
|
||||
}
|
||||
|
||||
/* proceed with descriptor discovery */
|
||||
pCb->charListIdx = 0;
|
||||
return attcDiscDescriptors((dmConnId_t) pMsg->hdr.param, pCb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* still more to do */
|
||||
return ATT_CONTINUING;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiates the next characteristic configuration procedure.
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param pMsg ATT callback event message.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and configuration procedure is continuing.
|
||||
* ATT_SUCCESS if configuration procedure completed successfully.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attcDiscConfigNext(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
attcDiscCfg_t *pCfg;
|
||||
|
||||
pCfg = pCb->pCfgList + pCb->charListIdx;
|
||||
|
||||
/* iterate over list */
|
||||
while (pCb->charListIdx < pCb->cfgListLen)
|
||||
{
|
||||
/* if handle was discovered */
|
||||
if (pCb->pHdlList[pCfg->hdlIdx] != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* if value present do write req */
|
||||
if (pCfg->valueLen != 0)
|
||||
{
|
||||
AttcWriteReq(connId, pCb->pHdlList[pCfg->hdlIdx], pCfg->valueLen, (uint8_t *) pCfg->pValue);
|
||||
}
|
||||
/* else do read */
|
||||
else
|
||||
{
|
||||
AttcReadReq(connId, pCb->pHdlList[pCfg->hdlIdx]);
|
||||
}
|
||||
|
||||
/* done for now */
|
||||
return ATT_CONTINUING;
|
||||
}
|
||||
|
||||
/* next in list */
|
||||
pCb->charListIdx++;
|
||||
pCfg++;
|
||||
}
|
||||
|
||||
/* nothing left to configure; we're done */
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function discovers the given service on a peer device. Function
|
||||
* AttcFindByTypeValueReq() is called to initiate the discovery procedure.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param uuidLen Length of UUID (2 or 16).
|
||||
* \param pUuid Pointer to UUID data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcDiscService(dmConnId_t connId, attcDiscCb_t *pCb, uint8_t uuidLen, uint8_t *pUuid)
|
||||
{
|
||||
AttcFindByTypeValueReq(connId, ATT_HANDLE_START, ATT_HANDLE_MAX, ATT_UUID_PRIMARY_SERVICE,
|
||||
uuidLen, pUuid, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function processes a service discovery result. It should be called
|
||||
* when an ATTC_FIND_BY_TYPE_VALUE_RSP callback event is received after service
|
||||
* discovery is initiated by calling AttcDiscService().
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param pMsg ATT callback event message.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttcDiscServiceCmpl(attcDiscCb_t *pCb, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* verify callback event */
|
||||
if (pMsg->hdr.event != ATTC_FIND_BY_TYPE_VALUE_RSP)
|
||||
{
|
||||
ATT_TRACE_WARN1("unexpected callback event %d", pMsg->hdr.event);
|
||||
return ATT_ERR_UNDEFINED;
|
||||
}
|
||||
/* verify status */
|
||||
else if (pMsg->hdr.status != ATT_SUCCESS)
|
||||
{
|
||||
return pMsg->hdr.status;
|
||||
}
|
||||
/* verify result was found */
|
||||
else if (pMsg->valueLen == 0)
|
||||
{
|
||||
return ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* get handles of first returned service only; ATT has already performed error checking */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT16(pCb->svcStartHdl, p);
|
||||
BSTREAM_TO_UINT16(pCb->svcEndHdl, p);
|
||||
|
||||
ATT_TRACE_INFO2("found service startHdl=0x%x endHdl=0x%x", pCb->svcStartHdl, pCb->svcEndHdl);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function starts characteristic and characteristic descriptor
|
||||
* discovery for a service on a peer device. The service must have been previously
|
||||
* discovered by calling AttcDiscService() and AttcDiscServiceCmpl().
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcDiscCharStart(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
/* initialize control block */
|
||||
pCb->charListIdx = 0;
|
||||
pCb->endHdlIdx = ATT_DISC_HDL_IDX_NONE;
|
||||
|
||||
AttcReadByTypeReq(connId, pCb->svcStartHdl, pCb->svcEndHdl, ATT_16_UUID_LEN,
|
||||
(uint8_t *) attChUuid, TRUE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function processes a characteristic discovery result. It should be
|
||||
* called when an ATTC_READ_BY_TYPE_RSP or ATTC_FIND_INFO_RSP callback event is
|
||||
* received after characteristic discovery is initiated by calling AttcDiscCharStart().
|
||||
*
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
* \param pMsg ATT callback event message.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and discovery procedure is continuing.
|
||||
* ATT_SUCCESS if discovery procedure completed successfully.
|
||||
* Otherwise the discovery procedure failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttcDiscCharCmpl(attcDiscCb_t *pCb, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* verify callback event */
|
||||
if (pMsg->hdr.event != ATTC_READ_BY_TYPE_RSP &&
|
||||
pMsg->hdr.event != ATTC_FIND_INFO_RSP)
|
||||
{
|
||||
ATT_TRACE_WARN1("unexpected callback event %d", pMsg->hdr.event);
|
||||
return ATT_ERR_UNDEFINED;
|
||||
}
|
||||
|
||||
/* if read by type (characteristic discovery) */
|
||||
if (pMsg->hdr.event == ATTC_READ_BY_TYPE_RSP)
|
||||
{
|
||||
status = attcDiscProcChar(pCb, pMsg);
|
||||
}
|
||||
/* else if find info (descriptor discovery) */
|
||||
else
|
||||
{
|
||||
status = attcDiscProcDesc(pCb, pMsg);
|
||||
}
|
||||
|
||||
/* if characteristic discovery failed clear any handles */
|
||||
if (status != ATT_SUCCESS && status != ATT_CONTINUING)
|
||||
{
|
||||
memset(pCb->pHdlList, 0, (pCb->charListLen * sizeof(uint16_t)));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function starts characteristic configuration for characteristics on a
|
||||
* peer device. The characteristics must have been previously discovered by calling
|
||||
* AttcDiscCharStart() and AttcDisccharCont().
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to service discovery control block.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and configuration procedure is continuing.
|
||||
* ATT_SUCCESS if nothing to configure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttcDiscConfigStart(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
/* use char list index to iterate over config list */
|
||||
pCb->charListIdx = 0;
|
||||
|
||||
return attcDiscConfigNext(connId, pCb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function initiates the next characteristic configuration procedure.
|
||||
* It should be called when an ATTC_READ_RSP or ATTC_WRITE_RSP callback event is received
|
||||
* after characteristic configuration is initiated by calling AttcDiscConfigStart().
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to discovery control block.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and configuration procedure is continuing.
|
||||
* ATT_SUCCESS if configuration procedure completed successfully.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttcDiscConfigCmpl(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
/* go to next in list */
|
||||
pCb->charListIdx++;
|
||||
|
||||
return attcDiscConfigNext(connId, pCb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This utility function resumes the characteristic configuration procedure. It can
|
||||
* be called when an ATTC_READ_RSP or ATTC_WRITE_RSP callback event is received
|
||||
* with failure status to attempt the read or write procedure again.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCb Pointer to discovery control block.
|
||||
*
|
||||
* \return ATT_CONTINUING if successful and configuration procedure is continuing.
|
||||
* ATT_SUCCESS if configuration procedure completed successfully.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttcDiscConfigResume(dmConnId_t connId, attcDiscCb_t *pCb)
|
||||
{
|
||||
return attcDiscConfigNext(connId, pCb);
|
||||
}
|
||||
Vendored
+840
@@ -0,0 +1,840 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client main 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_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_math.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "attc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* type for send request function */
|
||||
typedef void (*attcSendReq_t)(attcCcb_t *pCcb);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
static void attcDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket);
|
||||
static void attcCtrlCback(wsfMsgHdr_t *pMsg);
|
||||
static void attcConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt);
|
||||
static void attcMsgCback(attcApiMsg_t *pMsg);
|
||||
|
||||
static void attcSendSimpleReq(attcCcb_t *pCcb);
|
||||
static void attcSendContinuingReq(attcCcb_t *pCcb);
|
||||
static void attcSendMtuReq(attcCcb_t *pCcb);
|
||||
static void attcSendWriteCmd(attcCcb_t *pCcb);
|
||||
static void attcSendPrepWriteReq(attcCcb_t *pCcb);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Interface to ATT */
|
||||
static const attFcnIf_t attcFcnIf =
|
||||
{
|
||||
attcDataCback,
|
||||
attcCtrlCback,
|
||||
(attMsgHandler_t) attcMsgCback,
|
||||
attcConnCback
|
||||
};
|
||||
|
||||
/* Table of send request functions */
|
||||
static const attcSendReq_t attcSendReqTbl[] =
|
||||
{
|
||||
NULL, /* ATTC_MSG_API_NONE (unused) */
|
||||
attcSendMtuReq, /* ATTC_MSG_API_MTU */
|
||||
attcSendContinuingReq, /* ATTC_MSG_API_FIND_INFO */
|
||||
attcSendContinuingReq, /* ATTC_MSG_API_FIND_BY_TYPE_VALUE */
|
||||
attcSendContinuingReq, /* ATTC_MSG_API_READ_BY_TYPE */
|
||||
attcSendSimpleReq, /* ATTC_MSG_API_READ */
|
||||
attcSendContinuingReq, /* ATTC_MSG_API_READ_LONG */
|
||||
attcSendSimpleReq, /* ATTC_MSG_API_READ_MULTIPLE */
|
||||
attcSendContinuingReq, /* ATTC_MSG_API_READ_BY_GROUP_TYPE */
|
||||
attcSendSimpleReq, /* ATTC_MSG_API_WRITE */
|
||||
attcSendWriteCmd, /* ATTC_MSG_API_WRITE_CMD */
|
||||
attcSendPrepWriteReq, /* ATTC_MSG_API_PREP_WRITE */
|
||||
attcSendSimpleReq /* ATTC_MSG_API_EXEC_WRITE */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
attcCb_t attcCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if application callback is pending for a given write command, or the maximum
|
||||
* number of simultaneous write commands has been reached.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
* \param pMsg ATTC message.
|
||||
*
|
||||
* \return TRUE if app callback's pending or maximum number of simultaneous write commands reached.
|
||||
* FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t attcPendWriteCmd(attcCcb_t *pCcb, attcApiMsg_t *pMsg)
|
||||
{
|
||||
uint8_t pendRsp;
|
||||
uint8_t i;
|
||||
|
||||
/* initialize number of response callbacks pending */
|
||||
pendRsp = 0;
|
||||
|
||||
for (i = 0; i < ATT_NUM_SIMUL_WRITE_CMD; i++)
|
||||
{
|
||||
/* if callback pending for write command */
|
||||
if (pCcb->pendWriteCmdHandle[i] != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* if callback pending for this handle */
|
||||
if (pCcb->pendWriteCmdHandle[i] == pMsg->handle)
|
||||
{
|
||||
/* callback pending for this write command */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pendRsp++;
|
||||
}
|
||||
}
|
||||
|
||||
/* no callback is pending for this write command but see if the maximum number of simultaneous
|
||||
write commands has been reached */
|
||||
return (pendRsp < ATT_NUM_SIMUL_WRITE_CMD) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set pending write command response callback for a given attribute handle.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSetPendWriteCmd(attcCcb_t *pCcb)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ATT_NUM_SIMUL_WRITE_CMD; i++)
|
||||
{
|
||||
/* if entry free */
|
||||
if (pCcb->pendWriteCmdHandle[i] == ATT_HANDLE_NONE)
|
||||
{
|
||||
/* set pending write command handle */
|
||||
pCcb->pendWriteCmdHandle[i] = pCcb->outReq.handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Call pending write command response application callback.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCcb ATTC control block.
|
||||
* \param status Callback event status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcWriteCmdCallback(dmConnId_t connId, attcCcb_t *pCcb, uint8_t status)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if any pending write command callback */
|
||||
for (i = 0; i < ATT_NUM_SIMUL_WRITE_CMD; i++)
|
||||
{
|
||||
if (pCcb->pendWriteCmdHandle[i] != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* call callback with status */
|
||||
attcExecCallback(connId, ATTC_WRITE_CMD_RSP, pCcb->pendWriteCmdHandle[i], status);
|
||||
pCcb->pendWriteCmdHandle[i] = ATT_HANDLE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send attribute client request that has already been built.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSendSimpleReq(attcCcb_t *pCcb)
|
||||
{
|
||||
attcPktParam_t *pPkt = pCcb->outReq.pPkt;
|
||||
|
||||
/* clear stored packet pointer */
|
||||
pCcb->outReq.pPkt = NULL;
|
||||
|
||||
/* start request timer (except for write command) */
|
||||
if (pCcb->outReq.hdr.event != ATTC_MSG_API_WRITE_CMD)
|
||||
{
|
||||
pCcb->outReqTimer.msg.event = ATTC_MSG_REQ_TIMEOUT;
|
||||
WsfTimerStartSec(&pCcb->outReqTimer, pAttCfg->transTimeout);
|
||||
}
|
||||
|
||||
/* send packet to L2CAP */
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, pPkt->len, (uint8_t *) pPkt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request that may be continuing.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSendContinuingReq(attcCcb_t *pCcb)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* allocate new buffer */
|
||||
if ((pPkt = attMsgAlloc(pCcb->outReq.pPkt->len + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* copy stored packet to new */
|
||||
memcpy(pPkt, pCcb->outReq.pPkt, pCcb->outReq.pPkt->len + L2C_PAYLOAD_START);
|
||||
}
|
||||
/* else handle error case of allocation failure */
|
||||
else
|
||||
{
|
||||
/* free stored packet and call callback with failure status */
|
||||
attcReqClear(pCcb, &pCcb->outReq, ATT_ERR_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* else not continuing */
|
||||
else
|
||||
{
|
||||
/* send the stored packet */
|
||||
pPkt = pCcb->outReq.pPkt;
|
||||
|
||||
/* clear stored packet pointer */
|
||||
pCcb->outReq.pPkt = NULL;
|
||||
}
|
||||
|
||||
/* build remaining fields of packet from stored parameters */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_READ_LONG)
|
||||
{
|
||||
/* build offset field */
|
||||
p += sizeof(uint16_t);
|
||||
UINT16_TO_BSTREAM(p, pCcb->outReqParams.o.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Find Info, Find By Type Value, Read By Type, and Read By Group Type
|
||||
* request packets all begin with a start handle and end handle.
|
||||
*/
|
||||
UINT16_TO_BSTREAM(p, pCcb->outReqParams.h.startHandle);
|
||||
UINT16_TO_BSTREAM(p, pCcb->outReqParams.h.endHandle);
|
||||
}
|
||||
|
||||
/* start request timer */
|
||||
pCcb->outReqTimer.msg.event = ATTC_MSG_REQ_TIMEOUT;
|
||||
WsfTimerStartSec(&pCcb->outReqTimer, pAttCfg->transTimeout);
|
||||
|
||||
/* send packet to L2CAP */
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, pPkt->len, (uint8_t *) pPkt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send MTU request.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSendMtuReq(attcCcb_t *pCcb)
|
||||
{
|
||||
/* if MTU already exchanged */
|
||||
if (pCcb->pMainCcb->control & ATT_CCB_STATUS_MTU_SENT)
|
||||
{
|
||||
/* discard request */
|
||||
attcFreePkt(&pCcb->outReq);
|
||||
|
||||
/* clear out req */
|
||||
pCcb->outReq.hdr.event = ATTC_MSG_API_NONE;
|
||||
|
||||
ATT_TRACE_WARN0("MTU req discarded");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set MTU sent */
|
||||
pCcb->pMainCcb->control |= ATT_CCB_STATUS_MTU_SENT;
|
||||
|
||||
/* send packet */
|
||||
attcSendSimpleReq(pCcb);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send attribute client Write command.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSendWriteCmd(attcCcb_t *pCcb)
|
||||
{
|
||||
/* send packet */
|
||||
attcSendSimpleReq(pCcb);
|
||||
|
||||
/* if flow not disabled */
|
||||
if (!(pCcb->pMainCcb->control & ATT_CCB_STATUS_FLOW_DISABLED))
|
||||
{
|
||||
/* call callback */
|
||||
attcExecCallback(pCcb->pMainCcb->connId, ATTC_WRITE_CMD_RSP, pCcb->outReq.handle, ATT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set pending write command callback for this handle */
|
||||
attcSetPendWriteCmd(pCcb);
|
||||
}
|
||||
|
||||
/* clear out req */
|
||||
pCcb->outReq.hdr.event = ATTC_MSG_API_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send attribute client Prepare Write request.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSendPrepWriteReq(attcCcb_t *pCcb)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
uint16_t dataLen;
|
||||
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* determine size of buffer to allocate */
|
||||
if (pCcb->outReqParams.w.len < (pCcb->pMainCcb->mtu - ATT_PREP_WRITE_REQ_LEN))
|
||||
{
|
||||
dataLen = pCcb->outReqParams.w.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataLen = pCcb->pMainCcb->mtu - ATT_PREP_WRITE_REQ_LEN;
|
||||
}
|
||||
|
||||
/* allocate new buffer */
|
||||
if ((pPkt = attMsgAlloc(dataLen + ATT_PREP_WRITE_REQ_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* copy fixed fields */
|
||||
memcpy(pPkt, pCcb->outReq.pPkt, ATT_PREP_WRITE_REQ_LEN + L2C_PAYLOAD_START);
|
||||
|
||||
/* copy data */
|
||||
memcpy(((uint8_t *) pPkt + L2C_PAYLOAD_START + ATT_PREP_WRITE_REQ_LEN),
|
||||
pCcb->outReqParams.w.pValue, dataLen);
|
||||
|
||||
/* update length and data pointer */
|
||||
pCcb->outReqParams.w.pValue += dataLen;
|
||||
pCcb->outReqParams.w.len -= dataLen;
|
||||
}
|
||||
/* else handle error case of allocation failure */
|
||||
else
|
||||
{
|
||||
/* free stored packet and call callback with failure status */
|
||||
attcReqClear(pCcb, &pCcb->outReq, ATT_ERR_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* else not continuing */
|
||||
else
|
||||
{
|
||||
dataLen = pCcb->outReqParams.w.len;
|
||||
|
||||
/* send the stored packet */
|
||||
pPkt = pCcb->outReq.pPkt;
|
||||
|
||||
/* clear stored packet pointer */
|
||||
pCcb->outReq.pPkt = NULL;
|
||||
}
|
||||
|
||||
/* build remaining fields of packet from stored parameters */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START + ATT_HDR_LEN + sizeof(uint16_t);
|
||||
UINT16_TO_BSTREAM(p, pCcb->outReqParams.w.offset);
|
||||
|
||||
/* update offset after building packet */
|
||||
pCcb->outReqParams.w.offset += dataLen;
|
||||
|
||||
/* start request timer */
|
||||
pCcb->outReqTimer.msg.event = ATTC_MSG_REQ_TIMEOUT;
|
||||
WsfTimerStartSec(&pCcb->outReqTimer, pAttCfg->transTimeout);
|
||||
|
||||
/* send packet to L2CAP */
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, dataLen + ATT_PREP_WRITE_REQ_LEN, (uint8_t *) pPkt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Lookup and execute function to build and send request.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcSendReq(attcCcb_t *pCcb)
|
||||
{
|
||||
(*attcSendReqTbl[pCcb->outReq.hdr.event])(pCcb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set up and send an attribute client request.
|
||||
*
|
||||
* \param pCcb ATTC control block.
|
||||
* \param pMsg ATTC message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcSetupReq(attcCcb_t *pCcb, attcApiMsg_t *pMsg)
|
||||
{
|
||||
/* set out req to api message */
|
||||
pCcb->outReq = *pMsg;
|
||||
|
||||
/* store parameters */
|
||||
pCcb->outReqParams = *(pMsg->pPkt);
|
||||
|
||||
/* build and send request */
|
||||
attcSendReq(pCcb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Data callback for ATTC.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t opcode;
|
||||
attcCcb_t *pCcb;
|
||||
|
||||
/* get connection control block for this handle, ignore packet if not found */
|
||||
if ((pCcb = attcCcbByHandle(handle)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse opcode */
|
||||
opcode = *(pPacket + L2C_PAYLOAD_START);
|
||||
|
||||
/* if response */
|
||||
if (opcode <= ATT_PDU_EXEC_WRITE_RSP)
|
||||
{
|
||||
attcProcRsp(pCcb, len, pPacket);
|
||||
}
|
||||
/* else if indication or notification */
|
||||
else if ((opcode == ATT_PDU_VALUE_NTF) || (opcode == ATT_PDU_VALUE_IND))
|
||||
{
|
||||
attcProcInd(pCcb, len, pPacket);
|
||||
}
|
||||
/* else unknown opcode */
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN1("attc unknown opcode 0x%02x", opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2CAP control callback.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
attcCcb_t *pCcb;
|
||||
|
||||
/* note this function is currently only called when flow is enabled */
|
||||
|
||||
/* get CCB */
|
||||
if ((pCcb = attcCcbByConnId((dmConnId_t) pMsg->param)) != NULL)
|
||||
{
|
||||
/* if confirmation pending try sending now */
|
||||
AttcIndConfirm((dmConnId_t) pMsg->param);
|
||||
|
||||
/* call pending write command callback */
|
||||
attcWriteCmdCallback((dmConnId_t) pMsg->param, pCcb, ATT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection callback for ATTC.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt)
|
||||
{
|
||||
attcCcb_t *pClient;
|
||||
uint16_t localMtu;
|
||||
uint8_t status;
|
||||
|
||||
/* if connection opened */
|
||||
if (pDmEvt->hdr.event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
/* if we initiated connection send MTU request */
|
||||
if (DmConnRole(pCcb->connId) == DM_ROLE_MASTER)
|
||||
{
|
||||
localMtu = WSF_MIN(pAttCfg->mtu, (HciGetMaxRxAclLen() - L2C_HDR_LEN));
|
||||
|
||||
/* if desired MTU is not the default */
|
||||
if (localMtu != ATT_DEFAULT_MTU)
|
||||
{
|
||||
AttcMtuReq(pCcb->connId, localMtu);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if connection closed */
|
||||
else if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* set status */
|
||||
if (pDmEvt->connClose.hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
status = pDmEvt->connClose.reason + ATT_HCI_ERR_BASE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = pDmEvt->connClose.hdr.status + ATT_HCI_ERR_BASE;
|
||||
}
|
||||
|
||||
/* get client control block directly */
|
||||
pClient = &attcCb.ccb[pCcb->connId - 1];
|
||||
|
||||
/* free any out req */
|
||||
if (pClient->outReq.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
WsfTimerStop(&pClient->outReqTimer);
|
||||
attcReqClear(pClient, &pClient->outReq, status);
|
||||
}
|
||||
|
||||
/* free any req on deck */
|
||||
if (pClient->onDeck.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
attcReqClear(pClient, &pClient->onDeck, status);
|
||||
}
|
||||
|
||||
/* initialize other control block variables */
|
||||
pClient->flowDisabled = FALSE;
|
||||
pClient->cnfPending = FALSE;
|
||||
|
||||
/* pass to connection close callback for signed data */
|
||||
if (attcCb.pSign != NULL)
|
||||
{
|
||||
(*attcCb.pSign->closeCback)(pClient, status);
|
||||
}
|
||||
|
||||
/* call pending write command callback */
|
||||
attcWriteCmdCallback(pCcb->connId, pClient, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Message handler callback for ATTC.
|
||||
*
|
||||
* \param pMsg ATTC message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcMsgCback(attcApiMsg_t *pMsg)
|
||||
{
|
||||
attcCcb_t *pCcb;
|
||||
|
||||
/* get CCB and verify connection still in use */
|
||||
if ((pCcb = attcCcbByConnId((dmConnId_t) pMsg->hdr.param)) == NULL)
|
||||
{
|
||||
/* if message has a packet buffer */
|
||||
if (pMsg->hdr.event >= ATTC_MSG_API_MTU &&
|
||||
pMsg->hdr.event <= ATTC_MSG_API_SIGNED_WRITE_CMD)
|
||||
{
|
||||
/* free packet buffer */
|
||||
attcFreePkt(pMsg);
|
||||
}
|
||||
|
||||
/* ignore if connection not in use */
|
||||
return;
|
||||
}
|
||||
|
||||
/* if an API request to send packet (non-signed) */
|
||||
if (pMsg->hdr.event <= ATTC_MSG_API_EXEC_WRITE)
|
||||
{
|
||||
/* verify no API request already waiting on deck, in progress, or no pending write command
|
||||
already for this handle */
|
||||
if ((pCcb->onDeck.hdr.event != ATTC_MSG_API_NONE) ||
|
||||
(pCcb->outReq.hdr.event > ATTC_MSG_API_MTU) ||
|
||||
((pMsg->hdr.event == ATTC_MSG_API_WRITE_CMD) &&
|
||||
attcPendWriteCmd(pCcb, pMsg)))
|
||||
{
|
||||
/* free request and call callback with failure status */
|
||||
attcReqClear(pCcb, pMsg, ATT_ERR_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if MTU request in progress or flow controlled */
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_MTU || pCcb->flowDisabled)
|
||||
{
|
||||
/* put request "on deck" for processing later */
|
||||
pCcb->onDeck = *pMsg;
|
||||
}
|
||||
/* otherwise ready to send; set up request */
|
||||
else
|
||||
{
|
||||
attcSetupReq(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
/* else if signed data event */
|
||||
else if (pMsg->hdr.event >= ATTC_MSG_API_SIGNED_WRITE_CMD &&
|
||||
pMsg->hdr.event <= ATTC_MSG_CMAC_CMPL)
|
||||
{
|
||||
/* pass to message callback for signed data */
|
||||
if (attcCb.pSign != NULL)
|
||||
{
|
||||
(*attcCb.pSign->msgCback)(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
/* else if cancel request */
|
||||
else if (pMsg->hdr.event == ATTC_MSG_API_CANCEL)
|
||||
{
|
||||
/* free any out req (except mtu req) */
|
||||
if (pCcb->outReq.hdr.event != ATTC_MSG_API_NONE &&
|
||||
pCcb->outReq.hdr.event != ATTC_MSG_API_MTU)
|
||||
{
|
||||
WsfTimerStop(&pCcb->outReqTimer);
|
||||
attcReqClear(pCcb, &pCcb->outReq, ATT_ERR_CANCELLED);
|
||||
}
|
||||
/* else free any req on deck */
|
||||
else if (pCcb->onDeck.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
attcReqClear(pCcb, &pCcb->onDeck, ATT_ERR_CANCELLED);
|
||||
}
|
||||
}
|
||||
/* else if timeout */
|
||||
else if (pMsg->hdr.event == ATTC_MSG_REQ_TIMEOUT)
|
||||
{
|
||||
/* free any out req */
|
||||
if (pCcb->outReq.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
attcReqClear(pCcb, &pCcb->outReq, ATT_ERR_TIMEOUT);
|
||||
pCcb->pMainCcb->control |= ATT_CCB_STATUS_TX_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the ATTC connection control block connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to connection control block or NULL if not in use.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
attcCcb_t *attcCcbByConnId(dmConnId_t connId)
|
||||
{
|
||||
if (DmConnInUse(connId))
|
||||
{
|
||||
return &attcCb.ccb[connId - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN1("attc ccb not in use: %d", connId);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the connection control block for the given handle.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
*
|
||||
* \return Pointer to connection control block or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
attcCcb_t *attcCcbByHandle(uint16_t handle)
|
||||
{
|
||||
dmConnId_t connId;
|
||||
|
||||
if ((connId = DmConnIdByHandle(handle)) != DM_CONN_ID_NONE)
|
||||
{
|
||||
return &attcCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free the packet buffer of an API message structure.
|
||||
*
|
||||
* \param pMsg Pointer to API message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcFreePkt(attcApiMsg_t *pMsg)
|
||||
{
|
||||
if (pMsg->pPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pMsg->pPkt);
|
||||
pMsg->pPkt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute application callback function.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param event Callback event ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param status Callback event status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcExecCallback(dmConnId_t connId, uint8_t event, uint16_t handle, uint8_t status)
|
||||
{
|
||||
if (event != ATT_METHOD_MTU)
|
||||
{
|
||||
attExecCallback(connId, event, handle, status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear an outstanding request and execute the callback.
|
||||
*
|
||||
* \param pCcb Pointer to control block.
|
||||
* \param pMsg API message.
|
||||
* \param status Callback event status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcReqClear(attcCcb_t *pCcb, attcApiMsg_t *pMsg, uint8_t status)
|
||||
{
|
||||
attcFreePkt(pMsg);
|
||||
attcExecCallback(pCcb->pMainCcb->connId, pMsg->hdr.event, pMsg->handle, status);
|
||||
pMsg->hdr.event = ATTC_MSG_API_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set automatic Indication Confirmations sent from this ATT Client.
|
||||
*
|
||||
* \param enable \ref TRUE to enable automatic confirmations (default), \ref FALSE to disable.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcSetAutoConfirm(bool_t enable)
|
||||
{
|
||||
attcCb.autoCnf = enable;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATT client.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
attcCcb_t *pCcb;
|
||||
|
||||
/* Initialize control block */
|
||||
attcCb.pSign = NULL;
|
||||
attcCb.autoCnf = TRUE;
|
||||
|
||||
/* Initialize control block CCBs */
|
||||
for (i = 0, pCcb = attcCb.ccb; i < DM_CONN_MAX; i++, pCcb++)
|
||||
{
|
||||
/* set pointer to main CCB */
|
||||
pCcb->pMainCcb = &attCb.ccb[i];
|
||||
|
||||
/* initialize timer */
|
||||
pCcb->outReqTimer.handlerId = attCb.handlerId;
|
||||
pCcb->outReqTimer.msg.param = i + 1; /* param stores the conn id */
|
||||
}
|
||||
|
||||
/* set up callback interface */
|
||||
attCb.pClient = &attcFcnIf;
|
||||
}
|
||||
Vendored
+208
@@ -0,0 +1,208 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client main 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef ATTC_MAIN_H
|
||||
#define ATTC_MAIN_H
|
||||
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Buffer lengths for requests */
|
||||
#define ATT_MTU_REQ_BUF_LEN (ATT_MTU_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_FIND_INFO_REQ_BUF_LEN (ATT_FIND_INFO_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_FIND_TYPE_REQ_BUF_LEN (ATT_FIND_TYPE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_READ_TYPE_REQ_BUF_LEN (ATT_READ_TYPE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_READ_REQ_BUF_LEN (ATT_READ_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_READ_BLOB_REQ_BUF_LEN (ATT_READ_BLOB_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_READ_MULT_REQ_BUF_LEN (ATT_READ_MULT_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_READ_GROUP_TYPE_REQ_BUF_LEN (ATT_READ_GROUP_TYPE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_WRITE_REQ_BUF_LEN (ATT_WRITE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_WRITE_CMD_BUF_LEN (ATT_WRITE_CMD_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_SIGNED_WRITE_CMD_BUF_LEN (ATT_SIGNED_WRITE_CMD_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_PREP_WRITE_REQ_BUF_LEN (ATT_PREP_WRITE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
#define ATT_EXEC_WRITE_REQ_BUF_LEN (ATT_EXEC_WRITE_REQ_LEN + L2C_PAYLOAD_START)
|
||||
|
||||
/* values for 'continuing' flag */
|
||||
#define ATTC_CONTINUING TRUE
|
||||
#define ATTC_NOT_CONTINUING FALSE
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* ATTC event handler messages */
|
||||
enum
|
||||
{
|
||||
/* messages from API; note these match method values */
|
||||
ATTC_MSG_API_NONE = ATTC_MSG_START,
|
||||
ATTC_MSG_API_MTU = ATT_METHOD_MTU,
|
||||
ATTC_MSG_API_FIND_INFO = ATT_METHOD_FIND_INFO,
|
||||
ATTC_MSG_API_FIND_BY_TYPE_VALUE = ATT_METHOD_FIND_TYPE,
|
||||
ATTC_MSG_API_READ_BY_TYPE = ATT_METHOD_READ_TYPE,
|
||||
ATTC_MSG_API_READ = ATT_METHOD_READ,
|
||||
ATTC_MSG_API_READ_LONG = ATT_METHOD_READ_BLOB,
|
||||
ATTC_MSG_API_READ_MULTIPLE = ATT_METHOD_READ_MULTIPLE,
|
||||
ATTC_MSG_API_READ_BY_GROUP_TYPE = ATT_METHOD_READ_GROUP_TYPE,
|
||||
ATTC_MSG_API_WRITE = ATT_METHOD_WRITE,
|
||||
ATTC_MSG_API_WRITE_CMD = ATT_METHOD_WRITE_CMD,
|
||||
ATTC_MSG_API_PREP_WRITE = ATT_METHOD_PREPARE_WRITE,
|
||||
ATTC_MSG_API_EXEC_WRITE = ATT_METHOD_EXECUTE_WRITE,
|
||||
ATTC_MSG_API_SIGNED_WRITE_CMD,
|
||||
ATTC_MSG_CMAC_CMPL,
|
||||
ATTC_MSG_API_CANCEL,
|
||||
ATTC_MSG_REQ_TIMEOUT
|
||||
};
|
||||
|
||||
/*!
|
||||
* Data buffer format for API request messages:
|
||||
*
|
||||
* | attcPktParam_t | ATT request data |
|
||||
* | bytes 0 to 7 | bytes 8 - |
|
||||
*/
|
||||
|
||||
/* Structure for API with offset parameter */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t offset;
|
||||
} attcPktParamOffset_t;
|
||||
|
||||
/* Structure for API with start and end handle parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
} attcPktParamHandles_t;
|
||||
|
||||
/* Structure for API with offset and value parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t offset;
|
||||
uint8_t *pValue;
|
||||
} attcPktParamPrepWrite_t;
|
||||
|
||||
/* union of API parameter types */
|
||||
typedef union
|
||||
{
|
||||
uint16_t len;
|
||||
attcPktParamOffset_t o;
|
||||
attcPktParamHandles_t h;
|
||||
attcPktParamPrepWrite_t w;
|
||||
} attcPktParam_t;
|
||||
|
||||
/* verify attcPktParam_t will work in data buffer format described above */
|
||||
WSF_CT_ASSERT(sizeof(attcPktParam_t) <= L2C_PAYLOAD_START);
|
||||
|
||||
/* API message structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
attcPktParam_t *pPkt;
|
||||
uint16_t handle;
|
||||
} attcApiMsg_t;
|
||||
|
||||
/* ATTC connection control block */
|
||||
typedef struct
|
||||
{
|
||||
attCcb_t *pMainCcb; /* Pointer to ATT main CCB */
|
||||
attcApiMsg_t onDeck; /* API message "on deck" waiting to be sent */
|
||||
attcApiMsg_t outReq; /* Outstanding request waiting for response */
|
||||
attcPktParam_t outReqParams; /* Parameters associated with outstanding request */
|
||||
wsfTimer_t outReqTimer; /* Outstanding request timer */
|
||||
bool_t flowDisabled; /* Data flow disabled */
|
||||
bool_t cnfPending; /* Handle value confirm packet waiting to be sent */
|
||||
uint16_t pendWriteCmdHandle[ATT_NUM_SIMUL_WRITE_CMD]; /* Callback to app pending for this write cmd handle */
|
||||
} attcCcb_t;
|
||||
|
||||
/* Signed data callbacks */
|
||||
typedef void (*attcSignMsgCback_t)(attcCcb_t *pCcb, attcApiMsg_t *pMsg);
|
||||
typedef void (*attcCloseCback_t)(attcCcb_t *pCcb, uint8_t status);
|
||||
|
||||
/* Signed data callback interface */
|
||||
typedef struct
|
||||
{
|
||||
attcSignMsgCback_t msgCback; /* Message handling callback */
|
||||
attcCloseCback_t closeCback; /* Connection close callback */
|
||||
} attcSignFcnIf_t;
|
||||
|
||||
/* Main control block of the ATTC subsystem */
|
||||
typedef struct
|
||||
{
|
||||
attcCcb_t ccb[DM_CONN_MAX];
|
||||
attcSignFcnIf_t const *pSign;
|
||||
bool_t autoCnf;
|
||||
} attcCb_t;
|
||||
|
||||
/* type for response processing functions */
|
||||
typedef void (*attcProcRsp_t)(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
extern attcCb_t attcCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
attcCcb_t *attcCcbByConnId(dmConnId_t connId);
|
||||
attcCcb_t *attcCcbByHandle(uint16_t handle);
|
||||
void attcFreePkt(attcApiMsg_t *pMsg);
|
||||
void attcExecCallback(dmConnId_t connId, uint8_t event, uint16_t handle, uint8_t status);
|
||||
void attcReqClear(attcCcb_t *pCcb, attcApiMsg_t *pMsg, uint8_t status);
|
||||
|
||||
void attcSetupReq(attcCcb_t *pCcb, attcApiMsg_t *pMsg);
|
||||
void attcSendReq(attcCcb_t *pCcb);
|
||||
void attcSendMsg(dmConnId_t connId, uint16_t handle, uint8_t msgId, attcPktParam_t *pPkt, bool_t continuing);
|
||||
|
||||
void attcProcRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attcProcInd(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
|
||||
void attcProcErrRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcMtuRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcFindOrReadRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcFindByTypeRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcReadRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcReadLongRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcWriteRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
void attcProcPrepWriteRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATTC_MAIN_H */
|
||||
Vendored
+699
@@ -0,0 +1,699 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client mandatory PDU processing functions.
|
||||
*
|
||||
* 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_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_math.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "attc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Table of response processing functions */
|
||||
static const attcProcRsp_t attcProcRspTbl[] =
|
||||
{
|
||||
attcProcErrRsp, /* ATT_METHOD_ERR */
|
||||
attcProcMtuRsp, /* ATT_METHOD_MTU */
|
||||
attcProcFindOrReadRsp, /* ATT_METHOD_FIND_INFO */
|
||||
attcProcFindByTypeRsp, /* ATT_METHOD_FIND_TYPE */
|
||||
attcProcFindOrReadRsp, /* ATT_METHOD_READ_TYPE */
|
||||
attcProcReadRsp, /* ATT_METHOD_READ */
|
||||
attcProcReadLongRsp, /* ATT_METHOD_READ_BLOB */
|
||||
attcProcReadRsp, /* ATT_METHOD_READ_MULTIPLE */
|
||||
attcProcFindOrReadRsp, /* ATT_METHOD_READ_GROUP_TYPE */
|
||||
attcProcWriteRsp, /* ATT_METHOD_WRITE */
|
||||
NULL, /* ATT_METHOD_WRITE_CMD */
|
||||
attcProcPrepWriteRsp, /* ATT_METHOD_PREPARE_WRITE */
|
||||
attcProcWriteRsp /* ATT_METHOD_EXECUTE_WRITE */
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Error response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcErrRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
|
||||
/* set callback event from stored method */
|
||||
pEvt->hdr.event = pCcb->outReq.hdr.event;
|
||||
|
||||
/* ignore request opcode in the error response */
|
||||
p++;
|
||||
|
||||
/* if request was a read or write with a specific handle */
|
||||
if (pEvt->hdr.event == ATTC_READ_RSP || pEvt->hdr.event == ATTC_READ_LONG_RSP ||
|
||||
pEvt->hdr.event == ATTC_WRITE_RSP || pEvt->hdr.event == ATTC_PREPARE_WRITE_RSP)
|
||||
{
|
||||
/* ignore handle in the error response; callback will use stored handle from request */
|
||||
p += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set handle from packet */
|
||||
BSTREAM_TO_UINT16(pEvt->handle, p);
|
||||
}
|
||||
|
||||
/* set status from error code in packet, but verify it's not 'success' */
|
||||
BSTREAM_TO_UINT8(pEvt->hdr.status, p);
|
||||
if (pEvt->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_UNDEFINED;
|
||||
}
|
||||
|
||||
/* no parameters so clear length */
|
||||
pEvt->valueLen = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received MTU response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcMtuRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
uint16_t mtu;
|
||||
|
||||
BYTES_TO_UINT16(mtu, pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN);
|
||||
|
||||
/* verify */
|
||||
if (mtu < ATT_DEFAULT_MTU)
|
||||
{
|
||||
mtu = ATT_DEFAULT_MTU;
|
||||
}
|
||||
|
||||
/* set mtu for the connection */
|
||||
attSetMtu(pCcb->pMainCcb, mtu, WSF_MIN(pAttCfg->mtu, (HciGetMaxRxAclLen() - L2C_HDR_LEN)));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Find Information, Read By Type, or Read By Group Type
|
||||
* response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcFindOrReadRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t *pEnd;
|
||||
uint16_t handle;
|
||||
uint16_t nextHandle;
|
||||
uint16_t prevHandle;
|
||||
uint8_t paramLen;
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
pEnd = pPacket + L2C_PAYLOAD_START + len;
|
||||
|
||||
/* parameter length depends on packet type */
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_FIND_INFO)
|
||||
{
|
||||
/* length in find info response is coded by UUID */
|
||||
if (*p++ == ATT_FIND_HANDLE_16_UUID)
|
||||
{
|
||||
paramLen = ATT_16_UUID_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
paramLen = ATT_128_UUID_LEN;
|
||||
}
|
||||
}
|
||||
else if (pCcb->outReq.hdr.event == ATTC_MSG_API_READ_BY_TYPE)
|
||||
{
|
||||
/* length in read by type response is handle plus parameter length */
|
||||
paramLen = *p++ - sizeof(uint16_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* length in read by group type response is two handles plus parameter length */
|
||||
paramLen = *p++ - (2 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
/* get and verify all handles */
|
||||
nextHandle = pCcb->outReqParams.h.startHandle;
|
||||
while (p < pEnd)
|
||||
{
|
||||
/* get and compare handle */
|
||||
BSTREAM_TO_UINT16(handle, p);
|
||||
if (handle == 0 || nextHandle == 0 || handle < nextHandle ||
|
||||
handle > pCcb->outReqParams.h.endHandle)
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_INVALID_RSP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if read by group type response get second handle */
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_READ_BY_GROUP_TYPE)
|
||||
{
|
||||
prevHandle = handle;
|
||||
BSTREAM_TO_UINT16(handle, p);
|
||||
if (handle == 0 || handle < prevHandle || handle < nextHandle ||
|
||||
handle > pCcb->outReqParams.h.endHandle)
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_INVALID_RSP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set next expected handle, with special case for max handle */
|
||||
if (handle == ATT_HANDLE_MAX)
|
||||
{
|
||||
nextHandle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextHandle = handle + 1;
|
||||
}
|
||||
|
||||
/* skip over parameter */
|
||||
p += paramLen;
|
||||
|
||||
/* check for truncated response */
|
||||
if (p > pEnd)
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_INVALID_RSP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if response was correct */
|
||||
if (pEvt->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* if all handles read */
|
||||
if (nextHandle == 0 || nextHandle == (pCcb->outReqParams.h.endHandle + 1))
|
||||
{
|
||||
/* we're done */
|
||||
pCcb->outReq.hdr.status = ATTC_NOT_CONTINUING;
|
||||
}
|
||||
/* else set up for next request */
|
||||
else
|
||||
{
|
||||
pCcb->outReqParams.h.startHandle = nextHandle;
|
||||
pCcb->outReq.handle = nextHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Read response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcReadRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
/* nothing to process */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Write response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcWriteRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
/* no parameters so clear length */
|
||||
pEvt->valueLen = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
attEvt_t evt;
|
||||
|
||||
/* if no request in progress ignore response */
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* get method */
|
||||
evt.hdr.event = ATT_OPCODE_2_METHOD(*(pPacket + L2C_PAYLOAD_START));
|
||||
|
||||
/* if response method is not error and does not match stored method ignore response */
|
||||
if ((evt.hdr.event != ATT_METHOD_ERR) && (evt.hdr.event != pCcb->outReq.hdr.event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* stop request timer */
|
||||
WsfTimerStop(&pCcb->outReqTimer);
|
||||
|
||||
/* initialize event structure then process response */
|
||||
evt.pValue = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
evt.valueLen = len - ATT_HDR_LEN;
|
||||
evt.handle = pCcb->outReq.handle;
|
||||
evt.hdr.status = ATT_SUCCESS;
|
||||
(*attcProcRspTbl[evt.hdr.event])(pCcb, len, pPacket, &evt);
|
||||
|
||||
/* if not continuing or status is not success */
|
||||
if ((pCcb->outReq.hdr.status == ATTC_NOT_CONTINUING) || (evt.hdr.status != ATT_SUCCESS))
|
||||
{
|
||||
/* we're not sending another request so clear the out req */
|
||||
pCcb->outReq.hdr.event = ATTC_MSG_API_NONE;
|
||||
attcFreePkt(&pCcb->outReq);
|
||||
}
|
||||
|
||||
/* call callback (if not mtu rsp) */
|
||||
if ((evt.hdr.event != ATT_METHOD_MTU) && attCb.cback)
|
||||
{
|
||||
/* set additional parameters and call callback */
|
||||
evt.continuing = pCcb->outReq.hdr.status; /* continuing flag */
|
||||
evt.hdr.param = pCcb->outReq.hdr.param; /* connId */
|
||||
(*attCb.cback)(&evt);
|
||||
}
|
||||
|
||||
/* if no flow control */
|
||||
if (!pCcb->flowDisabled)
|
||||
{
|
||||
/* if out req ready */
|
||||
if (pCcb->outReq.pPkt != NULL)
|
||||
{
|
||||
/* build and send request */
|
||||
attcSendReq(pCcb);
|
||||
}
|
||||
/* else if api is on deck */
|
||||
else if (pCcb->onDeck.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
/* set up and send request */
|
||||
attcSetupReq(pCcb, &pCcb->onDeck);
|
||||
|
||||
/* clear on deck */
|
||||
pCcb->onDeck.hdr.event = ATTC_MSG_API_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received indication or notification packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcInd(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
attEvt_t evt;
|
||||
uint8_t *p;
|
||||
uint8_t *pPkt;
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
|
||||
/* parse packet and set callback event struct */
|
||||
evt.hdr.event = ATT_OPCODE_2_METHOD(*p++);
|
||||
BSTREAM_TO_UINT16(evt.handle, p);
|
||||
evt.pValue = p;
|
||||
evt.valueLen = len - ATT_HDR_LEN - sizeof(uint16_t);
|
||||
evt.hdr.param = pCcb->pMainCcb->connId;
|
||||
evt.hdr.status = ATT_SUCCESS;
|
||||
evt.continuing = FALSE;
|
||||
|
||||
/* verify handle and call callback */
|
||||
if ((evt.handle != 0) && attCb.cback)
|
||||
{
|
||||
(*attCb.cback)(&evt);
|
||||
}
|
||||
|
||||
/* if indication send confirm */
|
||||
if (attcCb.autoCnf && (evt.hdr.event == ATT_METHOD_VALUE_IND))
|
||||
{
|
||||
if (!pCcb->flowDisabled)
|
||||
{
|
||||
if ((pPkt = attMsgAlloc(ATT_VALUE_CNF_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
*(pPkt + L2C_PAYLOAD_START) = ATT_PDU_VALUE_CNF;
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, ATT_VALUE_CNF_LEN, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark confirm as pending; will be sent when flow enabled or application sends it. */
|
||||
pCcb->cnfPending = TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build and send a WSF message to ATTC.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param msgId Message ID.
|
||||
* \param pPkt Packet parameters.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcSendMsg(dmConnId_t connId, uint16_t handle, uint8_t msgId, attcPktParam_t *pPkt, bool_t continuing)
|
||||
{
|
||||
attcCcb_t *pCcb;
|
||||
uint16_t mtu;
|
||||
bool_t transTimedOut;
|
||||
|
||||
WsfTaskLock();
|
||||
|
||||
/* get CCB and verify connection still in use */
|
||||
if ((pCcb = attcCcbByConnId(connId)) != NULL)
|
||||
{
|
||||
/* get MTU size */
|
||||
mtu = pCcb->pMainCcb->mtu;
|
||||
transTimedOut = !!(pCcb->pMainCcb->control & ATT_CCB_STATUS_TX_TIMEOUT);
|
||||
}
|
||||
/* else connection not in use */
|
||||
else
|
||||
{
|
||||
/* MTU size unknown */
|
||||
mtu = 0;
|
||||
transTimedOut = FALSE;
|
||||
}
|
||||
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if MTU size known for connection */
|
||||
if (mtu > 0)
|
||||
{
|
||||
/* if no transaction's timed out */
|
||||
if (!transTimedOut)
|
||||
{
|
||||
uint16_t dataLen = 0;
|
||||
|
||||
/* if packet is not null then find out its length */
|
||||
if (pPkt != NULL)
|
||||
{
|
||||
/* if not prepare write request */
|
||||
if (msgId != ATTC_MSG_API_PREP_WRITE)
|
||||
{
|
||||
dataLen = pPkt->len;
|
||||
}
|
||||
/* else prepare write request */
|
||||
else
|
||||
{
|
||||
/* if not continuing */
|
||||
if (!continuing)
|
||||
{
|
||||
/* single prepare write request */
|
||||
dataLen = ATT_PREP_WRITE_REQ_LEN + pPkt->w.len;
|
||||
}
|
||||
/* else will be sent as multiple prepare write requests */
|
||||
}
|
||||
}
|
||||
|
||||
/* if packet length is less than or equal to negotiated MTU */
|
||||
if (dataLen <= mtu)
|
||||
{
|
||||
attcApiMsg_t *pMsg;
|
||||
|
||||
/* allocate message buffer */
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(attcApiMsg_t))) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->hdr.status = continuing;
|
||||
pMsg->hdr.event = msgId;
|
||||
pMsg->pPkt = pPkt;
|
||||
pMsg->handle = handle;
|
||||
|
||||
/* send message */
|
||||
WsfMsgSend(attCb.handlerId, pMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* else packet length exceeds MTU size */
|
||||
else
|
||||
{
|
||||
/* call callback with failure status */
|
||||
attcExecCallback(connId, msgId, handle, ATT_ERR_MTU_EXCEEDED);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* transaction's timed out */
|
||||
{
|
||||
/* call callback with failure status */
|
||||
attcExecCallback(connId, msgId, handle, ATT_ERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* alloc failed, transaction's timed out or packet length exceeded MTU size; free packet buffer */
|
||||
if (pPkt != NULL)
|
||||
{
|
||||
WsfMsgFree(pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Find Information Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param startHandle Attribute start handle.
|
||||
* \param endHandle Attribute end handle.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcFindInfoReq(dmConnId_t connId, uint16_t startHandle, uint16_t endHandle, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_FIND_INFO_REQ_BUF_LEN)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->len = ATT_FIND_INFO_REQ_LEN;
|
||||
pPkt->h.startHandle = startHandle;
|
||||
pPkt->h.endHandle = endHandle;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_FIND_INFO_REQ);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, startHandle, ATTC_MSG_API_FIND_INFO, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Read Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcReadReq(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_READ_REQ_BUF_LEN)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_READ_REQ_LEN;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_REQ);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_READ, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Write Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcWriteReq(dmConnId_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_WRITE_REQ_BUF_LEN + valueLen)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_WRITE_REQ_LEN + valueLen;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_WRITE_REQ);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pValue, valueLen);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_WRITE, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel an attribute protocol request in progress.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcCancelReq(dmConnId_t connId)
|
||||
{
|
||||
attcSendMsg(connId, 0, ATTC_MSG_API_CANCEL, NULL, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param mtu Attribute protocol MTU.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcMtuReq(dmConnId_t connId, uint16_t mtu)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_MTU_REQ_BUF_LEN)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_MTU_REQ_LEN;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_MTU_REQ);
|
||||
UINT16_TO_BSTREAM(p, mtu);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, 0, ATTC_MSG_API_MTU, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol indication confirmation.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcIndConfirm(dmConnId_t connId)
|
||||
{
|
||||
attcCcb_t *pCcb;
|
||||
uint8_t *pPkt;
|
||||
|
||||
pCcb = attcCcbByHandle(connId - 1);
|
||||
|
||||
/* If confirmation is pending */
|
||||
if (pCcb && pCcb->cnfPending && !pCcb->flowDisabled)
|
||||
{
|
||||
if ((pPkt = attMsgAlloc(ATT_VALUE_CNF_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
pCcb->cnfPending = FALSE;
|
||||
|
||||
*(pPkt + L2C_PAYLOAD_START) = ATT_PDU_VALUE_CNF;
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, ATT_VALUE_CNF_LEN, pPkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+347
@@ -0,0 +1,347 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client optional read PDU processing functions.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "attc_main.h"
|
||||
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Find By Type response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcFindByTypeRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t *pEnd;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
uint16_t nextHandle;
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
pEnd = pPacket + L2C_PAYLOAD_START + len;
|
||||
|
||||
/* get and verify all handles */
|
||||
nextHandle = pCcb->outReqParams.h.startHandle;
|
||||
while (p < pEnd)
|
||||
{
|
||||
/* get handle pair */
|
||||
BSTREAM_TO_UINT16(startHandle, p);
|
||||
BSTREAM_TO_UINT16(endHandle, p);
|
||||
|
||||
/*
|
||||
* start handle of handle pair must be:
|
||||
* not greater than end handle of handle pair
|
||||
* not less than than start handle of request or end handle of previous handle pair
|
||||
* not greater than end handle of request
|
||||
* and no additional handle pairs following end handle = 0xFFFF
|
||||
*/
|
||||
if ((startHandle > endHandle) || (startHandle < nextHandle) ||
|
||||
(startHandle > pCcb->outReqParams.h.endHandle) || (nextHandle == 0))
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_INVALID_RSP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set next expected handle, with special case for max handle */
|
||||
if (endHandle == ATT_HANDLE_MAX)
|
||||
{
|
||||
nextHandle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextHandle = endHandle + 1;
|
||||
}
|
||||
|
||||
/* check for truncated response */
|
||||
if (p > pEnd)
|
||||
{
|
||||
pEvt->hdr.status = ATT_ERR_INVALID_RSP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if response was correct */
|
||||
if (pEvt->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* if all handles read */
|
||||
if (nextHandle == 0 || nextHandle > pCcb->outReqParams.h.endHandle)
|
||||
{
|
||||
/* we're done */
|
||||
pCcb->outReq.hdr.status = ATTC_NOT_CONTINUING;
|
||||
}
|
||||
/* else set up for next request */
|
||||
else
|
||||
{
|
||||
pCcb->outReqParams.h.startHandle = nextHandle;
|
||||
pCcb->outReq.handle = nextHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Read Long response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcReadLongRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* length of response is less than mtu */
|
||||
if (len < pCcb->pMainCcb->mtu)
|
||||
{
|
||||
/* we're done */
|
||||
pCcb->outReq.hdr.status = ATTC_NOT_CONTINUING;
|
||||
}
|
||||
/* else set up for next request */
|
||||
else
|
||||
{
|
||||
pCcb->outReqParams.o.offset += pEvt->valueLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Find By Type Value Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param startHandle Attribute start handle.
|
||||
* \param endHandle Attribute end handle.
|
||||
* \param uuid16 16-bit UUID to find.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcFindByTypeValueReq(dmConnId_t connId, uint16_t startHandle, uint16_t endHandle,
|
||||
uint16_t uuid16, uint16_t valueLen, uint8_t *pValue, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_FIND_TYPE_REQ_BUF_LEN + valueLen)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->len = ATT_FIND_TYPE_REQ_LEN + valueLen;
|
||||
pPkt->h.startHandle = startHandle;
|
||||
pPkt->h.endHandle = endHandle;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_FIND_TYPE_REQ);
|
||||
/* skip start and end handle fields */
|
||||
p += (2 * sizeof(uint16_t));
|
||||
UINT16_TO_BSTREAM(p, uuid16);
|
||||
memcpy(p, pValue, valueLen);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, startHandle, ATTC_MSG_API_FIND_BY_TYPE_VALUE, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Read By Type Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param startHandle Attribute start handle.
|
||||
* \param endHandle Attribute end handle.
|
||||
* \param uuidLen Length of UUID (2 or 16).
|
||||
* \param pUuid Pointer to UUID data.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcReadByTypeReq(dmConnId_t connId, uint16_t startHandle, uint16_t endHandle,
|
||||
uint8_t uuidLen, uint8_t *pUuid, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_READ_TYPE_REQ_BUF_LEN + uuidLen)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->len = ATT_READ_TYPE_REQ_LEN + uuidLen;
|
||||
pPkt->h.startHandle = startHandle;
|
||||
pPkt->h.endHandle = endHandle;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_TYPE_REQ);
|
||||
/* skip start and end handle fields */
|
||||
p += (2 * sizeof(uint16_t));
|
||||
memcpy(p, pUuid, uuidLen);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, startHandle, ATTC_MSG_API_READ_BY_TYPE, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Read Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param offset Read attribute data starting at this offset.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcReadLongReq(dmConnId_t connId, uint16_t handle, uint16_t offset, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_READ_BLOB_REQ_BUF_LEN)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->len = ATT_READ_BLOB_REQ_LEN;
|
||||
pPkt->o.offset = offset;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_BLOB_REQ);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_READ_LONG, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Read Multiple Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param numHandles Number of handles in attribute handle list.
|
||||
* \param pHandles List of attribute handles.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcReadMultipleReq(dmConnId_t connId, uint8_t numHandles, uint16_t *pHandles)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
uint16_t handle;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_READ_MULT_REQ_BUF_LEN + (numHandles * sizeof(uint16_t)))) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_READ_MULT_REQ_LEN + (numHandles * sizeof(uint16_t));
|
||||
|
||||
/* save first handle */
|
||||
handle = pHandles[0];
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_MULT_REQ);
|
||||
while (numHandles--)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, *pHandles);
|
||||
pHandles++;
|
||||
}
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_READ_MULTIPLE, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Read By Group Type Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param startHandle Attribute start handle.
|
||||
* \param endHandle Attribute end handle.
|
||||
* \param uuidLen Length of UUID (2 or 16).
|
||||
* \param pUuid Pointer to UUID data.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcReadByGroupTypeReq(dmConnId_t connId, uint16_t startHandle, uint16_t endHandle,
|
||||
uint8_t uuidLen, uint8_t *pUuid, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_READ_GROUP_TYPE_REQ_BUF_LEN + uuidLen)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->len = ATT_READ_GROUP_TYPE_REQ_LEN + uuidLen;
|
||||
pPkt->h.startHandle = startHandle;
|
||||
pPkt->h.endHandle = endHandle;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_GROUP_TYPE_REQ);
|
||||
/* skip start and end handle fields */
|
||||
p += (2 * sizeof(uint16_t));
|
||||
memcpy(p, pUuid, uuidLen);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, startHandle, ATTC_MSG_API_READ_BY_GROUP_TYPE, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
Vendored
+303
@@ -0,0 +1,303 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client optional signed PDU processing functions.
|
||||
*
|
||||
* 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_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "attc_main.h"
|
||||
#include "att_sign.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* ATTC signed PDU control block */
|
||||
typedef struct
|
||||
{
|
||||
attcApiMsg_t msg;
|
||||
} attcSignCb_t;
|
||||
|
||||
/* Message parameters */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
attcApiMsg_t api;
|
||||
} attcSignMsg_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
static void attcSignCloseCback(attcCcb_t *pCcb, uint8_t status);
|
||||
static void attcSignMsgCback(attcCcb_t *pCcb, attcSignMsg_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Interface to ATT */
|
||||
static const attcSignFcnIf_t attcSignFcnIf =
|
||||
{
|
||||
(attcSignMsgCback_t) attcSignMsgCback,
|
||||
attcSignCloseCback
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
static attcSignCb_t *pAttcSignCb[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate a signing control block.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static attcSignCb_t *attcSignCbAlloc(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
WSF_ASSERT(pAttcSignCb[connId - 1] == NULL);
|
||||
|
||||
return (pAttcSignCb[connId - 1] = WsfBufAlloc(sizeof(attcSignCb_t)));
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free a signing control block.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSignCbFree(dmConnId_t connId)
|
||||
{
|
||||
WsfBufFree(pAttcSignCb[connId - 1]);
|
||||
pAttcSignCb[connId - 1] = NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the signing control block for the connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static attcSignCb_t *attcSignCbByConnId(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
return pAttcSignCb[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection close callback for ATTC signed PDU processing.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param status Connection close status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSignCloseCback(attcCcb_t *pCcb, uint8_t status)
|
||||
{
|
||||
attcSignCb_t *pCb;
|
||||
|
||||
/* if connection closed while processing in progress */
|
||||
if ((pCb = attcSignCbByConnId(pCcb->pMainCcb->connId)) != NULL)
|
||||
{
|
||||
|
||||
/* message free buffer */
|
||||
if (pCb->msg.hdr.event != ATTC_MSG_API_NONE)
|
||||
{
|
||||
attcReqClear(pCcb, &pCb->msg, status);
|
||||
}
|
||||
|
||||
attcSignCbFree(pCcb->pMainCcb->connId);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Message handler callback for ATTC signed PDU processing.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param pMsg ATTC message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attcSignMsgCback(attcCcb_t *pCcb, attcSignMsg_t *pMsg)
|
||||
{
|
||||
attcSignCb_t *pCb;
|
||||
|
||||
if (pMsg->hdr.event == ATTC_MSG_API_SIGNED_WRITE_CMD)
|
||||
{
|
||||
/* adjust msg event id for later use with app callback */
|
||||
pMsg->hdr.event = ATTC_MSG_API_WRITE_CMD;
|
||||
|
||||
/* verify no API request already waiting on deck or in progress,
|
||||
* and no signed write already in progress
|
||||
*/
|
||||
if ((pCcb->onDeck.hdr.event != ATTC_MSG_API_NONE) ||
|
||||
(pCcb->outReq.hdr.event > ATTC_MSG_API_MTU) ||
|
||||
(attcSignCbByConnId((dmConnId_t) pMsg->hdr.param) != NULL))
|
||||
{
|
||||
/* free request and call callback with failure status */
|
||||
attcReqClear(pCcb, &pMsg->api, ATT_ERR_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate signing control block */
|
||||
if ((pCb = attcSignCbAlloc((dmConnId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
/* store message */
|
||||
pCb->msg = pMsg->api;
|
||||
|
||||
uint16_t cmacTxtLen = pCb->msg.pPkt->len - ATT_AUTH_SIG_LEN + sizeof(uint32_t);
|
||||
uint8_t *pCmacText = WsfBufAlloc(cmacTxtLen);
|
||||
|
||||
if (pCmacText)
|
||||
{
|
||||
uint8_t revLocalCsrk[SEC_CMAC_KEY_LEN] = {0};
|
||||
|
||||
WStrReverseCpy(revLocalCsrk, DmSecGetLocalCsrk(), SEC_CMAC_KEY_LEN);
|
||||
WStrReverseCpy(pCmacText, (uint8_t *)pCb->msg.pPkt + L2C_PAYLOAD_START, cmacTxtLen);
|
||||
|
||||
if (SecCmac(revLocalCsrk, pCmacText, cmacTxtLen, attCb.handlerId,
|
||||
(dmConnId_t) pMsg->hdr.param, ATTC_MSG_CMAC_CMPL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WsfBufFree(pCmacText);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allocation failure */
|
||||
attcReqClear(pCcb, &pMsg->api, ATT_ERR_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (pMsg->hdr.event == ATTC_MSG_CMAC_CMPL)
|
||||
{
|
||||
secCmacMsg_t *pCmacMsg = (secCmacMsg_t*) pMsg;
|
||||
WsfBufFree(pCmacMsg->pPlainText);
|
||||
|
||||
if ((pCb = attcSignCbByConnId((dmConnId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
/* append signature to packet */
|
||||
WStrReverseCpy((uint8_t *) pCb->msg.pPkt +
|
||||
(L2C_PAYLOAD_START + pCb->msg.pPkt->len - ATT_CMAC_RESULT_LEN),
|
||||
pCmacMsg->pCiphertext, ATT_CMAC_RESULT_LEN);
|
||||
|
||||
/* if MTU request in progress or flow controlled */
|
||||
if (pCcb->outReq.hdr.event == ATTC_MSG_API_MTU || pCcb->flowDisabled)
|
||||
{
|
||||
/* put request "on deck" for processing later */
|
||||
pCcb->onDeck = pCb->msg;
|
||||
}
|
||||
/* otherwise ready to send */
|
||||
else
|
||||
{
|
||||
attcSetupReq(pCcb, &pCb->msg);
|
||||
}
|
||||
|
||||
/* we're done-- free control block */
|
||||
attcSignCbFree((dmConnId_t) pMsg->hdr.param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol signed Write Command.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param signCounter Value of the sign counter.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcSignedWriteCmd(dmConnId_t connId, uint16_t handle, uint32_t signCounter,
|
||||
uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* if connection already encrypted with security mode 1 level 2 or higher */
|
||||
if (DmConnSecLevel(connId) > DM_SEC_LEVEL_NONE)
|
||||
{
|
||||
/* use write command instead */
|
||||
AttcWriteCmd(connId, handle, valueLen, pValue);
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_SIGNED_WRITE_CMD_BUF_LEN + valueLen)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_SIGNED_WRITE_CMD_LEN + valueLen;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_SIGNED_WRITE_CMD);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pValue, valueLen);
|
||||
p += valueLen;
|
||||
UINT32_TO_BSTREAM(p, signCounter);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_SIGNED_WRITE_CMD, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATT client for data signing.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcSignInit(void)
|
||||
{
|
||||
/* set up callback interface */
|
||||
attcCb.pSign = &attcSignFcnIf;
|
||||
}
|
||||
Vendored
+189
@@ -0,0 +1,189 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client optional write PDU processing functions.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "attc_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received Prepare Write response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
* \param pEvt Pointer to callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attcProcPrepWriteRsp(attcCcb_t *pCcb, uint16_t len, uint8_t *pPacket, attEvt_t *pEvt)
|
||||
{
|
||||
/* if continuing */
|
||||
if (pCcb->outReq.hdr.status == ATTC_CONTINUING)
|
||||
{
|
||||
/* if no more data to send */
|
||||
if (pCcb->outReqParams.w.len == 0)
|
||||
{
|
||||
/* we're done */
|
||||
pCcb->outReq.hdr.status = ATTC_NOT_CONTINUING;
|
||||
}
|
||||
}
|
||||
|
||||
/* adjust attribute value and its length (adjusted by ATT header length already) */
|
||||
pEvt->pValue += (ATT_PREP_WRITE_RSP_LEN - ATT_HDR_LEN);
|
||||
pEvt->valueLen -= (ATT_PREP_WRITE_RSP_LEN - ATT_HDR_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Write Command.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcWriteCmd(dmConnId_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_WRITE_CMD_BUF_LEN + valueLen)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_WRITE_CMD_LEN + valueLen;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_WRITE_CMD);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pValue, valueLen);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_WRITE_CMD, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Prepare Write Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param offset Write attribute data starting at this offset.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
* \param valueByRef TRUE if pValue data is accessed by reference rather than copied.
|
||||
* \param continuing TRUE if ATTC continues sending requests until complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcPrepareWriteReq(dmConnId_t connId, uint16_t handle, uint16_t offset, uint16_t valueLen,
|
||||
uint8_t *pValue, bool_t valueByRef, bool_t continuing)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
uint16_t bufLen;
|
||||
|
||||
if (continuing && valueByRef)
|
||||
{
|
||||
bufLen = ATT_PREP_WRITE_REQ_BUF_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufLen = ATT_PREP_WRITE_REQ_BUF_LEN + valueLen;
|
||||
}
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(bufLen)) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pPkt->w.len = valueLen;
|
||||
pPkt->w.offset = offset;
|
||||
|
||||
/* build partial packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_PREP_WRITE_REQ);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
/* skip over offset field */
|
||||
p += sizeof(uint16_t);
|
||||
|
||||
/* set value pointer and copy data to packet, if not valueByRef */
|
||||
if (continuing && valueByRef)
|
||||
{
|
||||
pPkt->w.pValue = pValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, pValue, valueLen);
|
||||
pPkt->w.pValue = p;
|
||||
}
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, handle, ATTC_MSG_API_PREP_WRITE, pPkt, continuing);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate an attribute protocol Execute Write Request.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param writeAll TRUE to write all queued writes, FALSE to cancel all queued writes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttcExecuteWriteReq(dmConnId_t connId, bool_t writeAll)
|
||||
{
|
||||
attcPktParam_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate packet and parameter buffer */
|
||||
if ((pPkt = attMsgAlloc(ATT_EXEC_WRITE_REQ_BUF_LEN)) != NULL)
|
||||
{
|
||||
/* set length */
|
||||
pPkt->len = ATT_EXEC_WRITE_REQ_LEN;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *) pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_EXEC_WRITE_REQ);
|
||||
UINT8_TO_BSTREAM(p, writeAll);
|
||||
|
||||
/* send message */
|
||||
attcSendMsg(connId, 0, ATTC_MSG_API_EXEC_WRITE, pPkt, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
+457
@@ -0,0 +1,457 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client characteristic configuration 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t *pCccTbl[DM_CONN_MAX]; /* Pointer to descriptor value tables */
|
||||
attsCccSet_t *pSet; /* Array of CCC descriptor settings */
|
||||
attsCccCback_t cback; /* Client callback function */
|
||||
uint8_t setLen; /* Length of settings array */
|
||||
} AttsCccCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static AttsCccCb_t attsCccCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the client callback function.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param idx Index of descriptor in CCC descriptor handle table.
|
||||
* \param handle Attribute handle of the descriptor.
|
||||
* \param value Attribute value of the descriptor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsCccCback(dmConnId_t connId, uint8_t idx, uint16_t handle, uint16_t value)
|
||||
{
|
||||
attsCccEvt_t evt;
|
||||
|
||||
evt.hdr.event = ATTS_CCC_STATE_IND;
|
||||
evt.hdr.param = connId;
|
||||
evt.idx = idx;
|
||||
evt.handle = handle;
|
||||
evt.value = value;
|
||||
|
||||
(*attsCccCb.cback)(&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate the CCC table for this connection.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return Pointer into the CCC table.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint16_t *attsCccAllocTbl(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
/* if not already allocated */
|
||||
if (attsCccCb.pCccTbl[connId - 1] == NULL)
|
||||
{
|
||||
WSF_ASSERT(attsCccCb.setLen > 0);
|
||||
|
||||
/* allocate new buffer */
|
||||
attsCccCb.pCccTbl[connId - 1] = WsfBufAlloc(attsCccCb.setLen * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
return attsCccCb.pCccTbl[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the pointer into the CCC table for this connection.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return Pointer into the CCC table.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint16_t *attsCccGetTbl(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
return attsCccCb.pCccTbl[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free the CCC table for this connection.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsCccFreeTbl(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
if (attsCccCb.pCccTbl[connId - 1] != NULL)
|
||||
{
|
||||
WsfBufFree(attsCccCb.pCccTbl[connId - 1]);
|
||||
attsCccCb.pCccTbl[connId - 1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the value of a client characteristic configuration descriptor. Note the
|
||||
* value is treated as a little endian byte array.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle of the descriptor.
|
||||
* \param pValue The attribute value of the descriptor is copied to this pointer.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attsCccReadValue(dmConnId_t connId, uint16_t handle, uint8_t *pValue)
|
||||
{
|
||||
attsCccSet_t *pSet;
|
||||
uint16_t *pTbl;
|
||||
uint8_t i;
|
||||
|
||||
/* find handle in handle array */
|
||||
for (pSet = attsCccCb.pSet, i = 0; i < attsCccCb.setLen; i++, pSet++)
|
||||
{
|
||||
if (pSet->handle == handle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if handle not found return error */
|
||||
if (i == attsCccCb.setLen)
|
||||
{
|
||||
return ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* get pointer to the table for this connection */
|
||||
if ((pTbl = attsCccGetTbl(connId)) != NULL)
|
||||
{
|
||||
/* read value */
|
||||
UINT16_TO_BSTREAM(pValue, pTbl[i]);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write the value of a client characteristic configuration descriptor. Note the
|
||||
* value is treated as a little endian byte array.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle of the descriptor.
|
||||
* \param pValue Pointer to the attribute value of the descriptor.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attsCccWriteValue(dmConnId_t connId, uint16_t handle, uint8_t *pValue)
|
||||
{
|
||||
attsCccSet_t *pSet;
|
||||
uint16_t *pTbl;
|
||||
uint8_t i;
|
||||
uint16_t value;
|
||||
uint16_t prevValue;
|
||||
|
||||
/* find handle in handle array */
|
||||
for (pSet = attsCccCb.pSet, i = 0; i < attsCccCb.setLen; i++, pSet++)
|
||||
{
|
||||
if (pSet->handle == handle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if handle not found return error */
|
||||
if (i == attsCccCb.setLen)
|
||||
{
|
||||
return ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
BYTES_TO_UINT16(value, pValue);
|
||||
|
||||
/* verify value range */
|
||||
if (((value != 0) && (value != ATT_CLIENT_CFG_NOTIFY) && (value != ATT_CLIENT_CFG_INDICATE)) ||
|
||||
((value != 0) && ((value & pSet->valueRange) == 0)))
|
||||
{
|
||||
return ATT_ERR_VALUE_RANGE;
|
||||
}
|
||||
|
||||
/* get pointer to the table for this connection */
|
||||
if ((pTbl = attsCccGetTbl(connId)) != NULL)
|
||||
{
|
||||
/* write value */
|
||||
prevValue = pTbl[i];
|
||||
pTbl[i] = value;
|
||||
|
||||
/* if value changed call callback */
|
||||
if (prevValue != value)
|
||||
{
|
||||
attsCccCback(connId, i, handle, value);
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief CCC callback function executed by ATTS and CCC read or write.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param method Read or write.
|
||||
* \param handle Attribute handle of the descriptor.
|
||||
* \param pValue The attribute value of the descriptor is copied to this pointer.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attsCccMainCback(dmConnId_t connId, uint8_t method, uint16_t handle, uint8_t *pValue)
|
||||
{
|
||||
ATT_TRACE_INFO2("attsCccMainCback connId=%d handle=%d", connId, handle);
|
||||
|
||||
if (method == ATT_METHOD_READ)
|
||||
{
|
||||
return attsCccReadValue(connId, handle, pValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return attsCccWriteValue(connId, handle, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register the utility service for managing client characteristic
|
||||
* configuration descriptors. This function is typically called once on
|
||||
* system initialization.
|
||||
*
|
||||
* \param setLen Length of settings array.
|
||||
* \param pSet Array of CCC descriptor settings.
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCccRegister(uint8_t setLen, attsCccSet_t *pSet, attsCccCback_t cback)
|
||||
{
|
||||
attsCccCb.setLen = setLen;
|
||||
attsCccCb.pSet = pSet;
|
||||
attsCccCb.cback = cback;
|
||||
|
||||
attsCb.cccCback = attsCccMainCback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the client characteristic configuration descriptor value table for a
|
||||
* connection. This function is typically called when a connection is established
|
||||
* or when a device is bonded.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCccTbl Pointer to the descriptor value array. The length of the array
|
||||
* must equal the value of setLen passed to AttsCccRegister().
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCccInitTable(dmConnId_t connId, uint16_t *pCccTbl)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t *pTbl;
|
||||
|
||||
ATT_TRACE_INFO1("AttsCccInitTable connId=%d", connId);
|
||||
|
||||
if ((pTbl = attsCccAllocTbl(connId)) != NULL)
|
||||
{
|
||||
/* if initializer table is passed in */
|
||||
if (pCccTbl != NULL)
|
||||
{
|
||||
/* initialize table */
|
||||
for (i = 0; i < attsCccCb.setLen; i++, pCccTbl++, pTbl++)
|
||||
{
|
||||
/* copy value */
|
||||
*pTbl = *pCccTbl;
|
||||
|
||||
/* execute callback for each nonzero entry in table */
|
||||
if (*pCccTbl != 0)
|
||||
{
|
||||
attsCccCback(connId, i, ATT_HANDLE_NONE, *pCccTbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initialize table to zero */
|
||||
memset(pTbl, 0, (sizeof(uint16_t) * attsCccCb.setLen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear and deallocate the client characteristic configuration descriptor value
|
||||
* table for a connection. This function must be called when a connection is closed.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCccClearTable(dmConnId_t connId)
|
||||
{
|
||||
ATT_TRACE_INFO1("AttsCccClearTable connId=%d", connId);
|
||||
|
||||
attsCccFreeTbl(connId);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the value of a client characteristic configuration descriptor by its index.
|
||||
* If not found, return zero.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param idx Index of descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return Value of the descriptor.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t AttsCccGet(dmConnId_t connId, uint8_t idx)
|
||||
{
|
||||
uint16_t *pTbl;
|
||||
|
||||
WSF_ASSERT(idx < attsCccCb.setLen);
|
||||
|
||||
if ((pTbl = attsCccGetTbl(connId)) != NULL)
|
||||
{
|
||||
/* return value from table */
|
||||
return pTbl[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the value of a client characteristic configuration descriptor by its index.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param idx Index of descriptor in CCC descriptor handle table.
|
||||
* \param value Value of the descriptor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCccSet(dmConnId_t connId, uint8_t idx, uint16_t value)
|
||||
{
|
||||
uint16_t *pTbl;
|
||||
|
||||
WSF_ASSERT(idx < attsCccCb.setLen);
|
||||
|
||||
if ((pTbl = attsCccGetTbl(connId)) != NULL)
|
||||
{
|
||||
pTbl[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a client characteristic configuration descriptor is enabled and if
|
||||
* the characteristic's security level has been met.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param idx Index of descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return Value of the descriptor if security level is met, otherwise zero.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t AttsCccEnabled(dmConnId_t connId, uint8_t idx)
|
||||
{
|
||||
WSF_ASSERT(idx < attsCccCb.setLen);
|
||||
|
||||
/* check security level */
|
||||
if (DmConnSecLevel(connId) < attsCccCb.pSet[idx].secLevel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get value */
|
||||
return AttsCccGet(connId, idx);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get number of CCC entries in table.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return Number of CCC entries in table.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttsGetCccTableLen(void)
|
||||
{
|
||||
return attsCccCb.setLen;
|
||||
}
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT client supported features module.
|
||||
*
|
||||
* Copyright (c) 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_trace.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_core.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
attsCsfCb_t attsCsfCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set status of on-going database hash update operation.
|
||||
*
|
||||
* \param isUpdating \ref TRUE is updating, otherwise \ref FALSE;
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsCsfSetHashUpdateStatus(bool_t isUpdating)
|
||||
{
|
||||
if (attsCsfCb.isHashUpdating == isUpdating)
|
||||
{
|
||||
/* Already in the current state, nothing to do. */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update state. */
|
||||
attsCsfCb.isHashUpdating = isUpdating;
|
||||
}
|
||||
|
||||
/* Update complete.
|
||||
* Check if clients were pending on the hash value and fulfill their requests.
|
||||
*/
|
||||
if (isUpdating == FALSE)
|
||||
{
|
||||
ATT_TRACE_INFO0("Database hash calculation complete");
|
||||
|
||||
attsCheckPendDbHashReadRsp();
|
||||
|
||||
/* Note: Clients which were pending on a Database Hash read from a Read by Type Request are not
|
||||
* transitioned to the change-aware state here. The application is expected to initiate the
|
||||
* state transition of all clients when the new hash is set. If this is not done, the
|
||||
* state of pending Clients will be out of sync, and will be corrected on the next database
|
||||
* sync.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_INFO0("Calculating database hash");
|
||||
|
||||
/* If the application, for whatever reason, previously recalculated the database hash over an
|
||||
* unchanged database and a client pended on a Read By Type Request of the database hash, then
|
||||
* that clients state may be out of step if the application did not initiate a state
|
||||
* transition. That state transition is forced here to keep handle next transition.
|
||||
*/
|
||||
for (uint8_t i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
if (attsCsfCb.attsCsfTable[i].changeAwareState == ATTS_CLIENT_CHANGE_AWARE_DB_READ_PENDING)
|
||||
{
|
||||
attsCsfCb.attsCsfTable[i].changeAwareState = ATTS_CLIENT_CHANGE_PENDING_AWARE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if database hash update is in progress.
|
||||
*
|
||||
* \return \ref TRUE if update in progress, \ref FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t attsCsfGetHashUpdateStatus(void)
|
||||
{
|
||||
return attsCsfCb.isHashUpdating;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check client awareness to database hash before sending notification or indication.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle ATT handle.
|
||||
*
|
||||
* \return \ref TRUE if client is aware, otherwise \ref FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t attsCsfIsClientChangeAware(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
if ((attsCsfCb.attsCsfTable[connId - 1].csf & ATTS_CSF_ROBUST_CACHING) &&
|
||||
(attsCsfCb.attsCsfTable[connId - 1].changeAwareState == ATTS_CLIENT_CHANGE_UNAWARE) &&
|
||||
(handle != GATT_SC_HDL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update client change-aware state based on protocol event.
|
||||
*
|
||||
* \param connId Connection handle.
|
||||
* \param opcode ATT PDU type.
|
||||
* \param pPacket Data packet from L2CAP.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if client is change-aware, else \ref ATT_ERR_DATABASE_OUT_OF_SYNC.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t attsCsfActClientState(uint16_t handle, uint8_t opcode, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
attsCsfRec_t *pRec;
|
||||
|
||||
/* PDU which do not operate on att handles are handled agnostically of the client's state. */
|
||||
if (opcode == ATT_PDU_MTU_REQ || opcode == ATT_PDU_VALUE_CNF)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
pRec = &attsCsfCb.attsCsfTable[handle];
|
||||
|
||||
/* If the client is change-unaware */
|
||||
if (pRec->changeAwareState == ATTS_CLIENT_CHANGE_UNAWARE)
|
||||
{
|
||||
/* If not a command */
|
||||
if ((opcode & ATT_PDU_MASK_COMMAND) == 0)
|
||||
{
|
||||
/* Note: there is no need to call back to the application here. The application only
|
||||
* needs to know when a transition to or from the change-aware state occurs.
|
||||
*/
|
||||
|
||||
/* Move client change-aware state to pending */
|
||||
pRec->changeAwareState = ATTS_CLIENT_CHANGE_PENDING_AWARE;
|
||||
|
||||
ATT_TRACE_INFO2("ConnId %d change aware state is %d", handle + 1,
|
||||
ATTS_CLIENT_CHANGE_PENDING_AWARE);
|
||||
}
|
||||
|
||||
/* If this is a command or the Client has indicated Robust Caching, set an error so that
|
||||
* this command or request is not processed.
|
||||
*/
|
||||
if ((opcode & ATT_PDU_MASK_COMMAND) ||
|
||||
(pRec->csf & ATTS_CSF_ROBUST_CACHING))
|
||||
{
|
||||
/* return a database out of sync error */
|
||||
err = ATT_ERR_DATABASE_OUT_OF_SYNC;
|
||||
}
|
||||
}
|
||||
else if (pRec->changeAwareState == ATTS_CLIENT_CHANGE_PENDING_AWARE)
|
||||
{
|
||||
/* If not a command */
|
||||
if ((opcode & ATT_PDU_MASK_COMMAND) == 0)
|
||||
{
|
||||
/* Move client change-aware state to aware */
|
||||
pRec->changeAwareState = ATTS_CLIENT_CHANGE_AWARE;
|
||||
|
||||
ATT_TRACE_INFO2("ConnId %d change aware state is %d", handle + 1, ATTS_CLIENT_CHANGE_AWARE);
|
||||
|
||||
/* Callback to application to store updated awareness, if bonded. */
|
||||
if (attsCsfCb.writeCback != NULL)
|
||||
{
|
||||
attsCsfCb.writeCback(handle + 1, pRec->changeAwareState, &pRec->csf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return an error so that command is not processed. */
|
||||
err = ATT_ERR_DATABASE_OUT_OF_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is Read by Type request */
|
||||
if (opcode == ATT_PDU_READ_TYPE_REQ)
|
||||
{
|
||||
uint16_t uuid;
|
||||
|
||||
/* Extract UUID: Skip L2C, ATT Header and 4 byte handle range */
|
||||
BYTES_TO_UINT16(uuid, (pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN + 4));
|
||||
|
||||
/* If this is a Read By Type Request of the Database Hash characteristic value */
|
||||
if (uuid == ATT_UUID_DATABASE_HASH)
|
||||
{
|
||||
err = ATT_SUCCESS;
|
||||
|
||||
/* Reading the hash during a hash update causes the new hash to be returned and counts
|
||||
* towards the peer's progression towards a change-aware state.
|
||||
*/
|
||||
if (attsCsfCb.isHashUpdating)
|
||||
{
|
||||
/* This read will not be processed until after the hash update completes, so this read
|
||||
* request shall be counted as a move from change-unaware to chang-aware pending.
|
||||
*/
|
||||
pRec->changeAwareState = ATTS_CLIENT_CHANGE_AWARE_DB_READ_PENDING;
|
||||
|
||||
ATT_TRACE_INFO2("ConnId %d change aware state is %d", handle + 1,
|
||||
ATTS_CLIENT_CHANGE_AWARE_DB_READ_PENDING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ATT_ERR_DATABASE_OUT_OF_SYNC)
|
||||
{
|
||||
ATT_TRACE_INFO2("ConnId %d out of sync, PDU with opcode 0x%02x ignored!", handle + 1, opcode);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update a client's state of awareness to a change in the database.
|
||||
*
|
||||
* \param connId DM connection ID. if \ref DM_CONN_ID_NONE, sets the state for all connected
|
||||
* clients.
|
||||
* \param state The state of awareness to a change, see ::attClientAwareStates.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note A callback to application is not needed as it is expected the caller (i.e. the
|
||||
* application) will have updated all persistent records prior to calling this function.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCsfSetClientsChangeAwarenessState(dmConnId_t connId, uint8_t state)
|
||||
{
|
||||
if (connId == DM_CONN_ID_NONE)
|
||||
{
|
||||
for (uint8_t i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
if (attsCsfCb.attsCsfTable[i].changeAwareState == ATTS_CLIENT_CHANGE_AWARE_DB_READ_PENDING)
|
||||
{
|
||||
attsCsfCb.attsCsfTable[i].changeAwareState = ATTS_CLIENT_CHANGE_PENDING_AWARE;
|
||||
}
|
||||
else
|
||||
{
|
||||
attsCsfCb.attsCsfTable[i].changeAwareState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attsCsfCb.attsCsfTable[connId - 1].changeAwareState = state;
|
||||
|
||||
ATT_TRACE_INFO2("ConnId %d change aware state is %d", connId, state);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the client supported features for a connection.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param changeAwareState The state of awareness to a change in the database.
|
||||
* \param pCsf Pointer to the client supported features value to cache. \ref NULL or
|
||||
* buffer of length \ref ATT_CSF_LEN.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCsfConnOpen(dmConnId_t connId, uint8_t changeAwareState, uint8_t *pCsf)
|
||||
{
|
||||
if (pCsf != NULL)
|
||||
{
|
||||
attsCsfCb.attsCsfTable[connId - 1].changeAwareState = changeAwareState;
|
||||
memcpy(&attsCsfCb.attsCsfTable[connId - 1].csf, pCsf, ATT_CSF_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note: this set client to the change-aware state. */
|
||||
memset(&attsCsfCb.attsCsfTable[connId - 1], 0, sizeof(attsCsfRec_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register callback.
|
||||
*
|
||||
* \param writeCback Application callback for when features or status change.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCsfRegister(attsCsfWriteCback_t writeCback)
|
||||
{
|
||||
attsCsfCb.writeCback = writeCback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATTS client supported features module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCsfInit(void)
|
||||
{
|
||||
attsCsfCb.isHashUpdating = FALSE;
|
||||
attsCsfCb.writeCback = NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief GATT write of client supported feature characteristic value.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param offset offset into csf characteristic.
|
||||
* \param valueLen length of write in bytes.
|
||||
* \param pValue Pointer to client's supported features characteristic value.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS is successful, \ref ATT_ERR_VALUE_NOT_ALLOWED if any supported
|
||||
* features are flipped from 1 to 0.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttsCsfWriteFeatures(dmConnId_t connId, uint16_t offset, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attsCsfRec_t *pCsfRec = &attsCsfCb.attsCsfTable[connId - 1];
|
||||
|
||||
/* future parameter in case the client supported features characteristic becomes a multi-octet
|
||||
* structure.
|
||||
*/
|
||||
(void)offset;
|
||||
|
||||
if (valueLen > ATT_CSF_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* A client can not clear any bits it has set. */
|
||||
if ((pCsfRec->csf & *pValue) < pCsfRec->csf)
|
||||
{
|
||||
return ATT_ERR_VALUE_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
pCsfRec->csf = *pValue & ATTS_CSF_OCT0_FEATURES;
|
||||
|
||||
ATT_TRACE_INFO2("connId %d updated csf to 0x%02x", connId, pCsfRec->csf);
|
||||
|
||||
/* Callback to application to store updated features, if bonded. */
|
||||
if (attsCsfCb.writeCback != NULL)
|
||||
{
|
||||
attsCsfCb.writeCback(connId, pCsfRec->changeAwareState, &pCsfRec->csf);
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get client supported feature record.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCsfOut Output parameter for client supported features buffer.
|
||||
* \param pCsfOutLen Length of output parameter buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCsfGetFeatures(dmConnId_t connId, uint8_t *pCsfOut, uint8_t pCsfOutLen)
|
||||
{
|
||||
if (pCsfOutLen <= ATT_CSF_LEN)
|
||||
{
|
||||
memcpy(pCsfOut, &attsCsfCb.attsCsfTable[connId - 1].csf, pCsfOutLen);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get client state of awareness to a change in the database.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return Client's change-aware state.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttsCsfGetChangeAwareState(dmConnId_t connId)
|
||||
{
|
||||
return attsCsfCb.attsCsfTable[connId - 1].changeAwareState;
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Dynamic ATT services and attributes.
|
||||
*
|
||||
* Copyright (c) 2017-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_trace.h"
|
||||
#include "wsf_math.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Configurable number of bytes in the Dynamic Service and Attribute Heap */
|
||||
#ifndef ATTS_DYN_HEAP_SIZE
|
||||
#define ATTS_DYN_HEAP_SIZE 1280
|
||||
#endif
|
||||
|
||||
/* Configurable memory byte alignment Dynamic Service and Attribute Heap */
|
||||
#ifndef ATTS_DYN_ALIGNMENT
|
||||
#define ATTS_DYN_ALIGNMENT 4
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Dynamic service and attributes control block */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t numServices;
|
||||
uint8_t *pNextBuffer;
|
||||
} attsDynCb_t;
|
||||
|
||||
/* Dynamic service group control block */
|
||||
typedef struct
|
||||
{
|
||||
attsGroup_t group;
|
||||
uint16_t currentAttr;
|
||||
} attsDynGroupCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Dynamic Service and Attribute Heap */
|
||||
static uint8_t attsDynHeap[ATTS_DYN_HEAP_SIZE];
|
||||
|
||||
/* Dynamic Service and Attribute control block */
|
||||
static attsDynCb_t attsDynCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate memory from the Dynamic Service and Attribute Heap.
|
||||
*
|
||||
* \param size Size of buffer to allocate in bytes
|
||||
*
|
||||
* \return Allocated buffer or NULL if failed to allocate a buffer.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void *attsDynAlloc(uint16_t size)
|
||||
{
|
||||
uint8_t *pMem = attsDynCb.pNextBuffer;
|
||||
|
||||
/* Verify enough space in heap for buffer */
|
||||
if (pMem + size <= attsDynHeap + ATTS_DYN_HEAP_SIZE)
|
||||
{
|
||||
#if ATTS_DYN_ALIGNMENT > 1
|
||||
/* Increase size if size not a multiple of the memory alignment */
|
||||
if (size % ATTS_DYN_ALIGNMENT)
|
||||
{
|
||||
size += ATTS_DYN_ALIGNMENT - (size % ATTS_DYN_ALIGNMENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the next buffer location */
|
||||
attsDynCb.pNextBuffer += size;
|
||||
|
||||
return pMem;
|
||||
}
|
||||
|
||||
/* Out of heap */
|
||||
WSF_ASSERT(FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Dynamic ATT Service subsystem.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsDynInit()
|
||||
{
|
||||
attsDynCb.numServices = 0;
|
||||
attsDynCb.pNextBuffer = attsDynHeap;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Dynamically create an ATT Service at runtime.
|
||||
*
|
||||
* \param startHandle Starting attribute handle in the service
|
||||
* \param endHandle Last attribute handle in the service
|
||||
*
|
||||
* \return Service Handle.
|
||||
*
|
||||
* \note It is recommended this function only be used when no connections are open and the
|
||||
* device is not in a connectable mode.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void *AttsDynCreateGroup(uint16_t startHandle, uint16_t endHandle)
|
||||
{
|
||||
attsDynGroupCb_t *pGroup = NULL;
|
||||
|
||||
/* Allocate memory for the service control block */
|
||||
pGroup = attsDynAlloc(sizeof(attsDynGroupCb_t));
|
||||
WSF_ASSERT(pGroup);
|
||||
|
||||
if (pGroup != NULL)
|
||||
{
|
||||
|
||||
/* Initialize the service group */
|
||||
pGroup->group.startHandle = startHandle;
|
||||
pGroup->group.endHandle = endHandle;
|
||||
pGroup->group.readCback = NULL;
|
||||
pGroup->group.writeCback = NULL;
|
||||
|
||||
/* Allocate memory for the attributes */
|
||||
pGroup->group.pAttr = attsDynAlloc(sizeof(attsAttr_t) * (endHandle - startHandle + 1));
|
||||
WSF_ASSERT(pGroup->group.pAttr);
|
||||
|
||||
pGroup->currentAttr = 0;
|
||||
attsDynCb.numServices++;
|
||||
}
|
||||
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Dynamically delete an ATT Service at runtime.
|
||||
*
|
||||
* \param pSvcHandle Service handle returned by AttsDynCreateGroup
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note It is recommended this function only be used when no connections are open and the
|
||||
* device is not in a connectable mode.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsDynDeleteGroup(void *pSvcHandle)
|
||||
{
|
||||
attsDynGroupCb_t *pGroup = pSvcHandle;
|
||||
|
||||
WSF_ASSERT(attsDynCb.numServices);
|
||||
WSF_ASSERT(pGroup);
|
||||
|
||||
/* Remove the group */
|
||||
AttsRemoveGroup(pGroup->group.startHandle);
|
||||
|
||||
attsDynCb.numServices--;
|
||||
|
||||
/* If there are no more dynamic groups, initialize the subsystem to free the memory in the heap */
|
||||
if (attsDynCb.numServices == 0)
|
||||
{
|
||||
AttsDynInit();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register callback functions for a dynamic ATT Service at runtime.
|
||||
*
|
||||
* \param pSvcHandle Service handle returned by AttsDynCreateGroup
|
||||
* \param readCback Read callback function.
|
||||
* \param writeCback Write callback function.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note It is recommended this function only be used when no connections are open and the
|
||||
* device is not in a connectable mode.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsDynRegister(void *pSvcHandle, attsReadCback_t readCback, attsWriteCback_t writeCback)
|
||||
{
|
||||
attsDynGroupCb_t *pGroup = pSvcHandle;
|
||||
|
||||
WSF_ASSERT(pGroup);
|
||||
|
||||
pGroup->group.readCback = readCback;
|
||||
pGroup->group.writeCback = writeCback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Dynamically add an attribute to a dynamic ATT Services at app initialization.
|
||||
*
|
||||
* \param pSvcHandle Service handle returned by AttsDynCreateGroup
|
||||
* \param pUuid Constant UUID
|
||||
* \param pValue Initial value of attribute (copied into attribute memory)
|
||||
* \param len Length of pValue in bytes
|
||||
* \param maxLen Maximum length of the attribute in bytes
|
||||
* \param settings Attribute settings
|
||||
* \param permissions Attribute permissions
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note It is recommended this function only be used when no connections are open and the
|
||||
* device is not in a connectable mode.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsDynAddAttr(void *pSvcHandle, const uint8_t *pUuid, const uint8_t *pValue, uint16_t len,
|
||||
const uint16_t maxLen, uint8_t settings, uint8_t permissions)
|
||||
{
|
||||
attsAttr_t *pAttr;
|
||||
attsDynGroupCb_t *pGroup = pSvcHandle;
|
||||
uint16_t handle = pGroup->group.startHandle + pGroup->currentAttr++;
|
||||
|
||||
/* Verify inputs */
|
||||
WSF_ASSERT(handle <= pGroup->group.endHandle);
|
||||
WSF_ASSERT(pUuid);
|
||||
WSF_ASSERT(len <= maxLen);
|
||||
|
||||
pAttr = pGroup->group.pAttr + (handle - pGroup->group.startHandle);
|
||||
|
||||
|
||||
/* Allocate a buffer for the length of the attribute */
|
||||
pAttr->pLen = attsDynAlloc(sizeof(uint16_t));
|
||||
WSF_ASSERT(pAttr->pLen);
|
||||
|
||||
if (pAttr->pLen == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate a buffer for the value of the attribute */
|
||||
pAttr->pValue = attsDynAlloc(maxLen);
|
||||
WSF_ASSERT(pAttr->pValue);
|
||||
|
||||
if (pAttr->pValue == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the attribute values */
|
||||
pAttr->pUuid = pUuid;
|
||||
pAttr->maxLen = maxLen;
|
||||
pAttr->settings = settings;
|
||||
pAttr->permissions = permissions;
|
||||
|
||||
|
||||
|
||||
if (pValue)
|
||||
{
|
||||
/* Copy the initial value */
|
||||
memcpy(pAttr->pValue, pValue, len);
|
||||
*pAttr->pLen = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No initial value, zero value and length */
|
||||
memset(pAttr->pValue, 0, maxLen);
|
||||
*pAttr->pLen = 0;
|
||||
}
|
||||
|
||||
/* Add the service when the last attribute has been added */
|
||||
if (handle == pGroup->group.endHandle)
|
||||
{
|
||||
AttsAddGroup(&pGroup->group);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Dynamically add an attribute with a constant value to a dynamic ATT Services.
|
||||
*
|
||||
* \param pSvcHandle Service handle returned by AttsDynCreateGroup
|
||||
* \param pUuid Constant UUID
|
||||
* \param pValue Pointer to constant attribute memory
|
||||
* \param len Length of pValue in bytes
|
||||
* \param settings Attribute settings
|
||||
* \param permissions Attribute permissions
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note It is recommended this function only be used when no connections are open and the
|
||||
* device is not in a connectable mode.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsDynAddAttrConst(void *pSvcHandle, const uint8_t *pUuid, const uint8_t *pValue,
|
||||
const uint16_t len, uint8_t settings, uint8_t permissions)
|
||||
{
|
||||
attsAttr_t *pAttr;
|
||||
attsDynGroupCb_t *pGroup = pSvcHandle;
|
||||
uint16_t handle = pGroup->group.startHandle + pGroup->currentAttr++;
|
||||
|
||||
/* Verify inputs */
|
||||
WSF_ASSERT(handle <= pGroup->group.endHandle);
|
||||
WSF_ASSERT(pValue);
|
||||
WSF_ASSERT(pUuid);
|
||||
|
||||
pAttr = pGroup->group.pAttr + (handle - pGroup->group.startHandle);
|
||||
|
||||
/* Allocate a buffer for the length of the attribute */
|
||||
pAttr->pLen = attsDynAlloc(sizeof(uint16_t));
|
||||
WSF_ASSERT(pAttr->pLen);
|
||||
|
||||
if (pAttr->pLen == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the attribute values */
|
||||
*pAttr->pLen = len;
|
||||
pAttr->pUuid = pUuid;
|
||||
pAttr->pValue = (uint8_t *) pValue;
|
||||
pAttr->maxLen = len;
|
||||
pAttr->settings = settings;
|
||||
pAttr->permissions = permissions;
|
||||
|
||||
/* Add the service when the last attribute has been added */
|
||||
if (handle == pGroup->group.endHandle)
|
||||
{
|
||||
AttsAddGroup(&pGroup->group);
|
||||
}
|
||||
}
|
||||
+654
@@ -0,0 +1,654 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server indication and notification functions.
|
||||
*
|
||||
* 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_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
static void attsIndConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt);
|
||||
static void attsIndMsgCback(attsApiMsg_t *pMsg);
|
||||
static void attsIndCtrlCback(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Interface to ATT */
|
||||
static const attFcnIf_t attsIndFcnIf =
|
||||
{
|
||||
attEmptyDataCback,
|
||||
attsIndCtrlCback,
|
||||
(attMsgHandler_t) attsIndMsgCback,
|
||||
attsIndConnCback
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
attsIndCb_t attsIndCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the ATTS connection control block connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to connection control block or NULL if not in use.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static attsIndCcb_t *attsIndCcbByConnId(dmConnId_t connId)
|
||||
{
|
||||
if (DmConnInUse(connId))
|
||||
{
|
||||
return &attsIndCb.ccb[connId - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN1("atts ccb not in use: %d", connId);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if application callback is pending for indication or a given notification, or
|
||||
* the maximum number of simultaneous notifications has been reached.
|
||||
*
|
||||
* \param pCcb ATTS ind control block.
|
||||
* \param pPkt Pointer to packet.
|
||||
*
|
||||
* \return TRUE if app callback's pending or max number of simultaneous notifications reached.
|
||||
* FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t attsPendIndNtfHandle(attsIndCcb_t *pCcb, attsPktParam_t *pPkt)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t pendNtfs;
|
||||
uint8_t i;
|
||||
|
||||
/* extract opcode */
|
||||
opcode = *(((uint8_t *) pPkt) + L2C_PAYLOAD_START);
|
||||
|
||||
/* if indication */
|
||||
if (opcode == ATT_PDU_VALUE_IND)
|
||||
{
|
||||
/* see if callback pending for indication */
|
||||
return (pCcb->pendIndHandle == ATT_HANDLE_NONE) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/* initialize number of notification callbacks pending */
|
||||
pendNtfs = 0;
|
||||
|
||||
for (i = 0; i < ATT_NUM_SIMUL_NTF; i++)
|
||||
{
|
||||
/* if callback pending for notification */
|
||||
if (pCcb->pendNtfHandle[i] != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* if callback pending for this handle */
|
||||
if (pCcb->pendNtfHandle[i] == pPkt->handle)
|
||||
{
|
||||
/* callback pending for this notification */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pendNtfs++;
|
||||
}
|
||||
}
|
||||
|
||||
/* no callback is pending for this notification but see if the maximum number of simultaneous
|
||||
notifications has been reached */
|
||||
return (pendNtfs < ATT_NUM_SIMUL_NTF) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set pending notification callback for a given handle.
|
||||
*
|
||||
* \param pCcb ATTS ind control block.
|
||||
* \param handle Notification handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsSetPendNtfHandle(attsIndCcb_t *pCcb, uint16_t handle)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ATT_NUM_SIMUL_NTF; i++)
|
||||
{
|
||||
/* if entry free */
|
||||
if (pCcb->pendNtfHandle[i] == ATT_HANDLE_NONE)
|
||||
{
|
||||
/* set pending notification handle */
|
||||
pCcb->pendNtfHandle[i] = handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute application callback function with confirmation event.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param status Callback event status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsExecCallback(dmConnId_t connId, uint16_t handle, uint8_t status)
|
||||
{
|
||||
attExecCallback(connId, ATTS_HANDLE_VALUE_CNF, handle, status, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Call pending indication or/and notification(s) application callback.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCcb ATTS ind control block.
|
||||
* \param status Callback event status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsIndNtfCallback(dmConnId_t connId, attsIndCcb_t *pCcb, uint8_t status)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if pending indication callback */
|
||||
if (pCcb->pendIndHandle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* call indication callback with status */
|
||||
attsExecCallback(connId, pCcb->pendIndHandle, status);
|
||||
pCcb->pendIndHandle = ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
/* if any pending notification callback */
|
||||
for (i = 0; i < ATT_NUM_SIMUL_NTF; i++)
|
||||
{
|
||||
if (pCcb->pendNtfHandle[i] != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* call notification callback with status */
|
||||
attsExecCallback(connId, pCcb->pendNtfHandle[i], status);
|
||||
pCcb->pendNtfHandle[i] = ATT_HANDLE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set up and send an attribute server indication or notification.
|
||||
*
|
||||
* \param pCcb ATTS ind control block.
|
||||
* \param connId DM connection ID.
|
||||
* \param pPkt Pointer to packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsSetupMsg(attsIndCcb_t *pCcb, dmConnId_t connId, attsPktParam_t *pPkt)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint16_t handle;
|
||||
|
||||
/* extract opcode */
|
||||
opcode = *(((uint8_t *) pPkt) + L2C_PAYLOAD_START);
|
||||
|
||||
/* copy handle (it may be overwritten in pPkt) */
|
||||
handle = pPkt->handle;
|
||||
|
||||
/* send pdu */
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->pMainCcb->handle, pPkt->len, (uint8_t *) pPkt);
|
||||
|
||||
/* if indication store handle and start timer */
|
||||
if (opcode == ATT_PDU_VALUE_IND)
|
||||
{
|
||||
pCcb->outIndHandle = pCcb->pendIndHandle = handle;
|
||||
pCcb->outIndTimer.msg.event = ATTS_MSG_IND_TIMEOUT;
|
||||
WsfTimerStartSec(&pCcb->outIndTimer, pAttCfg->transTimeout);
|
||||
}
|
||||
/* else if a notification and flow not disabled call callback now */
|
||||
else if (!(pCcb->pMainCcb->control & ATT_CCB_STATUS_FLOW_DISABLED))
|
||||
{
|
||||
attsExecCallback(connId, handle, ATT_SUCCESS);
|
||||
}
|
||||
/* else set pending notification callback for this handle */
|
||||
else
|
||||
{
|
||||
attsSetPendNtfHandle(pCcb, handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection callback for ATTS indications/notifications.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsIndConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt)
|
||||
{
|
||||
attsIndCcb_t *pIndCcb;
|
||||
uint8_t status;
|
||||
|
||||
/* if connection opened */
|
||||
if (pDmEvt->hdr.event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
|
||||
}
|
||||
/* if connection closed */
|
||||
else if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* set status */
|
||||
if (pDmEvt->connClose.hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
status = pDmEvt->connClose.reason + ATT_HCI_ERR_BASE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = pDmEvt->connClose.hdr.status + ATT_HCI_ERR_BASE;
|
||||
}
|
||||
|
||||
/* get server control block directly */
|
||||
pIndCcb = &attsIndCb.ccb[pCcb->connId - 1];
|
||||
|
||||
/* if outstanding indication */
|
||||
if (pIndCcb->outIndHandle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* stop timer */
|
||||
WsfTimerStop(&pIndCcb->outIndTimer);
|
||||
pIndCcb->outIndHandle = ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
/* call pending indication and notification callback */
|
||||
attsIndNtfCallback(pCcb->connId, pIndCcb, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF message handler callback for ATTS indications/notifications.
|
||||
*
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsIndMsgCback(attsApiMsg_t *pMsg)
|
||||
{
|
||||
attsIndCcb_t *pCcb;
|
||||
|
||||
/* get CCB and verify connection still in use */
|
||||
if ((pCcb = attsIndCcbByConnId((dmConnId_t) pMsg->hdr.param)) == NULL)
|
||||
{
|
||||
/* if message has a packet buffer free packet buffer */
|
||||
if (pMsg->hdr.event == ATTS_MSG_API_VALUE_IND_NTF)
|
||||
{
|
||||
WsfMsgFree(pMsg->pPkt);
|
||||
}
|
||||
|
||||
/* ignore if connection not in use */
|
||||
return;
|
||||
}
|
||||
|
||||
/* if an API message to send packet */
|
||||
if (pMsg->hdr.event == ATTS_MSG_API_VALUE_IND_NTF)
|
||||
{
|
||||
/* verify no API message already pending */
|
||||
if (attsPendIndNtfHandle(pCcb, pMsg->pPkt))
|
||||
{
|
||||
/* call callback with failure status and free packet buffer */
|
||||
attsExecCallback((dmConnId_t) pMsg->hdr.param, pMsg->pPkt->handle, ATT_ERR_OVERFLOW);
|
||||
WsfMsgFree(pMsg->pPkt);
|
||||
}
|
||||
/* otherwise ready to send; set up request */
|
||||
else
|
||||
{
|
||||
attsSetupMsg(pCcb, (dmConnId_t) pMsg->hdr.param, pMsg->pPkt);
|
||||
}
|
||||
}
|
||||
/* else if indication timeout */
|
||||
else if (pMsg->hdr.event == ATTS_MSG_IND_TIMEOUT)
|
||||
{
|
||||
/* if outstanding indication */
|
||||
if (pCcb->outIndHandle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* clear out handle */
|
||||
pCcb->outIndHandle = ATT_HANDLE_NONE;
|
||||
|
||||
/* call callback with timeout error */
|
||||
attsExecCallback((dmConnId_t) pMsg->hdr.param, pCcb->pendIndHandle, ATT_ERR_TIMEOUT);
|
||||
pCcb->pendIndHandle = ATT_HANDLE_NONE;
|
||||
pCcb->pMainCcb->control |= ATT_CCB_STATUS_TX_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2CAP control callback.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsIndCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
attsIndCcb_t *pCcb;
|
||||
|
||||
/* note this function is currently only called when flow is enabled */
|
||||
|
||||
/* get CCB */
|
||||
if ((pCcb = attsIndCcbByConnId((dmConnId_t) pMsg->param)) != NULL)
|
||||
{
|
||||
/* call pending indication and notification callback */
|
||||
attsIndNtfCallback((dmConnId_t) pMsg->param, pCcb, ATT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol Handle Value Indication or Notification.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
* \param opcode Opcode for notification or indication.
|
||||
* \param zeroCpy Whether or not to copy attribute value data into new buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsHandleValueIndNtf(dmConnId_t connId, uint16_t handle, uint16_t valueLen,
|
||||
uint8_t *pValue, uint8_t opcode, bool_t zeroCpy)
|
||||
{
|
||||
attsIndCcb_t *pCcb;
|
||||
uint16_t mtu;
|
||||
bool_t transTimedOut;
|
||||
bool_t pktSent = FALSE;
|
||||
|
||||
WsfTaskLock();
|
||||
|
||||
/* get CCB and verify connection still in use */
|
||||
if ((pCcb = attsIndCcbByConnId(connId)) != NULL)
|
||||
{
|
||||
/* get MTU size */
|
||||
mtu = pCcb->pMainCcb->mtu;
|
||||
transTimedOut = !!(pCcb->pMainCcb->control & ATT_CCB_STATUS_TX_TIMEOUT);
|
||||
}
|
||||
/* else connection not in use */
|
||||
else
|
||||
{
|
||||
/* MTU size unknown */
|
||||
mtu = 0;
|
||||
transTimedOut = FALSE;
|
||||
}
|
||||
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if MTU size known for connection */
|
||||
if (mtu > 0)
|
||||
{
|
||||
/* if no transaction's timed out */
|
||||
if (!transTimedOut)
|
||||
{
|
||||
/* Only send notifications and indications if client is aware of any database changes. */
|
||||
if (attsCsfIsClientChangeAware(connId, handle))
|
||||
{
|
||||
/* if packet length is less than or equal to negotiated MTU */
|
||||
if ((valueLen + ATT_VALUE_NTF_LEN) <= mtu)
|
||||
{
|
||||
attsApiMsg_t *pMsg;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate message buffer */
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(attsApiMsg_t))) != NULL)
|
||||
{
|
||||
/* set parameters */
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->hdr.event = ATTS_MSG_API_VALUE_IND_NTF;
|
||||
|
||||
if (zeroCpy)
|
||||
{
|
||||
/* use packet buffer provided */
|
||||
pMsg->pPkt = (attsPktParam_t *)(pValue - ATT_VALUE_IND_NTF_BUF_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allocate packet buffer */
|
||||
pMsg->pPkt = attMsgAlloc(ATT_VALUE_IND_NTF_BUF_LEN + valueLen);
|
||||
}
|
||||
|
||||
if (pMsg->pPkt != NULL)
|
||||
{
|
||||
/* set data length and handle (ind and ntf have same header length) */
|
||||
pMsg->pPkt->len = ATT_VALUE_IND_LEN + valueLen;
|
||||
pMsg->pPkt->handle = handle;
|
||||
|
||||
/* build packet */
|
||||
p = (uint8_t *)pMsg->pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, opcode);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
if (!zeroCpy)
|
||||
{
|
||||
memcpy(p, pValue, valueLen);
|
||||
}
|
||||
|
||||
/* send message */
|
||||
WsfMsgSend(attCb.handlerId, pMsg);
|
||||
pktSent = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* free message buffer if packet buffer alloc failed */
|
||||
WsfMsgFree(pMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* packet length exceeds MTU size */
|
||||
else
|
||||
{
|
||||
/* call callback with failure status */
|
||||
attsExecCallback(connId, handle, ATT_ERR_MTU_EXCEEDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
/* transaction's timed out */
|
||||
{
|
||||
/* call callback with failure status */
|
||||
attsExecCallback(connId, handle, ATT_ERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* if packet wasn't sent and it's a zero-copy packet */
|
||||
if (!pktSent && zeroCpy)
|
||||
{
|
||||
/* free packet buffer provided */
|
||||
AttMsgFree(pValue, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received handle value confirm packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcValueCnf(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
attsIndCcb_t *pIndCcb;
|
||||
|
||||
/* get server indication CCB */
|
||||
if ((pIndCcb = attsIndCcbByConnId(pCcb->connId)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if an outstanding indication */
|
||||
if (pIndCcb->outIndHandle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* clear outstanding indication */
|
||||
pIndCcb->outIndHandle = ATT_HANDLE_NONE;
|
||||
|
||||
/* stop indication timer */
|
||||
WsfTimerStop(&pIndCcb->outIndTimer);
|
||||
|
||||
/* call callback if flow control permits */
|
||||
if (!(pCcb->control & ATT_CCB_STATUS_FLOW_DISABLED))
|
||||
{
|
||||
attsExecCallback(pCcb->connId, pIndCcb->pendIndHandle, ATT_SUCCESS);
|
||||
pIndCcb->pendIndHandle = ATT_HANDLE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATT server for indications/notifications.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsIndInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
attsIndCcb_t *pCcb;
|
||||
|
||||
/* Initialize control block CCBs */
|
||||
for (i = 0, pCcb = attsIndCb.ccb; i < DM_CONN_MAX; i++, pCcb++)
|
||||
{
|
||||
/* set pointer to main CCB */
|
||||
pCcb->pMainCcb = &attCb.ccb[i];
|
||||
|
||||
/* initialize timer */
|
||||
pCcb->outIndTimer.handlerId = attCb.handlerId;
|
||||
pCcb->outIndTimer.msg.param = i + 1; /* param stores the conn id */
|
||||
}
|
||||
|
||||
/* set up callback interface */
|
||||
attsCb.pInd = &attsIndFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol Handle Value Indication.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsHandleValueInd(dmConnId_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attsHandleValueIndNtf(connId, handle, valueLen, pValue, ATT_PDU_VALUE_IND, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol Handle Value Notification.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsHandleValueNtf(dmConnId_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attsHandleValueIndNtf(connId, handle, valueLen, pValue, ATT_PDU_VALUE_NTF, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol Handle Value Indication without copying the attribute
|
||||
* value data.
|
||||
*
|
||||
* Note: attribute value buffer 'pValue' must be allocated with AttMsgAlloc().
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsHandleValueIndZeroCpy(dmConnId_t connId, uint16_t handle, uint16_t valueLen,
|
||||
uint8_t *pValue)
|
||||
{
|
||||
attsHandleValueIndNtf(connId, handle, valueLen, pValue, ATT_PDU_VALUE_IND, TRUE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an attribute protocol Handle Value Notification without copying the attribute
|
||||
* value data.
|
||||
*
|
||||
* Note: attribute value buffer 'pValue' must be allocated with AttMsgAlloc().
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsHandleValueNtfZeroCpy(dmConnId_t connId, uint16_t handle, uint16_t valueLen,
|
||||
uint8_t *pValue)
|
||||
{
|
||||
attsHandleValueIndNtf(connId, handle, valueLen, pValue, ATT_PDU_VALUE_NTF, TRUE);
|
||||
}
|
||||
Vendored
+881
@@ -0,0 +1,881 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server main 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_trace.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/wstr.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
#include "att_uuid.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* ATTS control block */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
static void attsDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket);
|
||||
static void attsConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt);
|
||||
static void attsMsgCback(wsfMsgHdr_t *pMsg);
|
||||
static void attsL2cCtrlCback(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Interface to ATT */
|
||||
static const attFcnIf_t attsFcnIf =
|
||||
{
|
||||
attsDataCback,
|
||||
attsL2cCtrlCback,
|
||||
(attMsgHandler_t) attsMsgCback,
|
||||
attsConnCback
|
||||
};
|
||||
|
||||
/* Minimum PDU lengths, indexed by method */
|
||||
static const uint8_t attsMinPduLen[] =
|
||||
{
|
||||
0, /* ATT_METHOD_ERR */
|
||||
ATT_MTU_REQ_LEN, /* ATT_METHOD_MTU */
|
||||
ATT_FIND_INFO_REQ_LEN, /* ATT_METHOD_FIND_INFO */
|
||||
ATT_FIND_TYPE_REQ_LEN, /* ATT_METHOD_FIND_TYPE */
|
||||
ATT_READ_TYPE_REQ_LEN, /* ATT_METHOD_READ_TYPE */
|
||||
ATT_READ_REQ_LEN, /* ATT_METHOD_READ */
|
||||
ATT_READ_BLOB_REQ_LEN, /* ATT_METHOD_READ_BLOB */
|
||||
ATT_READ_MULT_REQ_LEN + 4, /* ATT_METHOD_READ_MULTIPLE */
|
||||
ATT_READ_GROUP_TYPE_REQ_LEN, /* ATT_METHOD_READ_GROUP_TYPE */
|
||||
ATT_WRITE_REQ_LEN, /* ATT_METHOD_WRITE */
|
||||
ATT_WRITE_CMD_LEN, /* ATT_METHOD_WRITE_CMD */
|
||||
ATT_PREP_WRITE_REQ_LEN, /* ATT_METHOD_PREPARE_WRITE */
|
||||
ATT_EXEC_WRITE_REQ_LEN, /* ATT_METHOD_EXECUTE_WRITE */
|
||||
0, /* ATT_METHOD_VALUE_NTF */
|
||||
0, /* ATT_METHOD_VALUE_IND */
|
||||
ATT_VALUE_CNF_LEN, /* ATT_METHOD_VALUE_CNF */
|
||||
ATT_SIGNED_WRITE_CMD_LEN /* ATT_METHOD_SIGNED_WRITE_CMD */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* PDU processing function lookup table, indexed by method */
|
||||
attsProcFcn_t attsProcFcnTbl[ATT_METHOD_SIGNED_WRITE_CMD+1] =
|
||||
{
|
||||
NULL, /* ATT_METHOD_ERR */
|
||||
attsProcMtuReq, /* ATT_METHOD_MTU */
|
||||
attsProcFindInfoReq, /* ATT_METHOD_FIND_INFO */
|
||||
attsProcFindTypeReq, /* ATT_METHOD_FIND_TYPE */
|
||||
attsProcReadTypeReq, /* ATT_METHOD_READ_TYPE */
|
||||
attsProcReadReq, /* ATT_METHOD_READ */
|
||||
attsProcReadBlobReq, /* ATT_METHOD_READ_BLOB */
|
||||
attsProcReadMultReq, /* ATT_METHOD_READ_MULT */
|
||||
attsProcReadGroupTypeReq, /* ATT_METHOD_READ_GROUP_TYPE */
|
||||
attsProcWrite, /* ATT_METHOD_WRITE */
|
||||
attsProcWrite, /* ATT_METHOD_WRITE_CMD */
|
||||
attsProcPrepWriteReq, /* ATT_METHOD_PREP_WRITE */
|
||||
attsProcExecWriteReq, /* ATT_METHOD_EXEC_WRITE */
|
||||
NULL, /* ATT_METHOD_VALUE_NTF */
|
||||
NULL, /* ATT_METHOD_VALUE_IND */
|
||||
attsProcValueCnf, /* ATT_METHOD_VALUE_CNF */
|
||||
NULL /* ATT_METHOD_SIGNED_WRITE_CMD */
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
attsCb_t attsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Data callback for ATTS.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t method;
|
||||
uint8_t err;
|
||||
attsProcFcn_t procFcn;
|
||||
attCcb_t *pCcb;
|
||||
uint16_t attHandle;
|
||||
|
||||
/* get connection cb for this handle */
|
||||
if ((pCcb = attCcbByHandle(handle)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse opcode */
|
||||
opcode = *(pPacket + L2C_PAYLOAD_START);
|
||||
|
||||
/* get method */
|
||||
if ((opcode <= ATT_PDU_WRITE_REQ) ||
|
||||
((opcode >= ATT_PDU_PREP_WRITE_REQ) && (opcode <= ATT_PDU_VALUE_CNF)))
|
||||
{
|
||||
method = ATT_OPCODE_2_METHOD(opcode);
|
||||
}
|
||||
else if (opcode == ATT_PDU_WRITE_CMD)
|
||||
{
|
||||
method = ATT_METHOD_WRITE_CMD;
|
||||
}
|
||||
else if (opcode == ATT_PDU_SIGNED_WRITE_CMD)
|
||||
{
|
||||
method = ATT_METHOD_SIGNED_WRITE_CMD;
|
||||
}
|
||||
else
|
||||
{
|
||||
method = ATT_METHOD_ERR;
|
||||
}
|
||||
|
||||
/* ignore packet if write response is pending. */
|
||||
if (pCcb->control & ATT_CCB_STATUS_RSP_PENDING)
|
||||
{
|
||||
if (method != ATT_METHOD_VALUE_CNF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check client's status to see if server is allowed to process this PDU. */
|
||||
err = attsCsfActClientState(handle, opcode, pPacket);
|
||||
if (err)
|
||||
{
|
||||
BYTES_TO_UINT16(attHandle, pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
attHandle = ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
#if defined(ATTS_ERROR_TEST) && (ATTS_ERROR_TEST == TRUE)
|
||||
if (attCb.errTest != ATT_SUCCESS)
|
||||
{
|
||||
BYTES_TO_UINT16(attHandle, pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN);
|
||||
attsErrRsp(handle, opcode, attHandle, attCb.errTest);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if no error process request */
|
||||
if (!err)
|
||||
{
|
||||
/* look up processing function */
|
||||
procFcn = attsProcFcnTbl[method];
|
||||
|
||||
/* if method is supported */
|
||||
if (procFcn != NULL)
|
||||
{
|
||||
/* verify length */
|
||||
if (len >= attsMinPduLen[method])
|
||||
{
|
||||
/* execute processing function */
|
||||
(*procFcn)(pCcb, len, pPacket);
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid PDU length */
|
||||
err = ATT_ERR_INVALID_PDU;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* PDU not supported */
|
||||
err = ATT_ERR_NOT_SUP;
|
||||
}
|
||||
}
|
||||
|
||||
/* if there's an error and an error response can be sent for this opcode */
|
||||
if (err && (opcode != ATT_PDU_MTU_REQ) && (opcode != ATT_PDU_VALUE_CNF) &&
|
||||
((opcode & ATT_PDU_MASK_COMMAND) == 0))
|
||||
{
|
||||
attsErrRsp(handle, opcode, attHandle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection callback for ATTS.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsConnCback(attCcb_t *pCcb, dmEvt_t *pDmEvt)
|
||||
{
|
||||
/* if connection closed */
|
||||
if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* clear prepare write queue */
|
||||
attsClearPrepWrites(pCcb);
|
||||
|
||||
/* stop service discovery idle timer, if running */
|
||||
if (DmConnCheckIdle(pCcb->connId) & DM_IDLE_ATTS_DISC)
|
||||
{
|
||||
WsfTimerStop(&pCcb->idleTimer);
|
||||
}
|
||||
}
|
||||
|
||||
/* pass event to indication interface */
|
||||
(*attsCb.pInd->connCback)(pCcb, pDmEvt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF message handler callback for ATTS.
|
||||
*
|
||||
* \param pMsg DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsMsgCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* handle service discovery idle timeout */
|
||||
if (pMsg->event == ATTS_MSG_IDLE_TIMEOUT)
|
||||
{
|
||||
/* set channel as idle */
|
||||
DmConnSetIdle((dmConnId_t) pMsg->param, DM_IDLE_ATTS_DISC, DM_CONN_IDLE);
|
||||
}
|
||||
/* pass event to indication interface */
|
||||
else if (pMsg->event <= ATTS_MSG_IND_TIMEOUT)
|
||||
{
|
||||
(*attsCb.pInd->msgCback)(pMsg);
|
||||
}
|
||||
/* pass event to signed data interface */
|
||||
else if (pMsg->event == ATTS_MSG_SIGN_CMAC_CMPL)
|
||||
{
|
||||
(*attsCb.signMsgCback)(pMsg);
|
||||
}
|
||||
else if (pMsg->event == ATTS_MSG_DBH_CMAC_CMPL)
|
||||
{
|
||||
/* handle database hash update */
|
||||
attsProcessDatabaseHashUpdate((secCmacMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C control callback for ATTS.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsL2cCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* pass event to indication interface */
|
||||
(*attsCb.pInd->ctrlCback)(pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an error response PDU.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param opcode Opcode of the request that generated this error.
|
||||
* \param attHandle Attribute handle in request, if applicable.
|
||||
* \param reason Error reason.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsErrRsp(uint16_t handle, uint8_t opcode, uint16_t attHandle, uint8_t reason)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate buffer */
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_ERR_RSP_LEN)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_ERR_RSP);
|
||||
UINT8_TO_BSTREAM(p, opcode);
|
||||
UINT16_TO_BSTREAM(p, attHandle);
|
||||
UINT8_TO_BSTREAM(p, reason);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, handle, ATT_ERR_RSP_LEN, pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear the prepared write queue.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsClearPrepWrites(attCcb_t *pCcb)
|
||||
{
|
||||
void *pBuf;
|
||||
|
||||
while ((pBuf = WsfQueueDeq(&pCcb->prepWriteQueue)) != NULL)
|
||||
{
|
||||
WsfBufFree(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set connection idle status to busy for service discovery.
|
||||
*
|
||||
* \param pCcb ATT control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsDiscBusy(attCcb_t *pCcb)
|
||||
{
|
||||
if (pAttCfg->discIdleTimeout > 0)
|
||||
{
|
||||
/* set channel as busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_ATTS_DISC, DM_CONN_BUSY);
|
||||
|
||||
/* start service discovery idle timer */
|
||||
pCcb->idleTimer.handlerId = attCb.handlerId;
|
||||
pCcb->idleTimer.msg.event = ATTS_MSG_IDLE_TIMEOUT;
|
||||
pCcb->idleTimer.msg.param = pCcb->connId;
|
||||
WsfTimerStartSec(&pCcb->idleTimer, pAttCfg->discIdleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process updated database hash.
|
||||
*
|
||||
* \param pMsg Event containing the new database hash.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcessDatabaseHashUpdate(secCmacMsg_t *pMsg)
|
||||
{
|
||||
attEvt_t evt;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t dbhCharHandle;
|
||||
|
||||
/* send to application */
|
||||
evt.hdr.event = ATTS_DB_HASH_CALC_CMPL_IND;
|
||||
evt.hdr.status = ATT_SUCCESS;
|
||||
evt.hdr.param = DM_CONN_ID_NONE;
|
||||
|
||||
evt.valueLen = ATT_DATABASE_HASH_LEN;
|
||||
evt.handle = ATT_HANDLE_NONE;
|
||||
evt.continuing = FALSE;
|
||||
evt.mtu = 0;
|
||||
|
||||
/* free plain text buffer */
|
||||
if (pMsg->pPlainText != NULL)
|
||||
{
|
||||
WsfBufFree(pMsg->pPlainText);
|
||||
pMsg->pPlainText = NULL;
|
||||
}
|
||||
|
||||
/* copy in little endian */
|
||||
evt.pValue = pMsg->pCiphertext;
|
||||
|
||||
/* find GATT database handle */
|
||||
dbhCharHandle = attsFindUuidInRange(ATT_HANDLE_START, ATT_HANDLE_MAX, ATT_16_UUID_LEN,
|
||||
(uint8_t *) attGattDbhChUuid, &pAttr, &pGroup);
|
||||
|
||||
if (dbhCharHandle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* Set hash in service. */
|
||||
AttsSetAttr(dbhCharHandle, SEC_CMAC_HASH_LEN, evt.pValue);
|
||||
}
|
||||
|
||||
/* set hash update complete */
|
||||
attsCsfSetHashUpdateStatus(FALSE);
|
||||
|
||||
attCb.cback(&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if any clients are pending on a new database hash value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsCheckPendDbHashReadRsp(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
attCcb_t *pCcb = &attCb.ccb[i];
|
||||
|
||||
if (pCcb->pPendDbHashRsp)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_TYPE_RSP);
|
||||
|
||||
/* set length parameter in response message */
|
||||
UINT8_TO_BSTREAM(p, ATT_DATABASE_HASH_LEN + sizeof(uint16_t));
|
||||
|
||||
/* copy result to response message */
|
||||
UINT16_TO_BSTREAM(p, pCcb->pPendDbHashRsp->handle);
|
||||
|
||||
if ((pAttr = attsFindByHandle(pCcb->pPendDbHashRsp->handle, &pGroup)) != NULL)
|
||||
{
|
||||
memcpy(p, pAttr->pValue, *pAttr->pLen);
|
||||
p += *pAttr->pLen;
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, p - (pBuf + L2C_PAYLOAD_START), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->connId, ATT_PDU_READ_TYPE_REQ, pCcb->pPendDbHashRsp->startHandle, ATT_ERR_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->connId, ATT_PDU_READ_TYPE_REQ, pCcb->pPendDbHashRsp->startHandle, ATT_ERR_RESOURCES);
|
||||
}
|
||||
|
||||
/* Free pending state information. */
|
||||
WsfBufFree(pCcb->pPendDbHashRsp);
|
||||
pCcb->pPendDbHashRsp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Determine if attribute is hashable and return length of hashable data.
|
||||
*
|
||||
* \param pAttr Attribute to check for inclusion in hash.
|
||||
*
|
||||
* \return 0 if not hashable, else length of hashable data in bytes.
|
||||
*
|
||||
* \note Hashable attributes include Primary Service, Secondary Service, Included Service,
|
||||
* Characteristic Declaration and Characteristic Extended Properties which contribute their
|
||||
* ATT handle, ATT type and ATT value. Hashable attributes also include Characteristic User
|
||||
* Description, Client Characteristic Configuration, Server Characteristic Configuration,
|
||||
* Characteristic Format, and Characteristic Aggreate Format which contribute their ATT
|
||||
* handle and ATT type.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t attsIsHashableAttr(attsAttr_t *pAttr)
|
||||
{
|
||||
/* Initialize length to 2 for ATT Handle length */
|
||||
uint16_t length = 2;
|
||||
uint16_t uuid;
|
||||
static bool_t isAttrCharVal = FALSE;
|
||||
|
||||
/* Characteristic values are skipped */
|
||||
if (isAttrCharVal)
|
||||
{
|
||||
isAttrCharVal = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTES_TO_UINT16(uuid, pAttr->pUuid);
|
||||
switch (uuid)
|
||||
{
|
||||
/* Top cases include Attribute Value length */
|
||||
case ATT_UUID_CHARACTERISTIC:
|
||||
/* Set the next characteristic in database to be skipped */
|
||||
isAttrCharVal = TRUE;
|
||||
/* Fallthrough */
|
||||
case ATT_UUID_PRIMARY_SERVICE:
|
||||
case ATT_UUID_SECONDARY_SERVICE:
|
||||
case ATT_UUID_INCLUDE:
|
||||
case ATT_UUID_CHARACTERISTIC_EXT:
|
||||
length += *pAttr->pLen;
|
||||
/* Fallthrough */
|
||||
|
||||
/* All values fall through to include Attribute Type length */
|
||||
case ATT_UUID_CHAR_USER_DESC:
|
||||
case ATT_UUID_CLIENT_CHAR_CONFIG:
|
||||
case ATT_UUID_SERVER_CHAR_CONFIG:
|
||||
case ATT_UUID_AGGREGATE_FORMAT:
|
||||
if (pAttr->settings & ATTS_SET_UUID_128)
|
||||
{
|
||||
length += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
length += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
length = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATT server.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsInit(void)
|
||||
{
|
||||
/* Initialize control block */
|
||||
WSF_QUEUE_INIT(&attsCb.groupQueue);
|
||||
attsCb.pInd = &attFcnDefault;
|
||||
attsCb.signMsgCback = (attMsgHandler_t) attEmptyHandler;
|
||||
|
||||
/* set up callback interfaces */
|
||||
attCb.pServer = &attsFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register an authorization callback with the attribute server.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsAuthorRegister(attsAuthorCback_t cback)
|
||||
{
|
||||
attsCb.authorCback = cback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Create hash from the database string.
|
||||
*
|
||||
* \param pKey Key for hashing.
|
||||
* \param pMsg Plaintext to hash.
|
||||
* \param msgLen Length of Plaintext data.
|
||||
*
|
||||
* \return \ref TRUE if successful, \ref FALSE if not.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t AttsHashDatabaseString(uint8_t *pKey, uint8_t *pMsg, uint16_t msgLen)
|
||||
{
|
||||
return SecCmac(pKey, pMsg, msgLen, attCb.handlerId, 0, ATTS_MSG_DBH_CMAC_CMPL);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate database hash from the GATT database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsCalculateDbHash(void)
|
||||
{
|
||||
uint16_t msgLen = 0;
|
||||
uint8_t *pMsg;
|
||||
attsGroup_t *pGroup = (attsGroup_t *) attsCb.groupQueue.pHead;
|
||||
|
||||
/* Determine length of message. */
|
||||
while (pGroup != NULL)
|
||||
{
|
||||
uint8_t numAttrs = (pGroup->endHandle - pGroup->startHandle) + 1;
|
||||
|
||||
for (attsAttr_t *pAttr = pGroup->pAttr; numAttrs != 0; numAttrs--, pAttr++)
|
||||
{
|
||||
msgLen += attsIsHashableAttr(pAttr);
|
||||
}
|
||||
|
||||
pGroup = pGroup->pNext;
|
||||
}
|
||||
|
||||
/* Allocate buffer for message. */
|
||||
if ((pMsg = WsfBufAlloc(msgLen)) != NULL)
|
||||
{
|
||||
pGroup = (attsGroup_t *)attsCb.groupQueue.pHead;
|
||||
uint8_t hashingKey[16] = { 0, };
|
||||
uint8_t *p = pMsg;
|
||||
|
||||
/* For each service in services */
|
||||
while (pGroup)
|
||||
{
|
||||
uint16_t attHandle = pGroup->startHandle;
|
||||
|
||||
/* For each attribute in the service */
|
||||
for (attsAttr_t *pAttr = pGroup->pAttr; attHandle <= pGroup->endHandle; attHandle++, pAttr++)
|
||||
{
|
||||
uint16_t valLen;
|
||||
uint8_t uuidLen = 2;
|
||||
|
||||
valLen = attsIsHashableAttr(pAttr);
|
||||
if (valLen)
|
||||
{
|
||||
/* Add handle */
|
||||
UINT16_TO_BSTREAM(p, attHandle);
|
||||
|
||||
/* Add attribute type*/
|
||||
if (pAttr->settings & ATTS_SET_UUID_128)
|
||||
{
|
||||
memcpy(p, pAttr->pUuid, 16);
|
||||
p += 16;
|
||||
uuidLen = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t uuid;
|
||||
BYTES_TO_UINT16(uuid, pAttr->pUuid);
|
||||
UINT16_TO_BSTREAM(p,uuid);
|
||||
}
|
||||
|
||||
/* Add Attribute value if required */
|
||||
if (valLen - (uuidLen + 2))
|
||||
{
|
||||
memcpy(p, pAttr->pValue, *pAttr->pLen);
|
||||
p += *pAttr->pLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pGroup = pGroup->pNext;
|
||||
}
|
||||
|
||||
/* Send to CMAC */
|
||||
if (AttsHashDatabaseString(hashingKey, pMsg, msgLen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assert on failure to initiate database hash generation. */
|
||||
WSF_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add an attribute group to the attribute server.
|
||||
*
|
||||
* \param pGroup Pointer to an attribute group structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsAddGroup(attsGroup_t *pGroup)
|
||||
{
|
||||
attsGroup_t *pElem;
|
||||
attsGroup_t *pPrev = NULL;
|
||||
|
||||
/* task schedule lock */
|
||||
WsfTaskLock();
|
||||
|
||||
pElem = (attsGroup_t *) attsCb.groupQueue.pHead;
|
||||
|
||||
/* iterate over queue sorted by increasing handle value */
|
||||
while (pElem != NULL)
|
||||
{
|
||||
if (pGroup->startHandle < pElem->startHandle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pPrev = pElem;
|
||||
pElem = pElem->pNext;
|
||||
}
|
||||
|
||||
/* insert new group */
|
||||
WsfQueueInsert(&attsCb.groupQueue, pGroup, pPrev);
|
||||
|
||||
/* set database hash update status to true until a new hash is generated */
|
||||
attsCsfSetHashUpdateStatus(TRUE);
|
||||
|
||||
/* task schedule unlock */
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove an attribute group from the attribute server.
|
||||
*
|
||||
* \param startHandle Start handle of attribute group to be removed.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsRemoveGroup(uint16_t startHandle)
|
||||
{
|
||||
attsGroup_t *pElem;
|
||||
attsGroup_t *pPrev = NULL;
|
||||
|
||||
/* task schedule lock */
|
||||
WsfTaskLock();
|
||||
|
||||
pElem = (attsGroup_t *) attsCb.groupQueue.pHead;
|
||||
|
||||
/* find group in queue */
|
||||
while (pElem != NULL)
|
||||
{
|
||||
if (pElem->startHandle == startHandle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pPrev = pElem;
|
||||
pElem = pElem->pNext;
|
||||
}
|
||||
|
||||
/* if group found remove from queue */
|
||||
if (pElem != NULL)
|
||||
{
|
||||
WsfQueueRemove(&attsCb.groupQueue, pElem, pPrev);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN1("AttsRemoveGroup start handle not found: 0x%04x", startHandle);
|
||||
}
|
||||
|
||||
/* set database hash update status to true until a new hash is generated */
|
||||
attsCsfSetHashUpdateStatus(TRUE);
|
||||
|
||||
/* task schedule unlock */
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set an attribute value in the attribute server.
|
||||
*
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Attribute length.
|
||||
* \param pValue Attribute value.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttsSetAttr(uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
WsfTaskLock();
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify write length */
|
||||
if (valueLen > pAttr->maxLen)
|
||||
{
|
||||
err = ATT_ERR_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set attribute value */
|
||||
memcpy(pAttr->pValue, pValue, valueLen);
|
||||
|
||||
/* set the length if variable length attribute */
|
||||
if ((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0)
|
||||
{
|
||||
*(pAttr->pLen) = valueLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else attribute not found */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
WsfTaskUnlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get an attribute value in the attribute server. Tasks should be locked before
|
||||
* calling this function and remain locked until pLen and pValue are no longer used.
|
||||
*
|
||||
* \param handle Attribute handle.
|
||||
* \param pLen Returned attribute length pointer.
|
||||
* \param pValue Returned attribute value pointer.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful or other error code if failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AttsGetAttr(uint16_t handle, uint16_t *pLen, uint8_t **pValue)
|
||||
{
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* set length and value pointers */
|
||||
*pLen = *(pAttr->pLen);
|
||||
*pValue = pAttr->pValue;
|
||||
}
|
||||
/* else attribute not found */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For testing purposes only.
|
||||
*
|
||||
* \param status ATT status
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsErrorTest(uint8_t status)
|
||||
{
|
||||
attCb.errTest = status;
|
||||
}
|
||||
Vendored
+174
@@ -0,0 +1,174 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server main 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef ATTS_MAIN_H
|
||||
#define ATTS_MAIN_H
|
||||
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* ATTS event handler messages */
|
||||
enum
|
||||
{
|
||||
ATTS_MSG_IDLE_TIMEOUT = ATTS_MSG_START,
|
||||
ATTS_MSG_API_VALUE_IND_NTF,
|
||||
ATTS_MSG_IND_TIMEOUT,
|
||||
ATTS_MSG_SIGN_CMAC_CMPL,
|
||||
ATTS_MSG_DBH_CMAC_CMPL
|
||||
};
|
||||
|
||||
/*!
|
||||
* Data buffer format for API request messages:
|
||||
*
|
||||
* | attsPktParam_t | ATT request data |
|
||||
* | bytes 0 to 7 | bytes 8 - |
|
||||
*/
|
||||
|
||||
/* API parameters */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t handle;
|
||||
} attsPktParam_t;
|
||||
|
||||
/* verify attsPktParam_t will work in data buffer format described above */
|
||||
WSF_CT_ASSERT(sizeof(attsPktParam_t) <= L2C_PAYLOAD_START);
|
||||
|
||||
/* API message structure */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
attsPktParam_t *pPkt;
|
||||
} attsApiMsg_t;
|
||||
|
||||
/* Connection control block for indications/notifications */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t outIndTimer; /* Outstanding indication timer */
|
||||
attCcb_t *pMainCcb; /* Pointer to ATT main CCB */
|
||||
uint16_t outIndHandle; /* Waiting for confirm from peer for this indication handle */
|
||||
uint16_t pendIndHandle; /* Callback to application pending for this indication handle */
|
||||
uint16_t pendNtfHandle[ATT_NUM_SIMUL_NTF]; /* Callback to application pending for this notification handle */
|
||||
} attsIndCcb_t;
|
||||
|
||||
/* Control block for indications/notifications */
|
||||
typedef struct
|
||||
{
|
||||
attsIndCcb_t ccb[DM_CONN_MAX];
|
||||
} attsIndCb_t;
|
||||
|
||||
/* Client characteristic configuration descriptor callback type
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param method Read or write.
|
||||
* \param handle Attribute handle of the descriptor.
|
||||
* \param pValue Pointer to the attribute value of the descriptor.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful otherwise error.
|
||||
*/
|
||||
typedef uint8_t (*attsCccFcn_t)(dmConnId_t connId, uint8_t method, uint16_t handle, uint8_t *pValue);
|
||||
|
||||
/* Main control block of the ATTS subsystem */
|
||||
typedef struct
|
||||
{
|
||||
wsfQueue_t groupQueue; /* Queue of attribute groups */
|
||||
attFcnIf_t const *pInd; /* Indication callback interface */
|
||||
attMsgHandler_t signMsgCback; /* Signed data callback interface */
|
||||
attsAuthorCback_t authorCback; /* Authorization callback */
|
||||
attsCccFcn_t cccCback; /* CCC callback */
|
||||
} attsCb_t;
|
||||
|
||||
/* PDU processing function type */
|
||||
typedef void (*attsProcFcn_t)(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
|
||||
/* CSF Control block */
|
||||
typedef struct
|
||||
{
|
||||
attsCsfRec_t attsCsfTable[DM_CONN_MAX]; /* connected clients' supported features record table. */
|
||||
attsCsfWriteCback_t writeCback; /* Write callback. */
|
||||
uint8_t isHashUpdating; /* Database hash update status. */
|
||||
} attsCsfCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* PDU processing function lookup table, indexed by method */
|
||||
extern attsProcFcn_t attsProcFcnTbl[ATT_METHOD_SIGNED_WRITE_CMD+1];
|
||||
|
||||
/* Control block for indications/notifications */
|
||||
extern attsIndCb_t attsIndCb;
|
||||
|
||||
/* Control block */
|
||||
extern attsCb_t attsCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void attsErrRsp(uint16_t handle, uint8_t opcode, uint16_t attHandle, uint8_t reason);
|
||||
void attsClearPrepWrites(attCcb_t *pCcb);
|
||||
bool_t attsUuidCmp(attsAttr_t *pAttr, uint8_t uuidLen, uint8_t *pUuid);
|
||||
bool_t attsUuid16Cmp(uint8_t *pUuid16, uint8_t uuidLen, uint8_t *pUuid);
|
||||
attsAttr_t *attsFindByHandle(uint16_t handle, attsGroup_t **pAttrGroup);
|
||||
uint16_t attsFindInRange(uint16_t startHandle, uint16_t endHandle, attsAttr_t **pAttr);
|
||||
uint16_t attsFindUuidInRange(uint16_t startHandle, uint16_t endHandle, uint8_t uuidLen,
|
||||
uint8_t *pUuid, attsAttr_t **pAttr, attsGroup_t **pAttrGroup);
|
||||
uint8_t attsPermissions(dmConnId_t connId, uint8_t permit, uint16_t handle, uint8_t permissions);
|
||||
void attsDiscBusy(attCcb_t *pCcb);
|
||||
void attsCheckPendDbHashReadRsp(void);
|
||||
void attsProcessDatabaseHashUpdate(secCmacMsg_t *pMsg);
|
||||
uint16_t attsIsHashableAttr(attsAttr_t *pAttr);
|
||||
|
||||
void attsProcMtuReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcFindInfoReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcFindTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcReadTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcReadReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcReadBlobReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcReadMultReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcReadGroupTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcWrite(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcPrepWriteReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcExecWriteReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
void attsProcValueCnf(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket);
|
||||
|
||||
uint8_t attsCsfActClientState(uint16_t handle, uint8_t opcode, uint8_t *pPacket);
|
||||
uint8_t attsCsfIsClientChangeAware(dmConnId_t connId, uint16_t handle);
|
||||
void attsCsfSetHashUpdateStatus(bool_t isUpdating);
|
||||
uint8_t attsCsfGetHashUpdateStatus(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATTS_MAIN_H */
|
||||
Vendored
+469
@@ -0,0 +1,469 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server mandatory PDU processing functions.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_math.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Compare the given attribute's UUID to the given UUID.
|
||||
*
|
||||
* \param pAttr Pointer to attribute.
|
||||
* \param uuidLen UUID length, either 2 or 16.
|
||||
* \param pUuid Pointer to UUID.
|
||||
*
|
||||
* \return TRUE of UUIDs match, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t attsUuidCmp(attsAttr_t *pAttr, uint8_t uuidLen, uint8_t *pUuid)
|
||||
{
|
||||
/* if both uuids are the same length */
|
||||
if ((((pAttr->settings & ATTS_SET_UUID_128) == 0) && (uuidLen == ATT_16_UUID_LEN)) ||
|
||||
(((pAttr->settings & ATTS_SET_UUID_128) != 0) && (uuidLen == ATT_128_UUID_LEN)))
|
||||
{
|
||||
/* simply compare the data */
|
||||
return (memcmp(pAttr->pUuid, pUuid, uuidLen) == 0);
|
||||
}
|
||||
/* else we need to convert one of the uuids */
|
||||
else if (((pAttr->settings & ATTS_SET_UUID_128) == 0) && (uuidLen == ATT_128_UUID_LEN))
|
||||
{
|
||||
return attUuidCmp16to128(pAttr->pUuid, pUuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return attUuidCmp16to128(pUuid, pAttr->pUuid);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Compare the given 16 bit UUID to the given UUID.
|
||||
*
|
||||
* \param pUuid16 Pointer to the 16 bit UUID.
|
||||
* \param uuidLen UUID length, either 2 or 16.
|
||||
* \param pUuid Pointer to UUID.
|
||||
*
|
||||
* \return TRUE of UUIDs match, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t attsUuid16Cmp(uint8_t *pUuid16, uint8_t uuidLen, uint8_t *pUuid)
|
||||
{
|
||||
if (uuidLen == ATT_16_UUID_LEN)
|
||||
{
|
||||
return ((pUuid16[0] == pUuid[0]) && (pUuid16[1] == pUuid[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
return attUuidCmp16to128(pUuid16, pUuid);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find an attribute with the given handle.
|
||||
*
|
||||
* \param handle Attribute handle.
|
||||
* \param pAttrGroup Return value pointer to found attribute's group.
|
||||
*
|
||||
* \return Pointer to attribute if found, othewise NULL.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
attsAttr_t *attsFindByHandle(uint16_t handle, attsGroup_t **pAttrGroup)
|
||||
{
|
||||
attsGroup_t *pGroup;
|
||||
|
||||
/* iterate over attribute group list */
|
||||
for (pGroup = attsCb.groupQueue.pHead; pGroup != NULL; pGroup = pGroup->pNext)
|
||||
{
|
||||
/* if start handle within handle range of group */
|
||||
if ((handle >= pGroup->startHandle) && (handle <= pGroup->endHandle))
|
||||
{
|
||||
/* index by handle into attribute array to return attribute */
|
||||
*pAttrGroup = pGroup;
|
||||
return &pGroup->pAttr[handle - pGroup->startHandle];
|
||||
}
|
||||
}
|
||||
|
||||
/* handle not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find the first attribute within the given handle range.
|
||||
*
|
||||
* \param startHandle Starting attribute handle.
|
||||
* \param endHandle Ending attribute handle.
|
||||
* \param pAttr Return value pointer to found attribute.
|
||||
*
|
||||
* \return Attribute handle or ATT_HANDLE_NONE if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t attsFindInRange(uint16_t startHandle, uint16_t endHandle, attsAttr_t **pAttr)
|
||||
{
|
||||
attsGroup_t *pGroup;
|
||||
|
||||
/* iterate over attribute group list */
|
||||
for (pGroup = attsCb.groupQueue.pHead; pGroup != NULL; pGroup = pGroup->pNext)
|
||||
{
|
||||
/* if start handle is less than group start handle but handle range is within group */
|
||||
if ((startHandle < pGroup->startHandle) && (endHandle >= pGroup->startHandle))
|
||||
{
|
||||
/* set start handle to first handle in group */
|
||||
startHandle = pGroup->startHandle;
|
||||
}
|
||||
|
||||
/* if start handle within handle range of group */
|
||||
if ((startHandle >= pGroup->startHandle) && (startHandle <= pGroup->endHandle))
|
||||
{
|
||||
/* index by handle into attribute array to return attribute */
|
||||
*pAttr = &pGroup->pAttr[startHandle - pGroup->startHandle];
|
||||
return startHandle;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle within range not found */
|
||||
return ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform required permission and security checks when reading or writing an attribute.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param permit Either ATTS_PERMIT_READ or ATTS_PERMIT_WRITE.
|
||||
* \param handle Attribute handle.
|
||||
* \param permissions Attribute permissions.
|
||||
*
|
||||
* \return ATT_SUCCESS if successful or error code on failure.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t attsPermissions(dmConnId_t connId, uint8_t permit, uint16_t handle, uint8_t permissions)
|
||||
{
|
||||
uint8_t secLevel;
|
||||
|
||||
/* verify read or write permissions */
|
||||
if (!(permissions & permit))
|
||||
{
|
||||
return (permit == ATTS_PERMIT_READ) ? ATT_ERR_READ : ATT_ERR_WRITE;
|
||||
}
|
||||
|
||||
/* convert write permissions to read permissions for easier masking */
|
||||
if (permit == ATTS_PERMIT_WRITE)
|
||||
{
|
||||
permissions >>= 4;
|
||||
}
|
||||
|
||||
/* if no security requirements return quickly */
|
||||
if ((permissions & (ATTS_PERMIT_READ_AUTH | ATTS_PERMIT_READ_AUTHORIZ | ATTS_PERMIT_READ_ENC)) == 0)
|
||||
{
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/* get security level for this connection */
|
||||
secLevel = DmConnSecLevel(connId);
|
||||
|
||||
/* check if encryption required */
|
||||
if ((permissions & ATTS_PERMIT_READ_ENC) && (secLevel == DM_SEC_LEVEL_NONE))
|
||||
{
|
||||
return ATT_ERR_AUTH;
|
||||
}
|
||||
|
||||
/* check if encryption required with authenticated key */
|
||||
if (((permissions & (ATTS_PERMIT_READ_AUTH | ATTS_PERMIT_READ_ENC)) ==
|
||||
(ATTS_PERMIT_READ_AUTH | ATTS_PERMIT_READ_ENC)) && (secLevel < DM_SEC_LEVEL_ENC_AUTH))
|
||||
{
|
||||
return ATT_ERR_AUTH;
|
||||
}
|
||||
|
||||
/* authorization check */
|
||||
if (permissions & ATTS_PERMIT_READ_AUTHORIZ)
|
||||
{
|
||||
if (attsCb.authorCback == NULL)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (*attsCb.authorCback)(connId, permit, handle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process an MTU request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcMtuReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint16_t mtu;
|
||||
uint16_t localMtu;
|
||||
uint8_t *pRsp;
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
|
||||
/* parse mtu */
|
||||
BYTES_TO_UINT16(mtu, p);
|
||||
|
||||
/* verify */
|
||||
if (mtu < ATT_DEFAULT_MTU)
|
||||
{
|
||||
mtu = ATT_DEFAULT_MTU;
|
||||
}
|
||||
|
||||
/* get desired MTU */
|
||||
localMtu = WSF_MIN(pAttCfg->mtu, (HciGetMaxRxAclLen() - L2C_HDR_LEN));
|
||||
|
||||
/* send response */
|
||||
if ((pRsp = attMsgAlloc(L2C_PAYLOAD_START + ATT_MTU_RSP_LEN)) != NULL)
|
||||
{
|
||||
p = pRsp + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_MTU_RSP);
|
||||
UINT16_TO_BSTREAM(p, localMtu);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, ATT_MTU_RSP_LEN, pRsp);
|
||||
}
|
||||
|
||||
/* set mtu for the connection */
|
||||
attSetMtu(pCcb, mtu, localMtu);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a find information request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcFindInfoReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
uint16_t handle;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handles */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(startHandle, pPacket);
|
||||
BSTREAM_TO_UINT16(endHandle, pPacket);
|
||||
|
||||
/* verify handles */
|
||||
if ((startHandle == 0) || (startHandle > endHandle))
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_FIND_INFO_RSP);
|
||||
|
||||
/* set result format */
|
||||
UINT8_TO_BSTREAM(p, ATT_FIND_HANDLE_16_UUID);
|
||||
|
||||
/* find attributes within handle range */
|
||||
handle = startHandle;
|
||||
while ((handle = attsFindInRange(handle, endHandle, &pAttr)) != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* copy handle and UUID into response buffer */
|
||||
|
||||
/* if 128 bit UUID */
|
||||
if (pAttr->settings & ATTS_SET_UUID_128)
|
||||
{
|
||||
/* if this is the first result */
|
||||
if (p == (pBuf + L2C_PAYLOAD_START + 2))
|
||||
{
|
||||
p--;
|
||||
UINT8_TO_BSTREAM(p, ATT_FIND_HANDLE_128_UUID);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pAttr->pUuid, ATT_128_UUID_LEN);
|
||||
p += ATT_128_UUID_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* else 16 bit UUID */
|
||||
else
|
||||
{
|
||||
/* check if result fits */
|
||||
if ((p + ATT_16_UUID_LEN + sizeof(uint16_t)) <=
|
||||
(pBuf + pCcb->mtu + L2C_PAYLOAD_START))
|
||||
{
|
||||
/* copy result */
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT8_TO_BSTREAM(p, pAttr->pUuid[0]);
|
||||
UINT8_TO_BSTREAM(p, pAttr->pUuid[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* response buffer full, we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* special case of handle at max range */
|
||||
if (handle == ATT_HANDLE_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* try next handle */
|
||||
if (++handle > endHandle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no results found set error, free buffer */
|
||||
if (p == (pBuf + L2C_PAYLOAD_START + 2))
|
||||
{
|
||||
WsfMsgFree(pBuf);
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer allocation failed */
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
/* set channel as busy for service discovery */
|
||||
attsDiscBusy(pCcb);
|
||||
|
||||
/* if no error send response, else send error */
|
||||
if (!err)
|
||||
{
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (p - (pBuf + L2C_PAYLOAD_START)), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_FIND_INFO_REQ, startHandle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a read request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcReadReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t handle;
|
||||
uint16_t readLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handle */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(handle, pPacket);
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify permissions */
|
||||
if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions)) == ATT_SUCCESS)
|
||||
{
|
||||
/* call read callback if desired */
|
||||
if ((pAttr->settings & ATTS_SET_READ_CBACK) &&
|
||||
(pGroup->readCback != NULL))
|
||||
{
|
||||
err = (*pGroup->readCback)(pCcb->connId, handle, ATT_PDU_READ_REQ, 0, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_READ, handle, pAttr->pValue);
|
||||
}
|
||||
|
||||
if (err == ATT_SUCCESS)
|
||||
{
|
||||
/* determine length of data to read */
|
||||
readLen = (*pAttr->pLen < (pCcb->mtu - ATT_READ_RSP_LEN)) ?
|
||||
*pAttr->pLen : (pCcb->mtu - ATT_READ_RSP_LEN);
|
||||
|
||||
/* Allocate response buffer */
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_READ_RSP_LEN + readLen)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_RSP);
|
||||
memcpy(p, pAttr->pValue, readLen);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (ATT_READ_RSP_LEN + readLen), pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else invalid handle */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_REQ, handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+833
@@ -0,0 +1,833 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server optional read PDU processing functions.
|
||||
*
|
||||
* 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_buf.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find the first attribute within the given handle range with a matching UUID.
|
||||
*
|
||||
* \param startHandle Starting attribute handle.
|
||||
* \param endHandle Ending attribute handle.
|
||||
* \param uuidLen UUID length, either 2 or 16.
|
||||
* \param pUUID Pointer to UUID.
|
||||
* \param pAttr Return value pointer to found attribute.
|
||||
* \param pAttrGroup Return value pointer to found attribute's group.
|
||||
*
|
||||
* \return Attribute handle or ATT_HANDLE_NONE if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t attsFindUuidInRange(uint16_t startHandle, uint16_t endHandle, uint8_t uuidLen,
|
||||
uint8_t *pUuid, attsAttr_t **pAttr, attsGroup_t **pAttrGroup)
|
||||
{
|
||||
attsGroup_t *pGroup;
|
||||
|
||||
/* iterate over attribute group list */
|
||||
for (pGroup = attsCb.groupQueue.pHead; pGroup != NULL; pGroup = pGroup->pNext)
|
||||
{
|
||||
/* if start handle is less than group start handle but handle range is within group */
|
||||
if ((startHandle < pGroup->startHandle) && (endHandle >= pGroup->startHandle))
|
||||
{
|
||||
/* set start handle to first handle in group */
|
||||
startHandle = pGroup->startHandle;
|
||||
}
|
||||
|
||||
/* if start handle within handle range of group */
|
||||
if ((startHandle >= pGroup->startHandle) && (startHandle <= pGroup->endHandle))
|
||||
{
|
||||
/* compare uuid with each attribute in group */
|
||||
*pAttr = &pGroup->pAttr[startHandle - pGroup->startHandle];
|
||||
while ((startHandle <= pGroup->endHandle) && (startHandle <= endHandle))
|
||||
{
|
||||
/* compare uuid in attribute */
|
||||
if (attsUuidCmp(*pAttr, uuidLen, pUuid))
|
||||
{
|
||||
*pAttrGroup = pGroup;
|
||||
return startHandle;
|
||||
}
|
||||
|
||||
/* special case of max handle value */
|
||||
if (startHandle == ATT_HANDLE_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
startHandle++;
|
||||
(*pAttr)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* no match found */
|
||||
return ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find the handle of the last attribute in a service group.
|
||||
*
|
||||
* \param startHandle Starting attribute handle of service.
|
||||
*
|
||||
* \return Service group end handle.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t attsFindServiceGroupEnd(uint16_t startHandle)
|
||||
{
|
||||
attsGroup_t *pGroup;
|
||||
attsAttr_t *pAttr;
|
||||
uint16_t prevHandle;
|
||||
uint8_t primSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PRIMARY_SERVICE)};
|
||||
uint8_t secSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_SECONDARY_SERVICE)};
|
||||
|
||||
/* special case for max handle */
|
||||
if (startHandle == ATT_HANDLE_MAX)
|
||||
{
|
||||
return ATT_HANDLE_MAX;
|
||||
}
|
||||
|
||||
prevHandle = startHandle;
|
||||
startHandle++;
|
||||
|
||||
/* iterate over attribute group list */
|
||||
for (pGroup = attsCb.groupQueue.pHead; pGroup != NULL; pGroup = pGroup->pNext)
|
||||
{
|
||||
/* if start handle is less than group start handle */
|
||||
if (startHandle < pGroup->startHandle)
|
||||
{
|
||||
/* set start handle to first handle in group */
|
||||
startHandle = pGroup->startHandle;
|
||||
}
|
||||
|
||||
/* if start handle within handle range of group */
|
||||
if (startHandle <= pGroup->endHandle)
|
||||
{
|
||||
/* compare uuid with each attribute in group */
|
||||
pAttr = &pGroup->pAttr[startHandle - pGroup->startHandle];
|
||||
while (startHandle <= pGroup->endHandle)
|
||||
{
|
||||
/* compare uuid in attribute to service uuids */
|
||||
if (attsUuidCmp(pAttr, ATT_16_UUID_LEN, primSvcUuid) ||
|
||||
attsUuidCmp(pAttr, ATT_16_UUID_LEN, secSvcUuid))
|
||||
{
|
||||
/* found next service; return handle of previous attribute */
|
||||
return prevHandle;
|
||||
}
|
||||
|
||||
/* special case of max handle value */
|
||||
if (startHandle == ATT_HANDLE_MAX)
|
||||
{
|
||||
return ATT_HANDLE_MAX;
|
||||
}
|
||||
|
||||
prevHandle = startHandle;
|
||||
startHandle++;
|
||||
pAttr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* next service not found; return 0xFFFF as the last handle in the database */
|
||||
return ATT_HANDLE_MAX;
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a read blob request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcReadBlobReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
uint16_t readLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handle and offset */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(handle, pPacket);
|
||||
BSTREAM_TO_UINT16(offset, pPacket);
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify permissions */
|
||||
if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
/* err has been set; fail */
|
||||
}
|
||||
/* verify offset */
|
||||
else if (offset > *pAttr->pLen)
|
||||
{
|
||||
err = ATT_ERR_OFFSET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call read callback if desired */
|
||||
if ((pAttr->settings & ATTS_SET_READ_CBACK) &&
|
||||
(pGroup->readCback != NULL))
|
||||
{
|
||||
err = (*pGroup->readCback)(pCcb->connId, handle, ATT_PDU_READ_BLOB_REQ, offset, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_READ, handle, pAttr->pValue);
|
||||
}
|
||||
|
||||
if (err == ATT_SUCCESS)
|
||||
{
|
||||
/* determine length of data to read */
|
||||
readLen = ((*pAttr->pLen - offset) < (pCcb->mtu - ATT_READ_BLOB_RSP_LEN)) ?
|
||||
(*pAttr->pLen - offset) : (pCcb->mtu - ATT_READ_BLOB_RSP_LEN);
|
||||
|
||||
/* Allocate response buffer */
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_READ_BLOB_RSP_LEN + readLen)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_BLOB_RSP);
|
||||
memcpy(p, (pAttr->pValue + offset), readLen);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (ATT_READ_BLOB_RSP_LEN + readLen), pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else invalid handle */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_BLOB_REQ, handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a find by type value request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcFindTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t *pUuid;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
uint16_t handle;
|
||||
uint16_t nextHandle;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handles and uuid; pPacket then points to the value in the request */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(startHandle, pPacket);
|
||||
BSTREAM_TO_UINT16(endHandle, pPacket);
|
||||
pUuid = pPacket;
|
||||
pPacket += ATT_16_UUID_LEN;
|
||||
|
||||
/* set len to the value length */
|
||||
len -= ATT_FIND_TYPE_REQ_LEN;
|
||||
|
||||
/* verify handles */
|
||||
if ((startHandle == 0) || (startHandle > endHandle))
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_FIND_TYPE_RSP);
|
||||
|
||||
/* find attributes with matching uuid within handle range */
|
||||
handle = startHandle;
|
||||
while ((handle = attsFindUuidInRange(handle, endHandle, ATT_16_UUID_LEN,
|
||||
pUuid, &pAttr, &pGroup)) != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* if value and length matches */
|
||||
if ((pAttr->permissions & ATTS_PERMIT_READ) &&
|
||||
((len == 0) ||
|
||||
((len == *pAttr->pLen) && (memcmp(pPacket, pAttr->pValue, len) == 0))))
|
||||
{
|
||||
/* if uuid in request is for primary service */
|
||||
if (pUuid[0] == UINT16_TO_BYTE0(ATT_UUID_PRIMARY_SERVICE) &&
|
||||
pUuid[1] == UINT16_TO_BYTE1(ATT_UUID_PRIMARY_SERVICE))
|
||||
{
|
||||
/* next handle is service group end handle */
|
||||
nextHandle = attsFindServiceGroupEnd(handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* for any other uuid next handle is same as found handle */
|
||||
nextHandle = handle;
|
||||
}
|
||||
|
||||
/* copy result into response buffer; first check if it fits */
|
||||
if ((p + (sizeof(uint16_t) * 2)) <= (pBuf + pCcb->mtu + L2C_PAYLOAD_START))
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT16_TO_BSTREAM(p, nextHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer full, we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* value doesn't match; still need to set next handle */
|
||||
else
|
||||
{
|
||||
nextHandle = handle;
|
||||
}
|
||||
|
||||
/* check if handle has reached end */
|
||||
if ((nextHandle >= endHandle) || (nextHandle == ATT_HANDLE_MAX))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* try next handle */
|
||||
handle = nextHandle + 1;
|
||||
}
|
||||
|
||||
/* if no results found set error, free buffer */
|
||||
if (p == (pBuf + L2C_PAYLOAD_START + 1))
|
||||
{
|
||||
WsfMsgFree(pBuf);
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer allocation failed */
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
/* set channel as busy for service discovery */
|
||||
attsDiscBusy(pCcb);
|
||||
|
||||
/* if no error send response, else send error */
|
||||
if (!err)
|
||||
{
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (p - (pBuf + L2C_PAYLOAD_START)), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_FIND_TYPE_REQ, startHandle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a read by type request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcReadTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
uint16_t handle;
|
||||
uint8_t uuidLen;
|
||||
uint8_t attLen;
|
||||
uint8_t cbackErr = ATT_SUCCESS;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handles; pPacket then points to the uuid */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(startHandle, pPacket);
|
||||
BSTREAM_TO_UINT16(endHandle, pPacket);
|
||||
|
||||
/* get and verify uuid length */
|
||||
uuidLen = len - ATT_READ_TYPE_REQ_LEN;
|
||||
if (!((uuidLen == ATT_16_UUID_LEN) || (uuidLen == ATT_128_UUID_LEN)))
|
||||
{
|
||||
err = ATT_ERR_INVALID_PDU;
|
||||
}
|
||||
/* verify handles */
|
||||
else if ((startHandle == 0) || (startHandle > endHandle))
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* find first attribute with matching uuid within handle range */
|
||||
handle = attsFindUuidInRange(startHandle, endHandle, uuidLen, pPacket, &pAttr, &pGroup);
|
||||
startHandle = handle;
|
||||
|
||||
if (handle == ATT_HANDLE_NONE)
|
||||
{
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
/* check permissions */
|
||||
else if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
/* err is set above */
|
||||
}
|
||||
/* check if read callback should be called */
|
||||
else if ((pAttr->settings & ATTS_SET_READ_CBACK) &&
|
||||
(pGroup->readCback != NULL))
|
||||
{
|
||||
err = (*pGroup->readCback)(pCcb->connId, handle, ATT_PDU_READ_TYPE_REQ, 0, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_READ, handle, pAttr->pValue);
|
||||
}
|
||||
|
||||
if (err == ATT_SUCCESS)
|
||||
{
|
||||
/* Check if UUID is the Database Hash Characteristic Value and the value is being
|
||||
* re-calculated
|
||||
*/
|
||||
if ((memcmp(pPacket, attGattDbhChUuid, ATT_16_UUID_LEN) == 0) && attsCsfGetHashUpdateStatus())
|
||||
{
|
||||
/* Store info and return */
|
||||
pCcb->pPendDbHashRsp = WsfBufAlloc(sizeof(attPendDbHashRsp_t));
|
||||
if (pCcb->pPendDbHashRsp)
|
||||
{
|
||||
pCcb->pPendDbHashRsp->startHandle = startHandle;
|
||||
pCcb->pPendDbHashRsp->handle = handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_TYPE_REQ, startHandle, ATT_ERR_RESOURCES);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_TYPE_RSP);
|
||||
|
||||
/* get length of this first attribute */
|
||||
attLen = (*pAttr->pLen < (pCcb->mtu - ATT_READ_TYPE_RSP_LEN - sizeof(uint16_t))) ?
|
||||
*pAttr->pLen : (pCcb->mtu - ATT_READ_TYPE_RSP_LEN - sizeof(uint16_t));
|
||||
|
||||
/* set length parameter in response message */
|
||||
UINT8_TO_BSTREAM(p, attLen + sizeof(uint16_t));
|
||||
|
||||
/* copy result to response message */
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pAttr->pValue, attLen);
|
||||
p += attLen;
|
||||
|
||||
/* look for additional attributes */
|
||||
handle++;
|
||||
while ((handle = attsFindUuidInRange(handle, endHandle, uuidLen,
|
||||
pPacket, &pAttr, &pGroup)) != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* call read callback if desired */
|
||||
if ((pAttr->settings & ATTS_SET_READ_CBACK) &&
|
||||
(pGroup->readCback != NULL))
|
||||
{
|
||||
cbackErr = (*pGroup->readCback)(pCcb->connId, handle, ATT_PDU_READ_TYPE_REQ, 0, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
cbackErr = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_READ, handle, pAttr->pValue);
|
||||
}
|
||||
|
||||
/* verify no error from read callback
|
||||
* verify length is same as first found attribute
|
||||
* verify attribute permissions
|
||||
*/
|
||||
if ((cbackErr == ATT_SUCCESS) &&
|
||||
(*pAttr->pLen == attLen) &&
|
||||
(attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions) == ATT_SUCCESS))
|
||||
{
|
||||
/* copy result into response buffer; first check if it fits */
|
||||
if ((p + attLen + sizeof(uint16_t)) <= (pBuf + pCcb->mtu + L2C_PAYLOAD_START))
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pAttr->pValue, attLen);
|
||||
p += attLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer full, we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* problem with read callback, length, or permissions; send what we've got so far */
|
||||
break;
|
||||
}
|
||||
|
||||
/* special case of handle at max range */
|
||||
if (handle == ATT_HANDLE_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* try next handle */
|
||||
if (++handle > endHandle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer allocation failed */
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if no error send response, else send error */
|
||||
if (!err)
|
||||
{
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (p - (pBuf + L2C_PAYLOAD_START)), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_TYPE_REQ, startHandle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a read multiple request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcReadMultReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
uint8_t *pEnd;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t handle = ATT_HANDLE_NONE;
|
||||
uint16_t readLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* points to end of payload */
|
||||
pEnd = pPacket + L2C_PAYLOAD_START + len;
|
||||
|
||||
/* points to first handle */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_MULT_RSP);
|
||||
|
||||
/* while there are handles remaining and there is space in response buffer */
|
||||
while (pPacket < pEnd)
|
||||
{
|
||||
/* parse handle */
|
||||
BSTREAM_TO_UINT16(handle, pPacket);
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) == NULL)
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* verify permissions */
|
||||
if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* call read callback if desired */
|
||||
if ((pAttr->settings & ATTS_SET_READ_CBACK) &&
|
||||
(pGroup->readCback != NULL))
|
||||
{
|
||||
err = (*pGroup->readCback)(pCcb->connId, handle, ATT_PDU_READ_MULT_REQ, 0, pAttr);
|
||||
if (err != ATT_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_READ, handle, pAttr->pValue);
|
||||
if (err != ATT_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p < (pBuf + pCcb->mtu + L2C_PAYLOAD_START))
|
||||
{
|
||||
/* calculate remaining space in response buffer */
|
||||
readLen = (pBuf + pCcb->mtu + L2C_PAYLOAD_START) - p;
|
||||
|
||||
/* actual length is minimum of remaining space and attribute length */
|
||||
readLen = (*pAttr->pLen < readLen) ? *pAttr->pLen : readLen;
|
||||
|
||||
/* copy attribute to response buffer */
|
||||
memcpy(p, pAttr->pValue, readLen);
|
||||
p += readLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer allocation failed */
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
|
||||
/* if no error send response, else send error */
|
||||
if (!err)
|
||||
{
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (p - (pBuf + L2C_PAYLOAD_START)), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* discard response buffer */
|
||||
if (pBuf != NULL)
|
||||
{
|
||||
WsfMsgFree(pBuf);
|
||||
}
|
||||
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_MULT_REQ, handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a read group by type request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcReadGroupTypeReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf = NULL;
|
||||
uint8_t *p = NULL;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint16_t startHandle;
|
||||
uint16_t endHandle;
|
||||
uint16_t handle;
|
||||
uint8_t uuidLen;
|
||||
uint8_t attLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
uint8_t primSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PRIMARY_SERVICE)};
|
||||
|
||||
/* parse handles; pPacket then points to the uuid */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(startHandle, pPacket);
|
||||
BSTREAM_TO_UINT16(endHandle, pPacket);
|
||||
|
||||
/* get and verify uuid length */
|
||||
uuidLen = len - ATT_READ_GROUP_TYPE_REQ_LEN;
|
||||
if (!((uuidLen == ATT_16_UUID_LEN) || (uuidLen == ATT_128_UUID_LEN)))
|
||||
{
|
||||
err = ATT_ERR_INVALID_PDU;
|
||||
}
|
||||
/* verify handles */
|
||||
else if ((startHandle == 0) || (startHandle > endHandle))
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
/* verify uuid is primary service group */
|
||||
else if (!attsUuid16Cmp(primSvcUuid, uuidLen, pPacket))
|
||||
{
|
||||
err = ATT_ERR_GROUP_TYPE;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* find first attribute with matching uuid within handle range */
|
||||
handle = attsFindUuidInRange(startHandle, endHandle, uuidLen, pPacket, &pAttr, &pGroup);
|
||||
|
||||
if (handle == ATT_HANDLE_NONE)
|
||||
{
|
||||
err = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
/* check permissions */
|
||||
else if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
startHandle = handle; /* this handle is returned in error response */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allocate max size buffer for response */
|
||||
if ((pBuf = attMsgAlloc(pCcb->mtu + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_READ_GROUP_TYPE_RSP);
|
||||
|
||||
/* get length of this first attribute */
|
||||
attLen = (*pAttr->pLen < (pCcb->mtu - ATT_READ_GROUP_TYPE_RSP_LEN - (2 * sizeof(uint16_t)))) ?
|
||||
*pAttr->pLen : (pCcb->mtu - ATT_READ_GROUP_TYPE_RSP_LEN - (2 * sizeof(uint16_t)));
|
||||
|
||||
/* set length parameter in response message */
|
||||
UINT8_TO_BSTREAM(p, attLen + (2 * sizeof(uint16_t)));
|
||||
|
||||
/* copy handle to response message */
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
/* get end group handle and copy it to response message */
|
||||
handle = attsFindServiceGroupEnd(handle);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
/* copy the attribute value to response message */
|
||||
memcpy(p, pAttr->pValue, attLen);
|
||||
p += attLen;
|
||||
|
||||
/* look for additional attributes */
|
||||
while (TRUE)
|
||||
{
|
||||
/* special case of handle at max range */
|
||||
if (handle == ATT_HANDLE_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* increment to next handle */
|
||||
if (++handle > endHandle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* find next matching handle */
|
||||
if ((handle = attsFindUuidInRange(handle, endHandle, uuidLen,
|
||||
pPacket, &pAttr, &pGroup)) == ATT_HANDLE_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* verify length is same as first found attribute
|
||||
* verify attribute permissions
|
||||
*/
|
||||
if ((*pAttr->pLen == attLen) &&
|
||||
(attsPermissions(pCcb->connId, ATTS_PERMIT_READ,
|
||||
handle, pAttr->permissions) == ATT_SUCCESS))
|
||||
{
|
||||
/* copy result into response buffer; first check if it fits */
|
||||
if ((p + attLen + (2 * sizeof(uint16_t))) <=
|
||||
(pBuf + pCcb->mtu + L2C_PAYLOAD_START))
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
handle = attsFindServiceGroupEnd(handle);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
memcpy(p, pAttr->pValue, attLen);
|
||||
p += attLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer full, we're done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* problem with either length or permissions; send what we've got so far */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* buffer allocation failed */
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set channel as busy for service discovery */
|
||||
attsDiscBusy(pCcb);
|
||||
|
||||
/* if no error send response, else send error */
|
||||
if (!err)
|
||||
{
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (p - (pBuf + L2C_PAYLOAD_START)), pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_READ_GROUP_TYPE_REQ, startHandle, err);
|
||||
}
|
||||
}
|
||||
Vendored
+402
@@ -0,0 +1,402 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server signed PDU processing functions.
|
||||
*
|
||||
* 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_buf.h"
|
||||
#include "wsf_queue.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
#include "att_sign.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Signed data buffer structure */
|
||||
typedef struct attsSignBuf_tag
|
||||
{
|
||||
struct attsSignBuf_tag *pNext; /* pointer to next in queue */
|
||||
attCcb_t *pCcb; /* ATT CCB associated with the packet */
|
||||
uint16_t handle; /* ATT handle */
|
||||
uint16_t writeLen; /* length of data to write */
|
||||
dmConnId_t connId; /* Connection ID associated with the packet */
|
||||
uint8_t packet[1]; /* packet */
|
||||
} attsSignBuf_t;
|
||||
|
||||
/* ATTS signed PDU connection control block */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t signCounter; /* sign counter for this connection */
|
||||
uint8_t *pCsrk; /* signing key for this connection */
|
||||
attsSignBuf_t *pBuf; /* current data being processed */
|
||||
bool_t authenticated; /* Indicate if the CSRK is authenticated or not */
|
||||
} attsSignCcb_t;
|
||||
|
||||
/* ATTS signed PDU control block */
|
||||
typedef struct
|
||||
{
|
||||
attsSignCcb_t ccb[DM_CONN_MAX];
|
||||
wsfQueue_t msgQueue;
|
||||
} attsSignCb_t;
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static attsSignCb_t attsSignCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the signing connection control block for the connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static attsSignCcb_t *attsSignCcbByConnId(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
return &attsSignCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start processing of data for signed write.
|
||||
*
|
||||
* \param pCcb Signed data CCB.
|
||||
* \param pBuf Signed data buffer structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsSignedWriteStart(attsSignCcb_t *pCcb, attsSignBuf_t *pBuf)
|
||||
{
|
||||
if (pCcb->pCsrk != NULL)
|
||||
{
|
||||
uint16_t cmacTxtLen = pBuf->writeLen + ATT_WRITE_CMD_LEN + sizeof(uint32_t);
|
||||
uint8_t *pCmacTxt = WsfBufAlloc(cmacTxtLen);
|
||||
|
||||
pCcb->pBuf = pBuf;
|
||||
|
||||
if (pCmacTxt)
|
||||
{
|
||||
uint8_t revPeerCsrk[SEC_CMAC_KEY_LEN] = {0};
|
||||
|
||||
WStrReverseCpy(revPeerCsrk, pCcb->pCsrk, SEC_CMAC_KEY_LEN);
|
||||
WStrReverseCpy(pCmacTxt, pBuf->packet, cmacTxtLen);
|
||||
|
||||
if (SecCmac(revPeerCsrk, pCmacTxt, cmacTxtLen, attCb.handlerId,
|
||||
pBuf->connId, ATTS_MSG_SIGN_CMAC_CMPL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WsfBufFree(pCmacTxt);
|
||||
}
|
||||
}
|
||||
|
||||
/* no CSRK-- free buffer */
|
||||
WsfBufFree(pBuf);
|
||||
ATT_TRACE_WARN0("ATTS CSRK not set");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a signed write command PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsProcSignedWrite(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
attsSignCcb_t *pSignCcb;
|
||||
attsSignBuf_t *pBuf;
|
||||
uint16_t handle;
|
||||
uint16_t writeLen;
|
||||
|
||||
/* parse handle, calculate write length */
|
||||
p = pPacket + L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(handle, p);
|
||||
writeLen = len - ATT_SIGNED_WRITE_CMD_LEN;
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify signed write is permitted */
|
||||
if ((pAttr->settings & ATTS_SET_ALLOW_SIGNED) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify that csrk is present */
|
||||
if (attsSignCcbByConnId(pCcb->connId)->pCsrk == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify basic permissions */
|
||||
if ((pAttr->permissions & (ATTS_PERMIT_WRITE | ATTS_PERMIT_WRITE_ENC)) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify authentication */
|
||||
if ((pAttr->permissions & ATTS_PERMIT_WRITE_AUTH) &&
|
||||
(attsSignCcbByConnId(pCcb->connId)->authenticated == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: authorization not verified at this stage as it is reserved for lesc
|
||||
writes; authorization occurs latter when the write cb is called */
|
||||
|
||||
/* verify write length, fixed length */
|
||||
if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) == 0) &&
|
||||
(writeLen != pAttr->maxLen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify write length, variable length */
|
||||
if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0) &&
|
||||
(writeLen > pAttr->maxLen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate buffer to store packet and parameters */
|
||||
if ((pBuf = WsfBufAlloc(sizeof(attsSignBuf_t) - 1 + len)) != NULL)
|
||||
{
|
||||
/* initialize buffer */
|
||||
pBuf->pCcb = pCcb;
|
||||
pBuf->handle = handle;
|
||||
pBuf->writeLen = writeLen;
|
||||
pBuf->connId = pCcb->connId;
|
||||
memcpy(pBuf->packet, (pPacket + L2C_PAYLOAD_START), len);
|
||||
|
||||
/* check if a signed write is already in progress */
|
||||
pSignCcb = attsSignCcbByConnId(pCcb->connId);
|
||||
|
||||
if (pSignCcb->pBuf != NULL)
|
||||
{
|
||||
/* signed write in progress; queue packet */
|
||||
WsfQueueEnq(&attsSignCb.msgQueue, pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start signed data processing */
|
||||
attsSignedWriteStart(pSignCcb, pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Message handler callback for ATTS signed PDU processing.
|
||||
*
|
||||
* \param pMsg ATTS message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void attsSignMsgCback(secCmacMsg_t *pMsg)
|
||||
{
|
||||
attsSignCcb_t *pCcb;
|
||||
attsSignBuf_t *pBuf;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint32_t signCounter;
|
||||
|
||||
if (pMsg->hdr.event == ATTS_MSG_SIGN_CMAC_CMPL)
|
||||
{
|
||||
uint8_t signature[ATT_CMAC_RESULT_LEN] = {0};
|
||||
|
||||
pCcb = attsSignCcbByConnId((dmConnId_t) pMsg->hdr.param);
|
||||
pBuf = pCcb->pBuf;
|
||||
|
||||
WStrReverseCpy(signature, pMsg->pCiphertext, ATT_CMAC_RESULT_LEN);
|
||||
|
||||
/* if signature ok */
|
||||
if (memcmp(signature, pBuf->packet + pBuf->writeLen + ATT_WRITE_CMD_LEN + 4, ATT_CMAC_RESULT_LEN) == 0)
|
||||
{
|
||||
/* check sign counter */
|
||||
BYTES_TO_UINT32(signCounter, (pBuf->packet + pBuf->writeLen + ATT_WRITE_CMD_LEN));
|
||||
|
||||
if (signCounter >= pCcb->signCounter)
|
||||
{
|
||||
/* update sign counter */
|
||||
pCcb->signCounter = signCounter + 1;
|
||||
|
||||
/* perform write: */
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(pBuf->handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* if write callback is desired */
|
||||
if ((pAttr->settings & ATTS_SET_WRITE_CBACK) &&
|
||||
(pGroup->writeCback != NULL))
|
||||
{
|
||||
/* write value via write callback */
|
||||
(*pGroup->writeCback)(pBuf->connId, pBuf->handle, ATT_PDU_SIGNED_WRITE_CMD,
|
||||
0, pBuf->writeLen, (pBuf->packet + ATT_WRITE_CMD_LEN), pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
(*attsCb.cccCback)(pBuf->connId, ATT_METHOD_WRITE, pBuf->handle,
|
||||
(pBuf->packet + ATT_WRITE_CMD_LEN));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write attribute value */
|
||||
memcpy(pAttr->pValue, (pBuf->packet + ATT_WRITE_CMD_LEN), pBuf->writeLen);
|
||||
|
||||
/* write the length if variable length attribute */
|
||||
if ((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0)
|
||||
{
|
||||
*(pAttr->pLen) = pBuf->writeLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN0("Signed write counter failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ATT_TRACE_WARN0("Signed write sig failed");
|
||||
}
|
||||
|
||||
/* we're done-- free parameter buffer */
|
||||
WsfBufFree(pBuf);
|
||||
|
||||
WsfBufFree(pMsg->pPlainText);
|
||||
|
||||
/* process next signed write in queue, if any */
|
||||
if ((pBuf = WsfQueueDeq(&attsSignCb.msgQueue)) != NULL)
|
||||
{
|
||||
pCcb = attsSignCcbByConnId(pBuf->connId);
|
||||
attsSignedWriteStart(pCcb, pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->pBuf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize ATT server for data signing.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsSignInit(void)
|
||||
{
|
||||
/* initialize control block */
|
||||
WSF_QUEUE_INIT(&attsSignCb.msgQueue);
|
||||
|
||||
/* set up callback interface */
|
||||
attsCb.signMsgCback = (attMsgHandler_t) attsSignMsgCback;
|
||||
attsProcFcnTbl[ATT_METHOD_SIGNED_WRITE_CMD] = attsProcSignedWrite;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the peer's data signing key on this connection. This function
|
||||
* is typically called from the ATT connection callback when the connection is
|
||||
* established. The caller is responsible for maintaining the memory that
|
||||
* contains the key.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param pCsrk Pointer to data signing key (CSRK).
|
||||
* \param authenticated True if CSRK is authenticated and false otherwise.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsSetCsrk(dmConnId_t connId, uint8_t *pCsrk, bool_t authenticated)
|
||||
{
|
||||
attsSignCcbByConnId(connId)->pCsrk = pCsrk;
|
||||
attsSignCcbByConnId(connId)->authenticated = authenticated;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the peer's sign counter on this connection. This function
|
||||
* is typically called from the ATT connection callback when the connection is
|
||||
* established. ATT maintains the value of the sign counter internally and
|
||||
* sets the value when a signed packet is successfully received.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param signCounter Sign counter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsSetSignCounter(dmConnId_t connId, uint32_t signCounter)
|
||||
{
|
||||
attsSignCcbByConnId(connId)->signCounter = signCounter;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the current value peer's sign counter on this connection. This function
|
||||
* is typically called from the ATT connection callback when the connection is
|
||||
* closed so the application can store the sign counter for use on future
|
||||
* connections.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
*
|
||||
* \return Sign counter.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t AttsGetSignCounter(dmConnId_t connId)
|
||||
{
|
||||
return attsSignCcbByConnId(connId)->signCounter;
|
||||
}
|
||||
Vendored
+463
@@ -0,0 +1,463 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief ATT server write PDU processing functions.
|
||||
*
|
||||
* 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_trace.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "att_main.h"
|
||||
#include "atts_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Queued prepare write structure */
|
||||
typedef struct attsPrepWrite_tag
|
||||
{
|
||||
struct attsPrepWrite_tag *pNext;
|
||||
uint16_t writeLen;
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
uint8_t packet[1];
|
||||
} attsPrepWrite_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute a queued prepared write operation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pPrep Pointer to buffer containing prepared write.
|
||||
*
|
||||
* \return ATT_SUCCESS or failure status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t attsExecPrepWrite(attCcb_t *pCcb, attsPrepWrite_t *pPrep)
|
||||
{
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
p = pPrep->packet;
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(pPrep->handle, &pGroup)) == NULL)
|
||||
{
|
||||
/* handle not found; only possible unless handle was removed */
|
||||
err = ATT_ERR_UNLIKELY;
|
||||
}
|
||||
/* verify write permissions (in theory could have changed) */
|
||||
else if (!(pAttr->permissions & ATTS_PERMIT_WRITE))
|
||||
{
|
||||
err = ATT_ERR_WRITE;
|
||||
}
|
||||
/* if write callback is desired */
|
||||
else if ((pAttr->settings & ATTS_SET_WRITE_CBACK) &&
|
||||
(pGroup->writeCback != NULL))
|
||||
{
|
||||
|
||||
/* write callback performs the write */
|
||||
err = (*pGroup->writeCback)(pCcb->connId, pPrep->handle, ATT_PDU_EXEC_WRITE_REQ,
|
||||
pPrep->offset, pPrep->writeLen, p, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_WRITE, pPrep->handle, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* perform write; parameters have already been vetted by previous procedures */
|
||||
|
||||
/* write attribute value */
|
||||
memcpy((pAttr->pValue + pPrep->offset), p, pPrep->writeLen);
|
||||
|
||||
/* write the length if variable length attribute */
|
||||
if ((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0)
|
||||
{
|
||||
*(pAttr->pLen) = pPrep->writeLen + pPrep->offset;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write request or write command PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcWrite(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint8_t opcode;
|
||||
uint16_t handle;
|
||||
uint16_t writeLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse opcode handle, calculate write length */
|
||||
pPacket += L2C_PAYLOAD_START;
|
||||
BSTREAM_TO_UINT8(opcode, pPacket);
|
||||
BSTREAM_TO_UINT16(handle, pPacket);
|
||||
writeLen = len - ATT_WRITE_REQ_LEN;
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify permissions */
|
||||
if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_WRITE,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
/* err has been set; fail */
|
||||
}
|
||||
/* verify write length, fixed length */
|
||||
else if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) == 0) &&
|
||||
(writeLen != pAttr->maxLen))
|
||||
{
|
||||
err = ATT_ERR_LENGTH;
|
||||
}
|
||||
/* verify write length, variable length */
|
||||
else if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0) &&
|
||||
(writeLen > pAttr->maxLen))
|
||||
{
|
||||
err = ATT_ERR_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if write callback is desired */
|
||||
if ((pAttr->settings & ATTS_SET_WRITE_CBACK) &&
|
||||
(pGroup->writeCback != NULL))
|
||||
{
|
||||
err = (*pGroup->writeCback)(pCcb->connId, handle, opcode, 0, writeLen,
|
||||
pPacket, pAttr);
|
||||
}
|
||||
/* else check if CCC */
|
||||
else if ((pAttr->settings & ATTS_SET_CCC) && (attsCb.cccCback != NULL))
|
||||
{
|
||||
err = (*attsCb.cccCback)(pCcb->connId, ATT_METHOD_WRITE, handle, pPacket);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write attribute value */
|
||||
memcpy(pAttr->pValue, pPacket, writeLen);
|
||||
|
||||
/* write the length if variable length attribute */
|
||||
if ((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0)
|
||||
{
|
||||
*(pAttr->pLen) = writeLen;
|
||||
}
|
||||
}
|
||||
|
||||
/* if success and write req allocate response buffer */
|
||||
if (err == ATT_SUCCESS && opcode == ATT_PDU_WRITE_REQ)
|
||||
{
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_WRITE_RSP_LEN)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_WRITE_RSP);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, ATT_WRITE_RSP_LEN, pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else attribute not found */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
|
||||
/* send error response for write req only */
|
||||
if (err && (opcode == ATT_PDU_WRITE_REQ))
|
||||
{
|
||||
if (err == ATT_RSP_PENDING)
|
||||
{
|
||||
/* set response pending */
|
||||
pCcb->control |= ATT_CCB_STATUS_RSP_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_WRITE_REQ, handle, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a prepare write request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcPrepWriteReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
attsPrepWrite_t *pPrep;
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
uint16_t writeLen;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
/* parse handle and offset, calculate write length */
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
BSTREAM_TO_UINT16(handle, pPacket);
|
||||
BSTREAM_TO_UINT16(offset, pPacket);
|
||||
writeLen = len - ATT_PREP_WRITE_REQ_LEN; /* length of value being written */
|
||||
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(handle, &pGroup)) == NULL)
|
||||
{
|
||||
/* attribute not found */
|
||||
err = ATT_ERR_HANDLE;
|
||||
}
|
||||
/* verify permissions */
|
||||
else if ((err = attsPermissions(pCcb->connId, ATTS_PERMIT_WRITE,
|
||||
handle, pAttr->permissions)) != ATT_SUCCESS)
|
||||
{
|
||||
/* err has been set; fail */
|
||||
}
|
||||
/* verify offset is allowed */
|
||||
else if ((offset != 0) && ((pAttr->settings & ATTS_SET_ALLOW_OFFSET) == 0))
|
||||
{
|
||||
err = ATT_ERR_NOT_LONG;
|
||||
}
|
||||
/* verify write length, fixed length */
|
||||
else if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) == 0) &&
|
||||
(writeLen != pAttr->maxLen))
|
||||
{
|
||||
err = ATT_ERR_LENGTH;
|
||||
}
|
||||
/* verify prepare write queue limit not reached */
|
||||
else if (WsfQueueCount(&pCcb->prepWriteQueue) >= pAttCfg->numPrepWrites)
|
||||
{
|
||||
err = ATT_ERR_QUEUE_FULL;
|
||||
}
|
||||
/* allocate new buffer to hold prepared write */
|
||||
else if ((pPrep = WsfBufAlloc(sizeof(attsPrepWrite_t) - 1 + writeLen)) == NULL)
|
||||
{
|
||||
err = ATT_ERR_RESOURCES;
|
||||
}
|
||||
else if ((pAttr->settings & ATTS_SET_WRITE_CBACK) &&
|
||||
(pGroup->writeCback != NULL))
|
||||
{
|
||||
err = (*pGroup->writeCback)(pCcb->connId, handle, ATT_PDU_PREP_WRITE_REQ, 0, writeLen,
|
||||
pPacket, pAttr);
|
||||
}
|
||||
|
||||
if (err == ATT_SUCCESS)
|
||||
{
|
||||
/* copy data to new buffer and queue it */
|
||||
pPrep->writeLen = writeLen;
|
||||
pPrep->handle = handle;
|
||||
pPrep->offset = offset;
|
||||
memcpy(pPrep->packet, pPacket, writeLen);
|
||||
WsfQueueEnq(&pCcb->prepWriteQueue, pPrep);
|
||||
|
||||
/* allocate response buffer */
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_PREP_WRITE_RSP_LEN + writeLen)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_PREP_WRITE_RSP);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT16_TO_BSTREAM(p, offset);
|
||||
memcpy(p, pPacket, writeLen);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, (ATT_PREP_WRITE_RSP_LEN + writeLen), pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_PREP_WRITE_REQ, handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process an execute write request PDU.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void attsProcExecWriteReq(attCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
attsPrepWrite_t *pPrep;
|
||||
attsAttr_t *pAttr;
|
||||
attsGroup_t *pGroup;
|
||||
uint8_t err = ATT_SUCCESS;
|
||||
|
||||
pPacket += L2C_PAYLOAD_START + ATT_HDR_LEN;
|
||||
|
||||
/* if cancelling all prepared writes */
|
||||
if (*pPacket == ATT_EXEC_WRITE_CANCEL)
|
||||
{
|
||||
/* free all queued buffers */
|
||||
attsClearPrepWrites(pCcb);
|
||||
}
|
||||
/* else writing all prepared writes */
|
||||
else if (*pPacket == ATT_EXEC_WRITE_ALL)
|
||||
{
|
||||
/* iterate over prepare write queue and verify offset and length */
|
||||
for (pPrep = pCcb->prepWriteQueue.pHead; pPrep != NULL; pPrep = pPrep->pNext)
|
||||
{
|
||||
/* find attribute */
|
||||
if ((pAttr = attsFindByHandle(pPrep->handle, &pGroup)) != NULL)
|
||||
{
|
||||
/* verify offset */
|
||||
if (pPrep->offset > pAttr->maxLen)
|
||||
{
|
||||
err = ATT_ERR_OFFSET;
|
||||
}
|
||||
/* verify write length with offset */
|
||||
else if ((pPrep->writeLen + pPrep->offset) > pAttr->maxLen)
|
||||
{
|
||||
err = ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
/* verification failed; discard all prepared writes */
|
||||
attsClearPrepWrites(pCcb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if length and offset checks ok then write all buffers in queue */
|
||||
if (err == ATT_SUCCESS)
|
||||
{
|
||||
/* for each buffer */
|
||||
while ((pPrep = WsfQueueDeq(&pCcb->prepWriteQueue)) != NULL)
|
||||
{
|
||||
/* write buffer */
|
||||
if ((err = attsExecPrepWrite(pCcb, pPrep)) != ATT_SUCCESS)
|
||||
{
|
||||
/* write failed; discard remaining prepared writes */
|
||||
attsClearPrepWrites(pCcb);
|
||||
}
|
||||
|
||||
/* free buffer */
|
||||
WsfBufFree(pPrep);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* else unknown operation */
|
||||
else
|
||||
{
|
||||
err = ATT_ERR_INVALID_PDU;
|
||||
}
|
||||
|
||||
/* send response or error response */
|
||||
if (err)
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_EXEC_WRITE_REQ, 0, err);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_EXEC_WRITE_RSP_LEN)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_EXEC_WRITE_RSP);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, ATT_EXEC_WRITE_RSP_LEN, pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a response to a pending write request. For use with ATT_RSP_PENDING.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param status Status of the write request.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note When a higher layer returns ATT_RSP_PENDING to an ATT write callback indicating the
|
||||
* response status is pending, the higher layer must subsequently call this function
|
||||
* with the status of the write request.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AttsContinueWriteReq(dmConnId_t connId, uint16_t handle, uint8_t status)
|
||||
{
|
||||
attCcb_t *pCcb;
|
||||
uint8_t *pBuf;
|
||||
uint8_t *p;
|
||||
|
||||
/* get connection cb for this handle */
|
||||
if ((pCcb = attCcbByConnId(connId)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear response pending */
|
||||
pCcb->control &= ~ATT_CCB_STATUS_RSP_PENDING;
|
||||
|
||||
if (status)
|
||||
{
|
||||
attsErrRsp(pCcb->handle, ATT_PDU_WRITE_REQ, handle, status);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pBuf = attMsgAlloc(L2C_PAYLOAD_START + ATT_WRITE_RSP_LEN)) != NULL)
|
||||
{
|
||||
/* build and send PDU */
|
||||
p = pBuf + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, ATT_PDU_WRITE_RSP);
|
||||
|
||||
L2cDataReq(L2C_CID_ATT, pCcb->handle, ATT_WRITE_RSP_LEN, pBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+112
@@ -0,0 +1,112 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Stack configuration.
|
||||
*
|
||||
* 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 "cfg_stack.h"
|
||||
#include "hci_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "l2c_api.h"
|
||||
#include "att_api.h"
|
||||
#include "smp_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
HCI
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
DM
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Configuration structure */
|
||||
const dmCfg_t dmCfg =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
/* Configuration pointer */
|
||||
dmCfg_t *pDmCfg = (dmCfg_t *) &dmCfg;
|
||||
|
||||
/**************************************************************************************************
|
||||
L2C
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Configuration structure */
|
||||
const l2cCfg_t l2cCfg =
|
||||
{
|
||||
30 /* Request timeout in seconds */
|
||||
};
|
||||
|
||||
/* Configuration pointer */
|
||||
l2cCfg_t *pL2cCfg = (l2cCfg_t *) &l2cCfg;
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Configuration structure */
|
||||
const attCfg_t attCfg =
|
||||
{
|
||||
15, /* ATT server service discovery connection idle timeout in seconds */
|
||||
480,//LL_MAX_DATA_LEN_ABS_MAX - 4, /* desired ATT MTU */
|
||||
ATT_MAX_TRANS_TIMEOUT, /* transcation timeout in seconds */
|
||||
4 /* number of queued prepare writes supported by server */
|
||||
};
|
||||
|
||||
/* Configuration pointer */
|
||||
attCfg_t *pAttCfg = (attCfg_t *) &attCfg;
|
||||
|
||||
/**************************************************************************************************
|
||||
SMP
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Configuration structure */
|
||||
const smpCfg_t smpCfg =
|
||||
{
|
||||
500, /* 'Repeated attempts' timeout in msec */
|
||||
SMP_IO_NO_IN_NO_OUT, /* I/O Capability */
|
||||
7, /* Minimum encryption key length */
|
||||
16, /* Maximum encryption key length */
|
||||
1, /* Attempts to trigger 'repeated attempts' timeout */
|
||||
0, /* Device authentication requirements */
|
||||
64000, /* Maximum repeated attempts timeout in msec */
|
||||
64000, /* Time msec before attemptExp decreases */
|
||||
2 /* Repeated attempts multiplier exponent */
|
||||
};
|
||||
|
||||
/* Configuration pointer */
|
||||
smpCfg_t *pSmpCfg = (smpCfg_t *) &smpCfg;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get Stack version number.
|
||||
*
|
||||
* \param pVersion output parameter for version number.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void StackGetVersionNumber(const char **pVersion)
|
||||
{
|
||||
*pVersion = STACK_VERSION;
|
||||
}
|
||||
Vendored
+170
@@ -0,0 +1,170 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Stack configuration.
|
||||
*
|
||||
* 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 CFG_STACK_H
|
||||
#define CFG_STACK_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup STACK_INIT
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
STACK VERSION
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Stack release version label */
|
||||
#define STACK_VERSION ((const char *)"r19.02\n")
|
||||
/*! \brief Stack release version number */
|
||||
#define STACK_VER_NUM 0x1302 /* Default value. Auto-generated by builder. */
|
||||
|
||||
/**************************************************************************************************
|
||||
HCI
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name HCI Vendor Specific targets
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define HCI_VS_GENERIC 0
|
||||
#define HCI_VS_EMM 1
|
||||
|
||||
/*! \brief Vendor specific target configuration */
|
||||
#ifndef HCI_VS_TARGET
|
||||
#define HCI_VS_TARGET HCI_VS_GENERIC
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/** \name HCI Tx Data Tailroom
|
||||
* Extra byte allocation required for LL operations (i.e. MIC) in single-chip implementation
|
||||
*/
|
||||
/**@{*/
|
||||
#ifndef HCI_TX_DATA_TAILROOM
|
||||
/*! \brief Tx data tailroom. */
|
||||
#define HCI_TX_DATA_TAILROOM 0
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
DM
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name DM Configuration
|
||||
* DM build-time configuration parameters
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Maximum number of connections */
|
||||
#ifndef DM_CONN_MAX
|
||||
#define DM_CONN_MAX 3
|
||||
#endif
|
||||
|
||||
/*! \brief Maximum number of periodic advertising synchronizations */
|
||||
#ifndef DM_SYNC_MAX
|
||||
#define DM_SYNC_MAX 1
|
||||
#endif
|
||||
|
||||
/*! \brief Number of supported advertising sets: must be set to 1 for legacy advertising */
|
||||
#ifndef DM_NUM_ADV_SETS
|
||||
#define DM_NUM_ADV_SETS 1
|
||||
#endif
|
||||
|
||||
/*! \brief Number of scanner and initiator PHYs (LE 1M, LE 2M and LE Coded): must be set to 1 for
|
||||
legacy scanner and initiator */
|
||||
#ifndef DM_NUM_PHYS
|
||||
#define DM_NUM_PHYS 1
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
L2C
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name L2CAP Configuration
|
||||
* L2CAP build-time configuration parameters
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Maximum number of connection oriented channels */
|
||||
#ifndef L2C_COC_CHAN_MAX
|
||||
#define L2C_COC_CHAN_MAX 8
|
||||
#endif
|
||||
|
||||
/*! \brief Maximum number of connection oriented channel registered clients */
|
||||
#ifndef L2C_COC_REG_MAX
|
||||
#define L2C_COC_REG_MAX 4
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name ATT Configuration
|
||||
* ATT build-time configuration parameters
|
||||
*/
|
||||
/**@{*/
|
||||
/*! \brief Maximum number of simultaneous ATT write commands */
|
||||
#ifndef ATT_NUM_SIMUL_WRITE_CMD
|
||||
#define ATT_NUM_SIMUL_WRITE_CMD 1
|
||||
#endif
|
||||
|
||||
/*! \brief Maximum number of simultaneous ATT notifications */
|
||||
#ifndef ATT_NUM_SIMUL_NTF
|
||||
#define ATT_NUM_SIMUL_NTF 1
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
SMP
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name SMP Configuration
|
||||
* SMP build-time configuration parameters
|
||||
*/
|
||||
/**@{*/
|
||||
/*! Max number of devices in the database */
|
||||
#ifndef SMP_DB_MAX_DEVICES
|
||||
#define SMP_DB_MAX_DEVICES 3
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get Stack version number.
|
||||
*
|
||||
* \param pVersion output parameter for version number.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void StackGetVersionNumber(const char **pVersion);
|
||||
|
||||
/*! \} */ /* STACK_INIT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CFG_STACK_H */
|
||||
+523
@@ -0,0 +1,523 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* control block */
|
||||
dmAdvCb_t dmAdvCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the advertising CB for a given handle.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvCbInit(uint8_t advHandle)
|
||||
{
|
||||
/* initialize control block */
|
||||
dmAdvCb.advType[advHandle] = DM_ADV_NONE;
|
||||
dmAdvCb.intervalMin[advHandle] = DM_GAP_ADV_SLOW_INT_MIN;
|
||||
dmAdvCb.intervalMax[advHandle] = DM_GAP_ADV_SLOW_INT_MAX;
|
||||
dmAdvCb.channelMap[advHandle] = DM_ADV_CHAN_ALL;
|
||||
dmCb.advFiltPolicy[advHandle] = HCI_ADV_FILT_NONE;
|
||||
dmAdvCb.advState[advHandle] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the legacy adv module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
dmAdvCbInit(i);
|
||||
}
|
||||
|
||||
dmAdvCb.advTimer.handlerId = dmCb.handlerId;
|
||||
dmCb.advAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate an enhanced connection complete event.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param status Status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvGenConnCmpl(uint8_t advHandle, uint8_t status)
|
||||
{
|
||||
hciLeConnCmplEvt_t leConnCmpl;
|
||||
|
||||
/* generate enhanced connection complete event */
|
||||
memset(&leConnCmpl, 0, sizeof(leConnCmpl));
|
||||
|
||||
leConnCmpl.hdr.event = HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT;
|
||||
leConnCmpl.hdr.status = leConnCmpl.status = status;
|
||||
leConnCmpl.role = DM_ROLE_SLAVE;
|
||||
leConnCmpl.addrType = dmAdvCb.peerAddrType[advHandle];
|
||||
BdaCpy(leConnCmpl.peerAddr, dmAdvCb.peerAddr[advHandle]);
|
||||
|
||||
/* pass connection complete event to DM connection management module */
|
||||
dmDevPassHciEvtToConn((hciEvt_t *) &leConnCmpl);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising parameters using the given advertising type, and peer address.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advType Advertising type.
|
||||
* \param peerAddrType Peer address type.
|
||||
* \param pPeerAddr Peer address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvConfig(uint8_t advHandle, uint8_t advType, uint8_t peerAddrType, uint8_t *pPeerAddr)
|
||||
{
|
||||
dmAdvApiConfig_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiConfig_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_CONFIG;
|
||||
pMsg->advType = advType;
|
||||
pMsg->advHandle = advHandle;
|
||||
pMsg->peerAddrType = peerAddrType;
|
||||
BdaCpy(pMsg->peerAddr, pPeerAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising or scan response data to the given data.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param op Data operation.
|
||||
* \param location Data location.
|
||||
* \param len Length of the data. Maximum length is 236 bytes.
|
||||
* \param pData Pointer to the data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetData(uint8_t advHandle, uint8_t op, uint8_t location, uint8_t len, uint8_t *pData)
|
||||
{
|
||||
dmAdvApiSetData_t *pMsg;
|
||||
|
||||
WSF_ASSERT((location == DM_DATA_LOC_SCAN) || (location == DM_DATA_LOC_ADV));
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiSetData_t) + len)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_SET_DATA;
|
||||
pMsg->advHandle = advHandle;
|
||||
pMsg->op = op;
|
||||
pMsg->location = location;
|
||||
pMsg->len = len;
|
||||
memcpy(pMsg->pData, pData, len);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising using the given advertising set and duration.
|
||||
*
|
||||
* \param numSets Number of advertising sets to enable.
|
||||
* \param pAdvHandles Advertising handles array.
|
||||
* \param pDuration Advertising duration (in milliseconds) array.
|
||||
* \param pMaxEaEvents Maximum number of extended advertising events array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvStart(uint8_t numSets, uint8_t *pAdvHandles, uint16_t *pDuration, uint8_t *pMaxEaEvents)
|
||||
{
|
||||
uint8_t i;
|
||||
dmAdvApiStart_t *pMsg;
|
||||
|
||||
WSF_ASSERT(numSets <= DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_START;
|
||||
pMsg->numSets = numSets;
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
pMsg->advHandle[i] = pAdvHandles[i];
|
||||
pMsg->duration[i] = pDuration[i];
|
||||
pMsg->maxEaEvents[i] = pMaxEaEvents[i];
|
||||
}
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop advertising for the given advertising set. If the number of sets is set to 0
|
||||
* then all advertising sets are disabled.
|
||||
*
|
||||
* \param numSets Number of advertising sets to disable.
|
||||
* \param pAdvHandles Advertising handles array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvStop(uint8_t numSets, uint8_t *pAdvHandles)
|
||||
{
|
||||
uint8_t i;
|
||||
dmAdvApiStop_t *pMsg;
|
||||
|
||||
WSF_ASSERT(numSets <= DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_STOP;
|
||||
pMsg->numSets = numSets;
|
||||
|
||||
for (i = 0; i < numSets; i++)
|
||||
{
|
||||
pMsg->advHandle[i] = pAdvHandles[i];
|
||||
}
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove an advertising set.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvRemoveAdvSet(uint8_t advHandle)
|
||||
{
|
||||
dmAdvApiRemove_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiRemove_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_REMOVE;
|
||||
pMsg->advHandle = advHandle;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear advertising sets.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvClearAdvSets(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_ADV_MSG_API_CLEAR;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random device address for a given advertising set.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param pAddr Random device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetRandAddr(uint8_t advHandle, const uint8_t *pAddr)
|
||||
{
|
||||
dmAdvApiSetRandAddr_t *pMsg;
|
||||
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmAdvApiSetRandAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_ADV_MSG_API_SET_RAND_ADDR;
|
||||
pMsg->advHandle = advHandle;
|
||||
BdaCpy(pMsg->addr, pAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the minimum and maximum advertising intervals.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param intervalMin Minimum advertising interval.
|
||||
* \param intervalMax Maximum advertising interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetInterval(uint8_t advHandle, uint16_t intervalMin, uint16_t intervalMax)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
WsfTaskLock();
|
||||
dmAdvCb.intervalMin[advHandle] = intervalMin;
|
||||
dmAdvCb.intervalMax[advHandle] = intervalMax;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Include or exclude certain channels from the advertising channel map.
|
||||
*
|
||||
* \param advHandle Advertising handle.
|
||||
* \param channelMap Advertising channel map.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetChannelMap(uint8_t advHandle, uint8_t channelMap)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
WsfTaskLock();
|
||||
dmAdvCb.channelMap[advHandle] = channelMap;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used while advertising. This function can be used to
|
||||
* configure advertising to use a random address.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.advAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the value of an advertising data element in the given advertising or
|
||||
* scan response data. If the element already exists in the data then it is replaced
|
||||
* with the new value. If the element does not exist in the data it is appended
|
||||
* to it, space permitting.
|
||||
*
|
||||
* \param adType Advertising data element type.
|
||||
* \param len Length of the value. Maximum length is 29 bytes.
|
||||
* \param pValue Pointer to the value.
|
||||
* \param pAdvDataLen Advertising or scan response data length. The new length is returned
|
||||
* in this parameter.
|
||||
* \param pAdvData Pointer to advertising or scan response data.
|
||||
* \param advDataBufLen Length of the advertising or scan response data buffer maintained by
|
||||
* Application.
|
||||
*
|
||||
* \return TRUE if the element was successfully added to the data, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvSetAdValue(uint8_t adType, uint8_t len, uint8_t *pValue, uint16_t *pAdvDataLen,
|
||||
uint8_t *pAdvData, uint16_t advDataBufLen)
|
||||
{
|
||||
uint8_t *pElem;
|
||||
uint8_t *pNext;
|
||||
uint16_t totalLen;
|
||||
uint16_t newAdvDataLen;
|
||||
bool_t valueSet = FALSE;
|
||||
|
||||
/* find ad type in data */
|
||||
if ((pElem = DmFindAdType(adType, *pAdvDataLen, pAdvData)) != NULL)
|
||||
{
|
||||
/* if new length equals existing length */
|
||||
if ((len + 1) == pElem[DM_AD_LEN_IDX])
|
||||
{
|
||||
/* copy new ad value to data in existing location */
|
||||
memcpy(&pElem[DM_AD_DATA_IDX], pValue, len);
|
||||
valueSet = TRUE;
|
||||
}
|
||||
/* else if new value can replace old value and still fit */
|
||||
else
|
||||
{
|
||||
/* calculate the advertising data length if old element was replaced with new */
|
||||
newAdvDataLen = *pAdvDataLen + len + 1 - pElem[DM_AD_LEN_IDX];
|
||||
|
||||
/* if length is ok */
|
||||
if (newAdvDataLen <= advDataBufLen)
|
||||
{
|
||||
/* delete item (then we will replace it) */
|
||||
|
||||
/* get the start of element that follows the element to delete */
|
||||
totalLen = pElem[DM_AD_LEN_IDX] + 1;
|
||||
pNext = pElem + totalLen;
|
||||
|
||||
/* move data from start of next element to start of current item;
|
||||
* length is equal the data that remains after pNext
|
||||
*/
|
||||
memmove(pElem, pNext, *pAdvDataLen - (uint8_t)(pNext - pAdvData));
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen - totalLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if value not set */
|
||||
if (!valueSet)
|
||||
{
|
||||
/* if new value fits */
|
||||
if ((*pAdvDataLen + len + 2) <= advDataBufLen)
|
||||
{
|
||||
/* construct AD item in advertising data */
|
||||
pElem = &pAdvData[*pAdvDataLen];
|
||||
*pElem++ = len + 1;
|
||||
*pElem++ = adType;
|
||||
memcpy(pElem, pValue, len);
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen + len + 2;
|
||||
|
||||
valueSet = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the device name in the given advertising or scan response data. If the
|
||||
* device can only fit in the data if it is shortened, the name is shortened
|
||||
* and the AD type is changed to DM_ADV_TYPE_SHORT_NAME.
|
||||
*
|
||||
* \param len Length of the name. Maximum length is 29 bytes.
|
||||
* \param pValue Pointer to the name in UTF-8 format.
|
||||
* \param pAdvDataLen Advertising or scan response data length. The new length is returned
|
||||
* in this parameter.
|
||||
* \param pAdvData Pointer to advertising or scan response data.
|
||||
* \param advDataBufLen Length of the advertising or scan response data buffer maintained by
|
||||
* Application.
|
||||
*
|
||||
* \return TRUE if the element was successfully added to the data, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvSetName(uint8_t len, uint8_t *pValue, uint16_t *pAdvDataLen, uint8_t *pAdvData,
|
||||
uint16_t advDataBufLen)
|
||||
{
|
||||
uint8_t *pElem;
|
||||
uint8_t *pNext;
|
||||
uint16_t totalLen;
|
||||
uint8_t adType;
|
||||
|
||||
/* find name in data */
|
||||
if ((pElem = DmFindAdType(DM_ADV_TYPE_LOCAL_NAME, *pAdvDataLen, pAdvData)) == NULL)
|
||||
{
|
||||
pElem = DmFindAdType(DM_ADV_TYPE_SHORT_NAME, *pAdvDataLen, pAdvData);
|
||||
}
|
||||
|
||||
/* if found delete it */
|
||||
if (pElem != NULL)
|
||||
{
|
||||
/* get the start of element that follows the element to delete */
|
||||
totalLen = pElem[DM_AD_LEN_IDX] + 1;
|
||||
pNext = pElem + totalLen;
|
||||
|
||||
/* move data from start of next element to start of current item;
|
||||
* length is equal the data that remains after pNext
|
||||
*/
|
||||
memmove(pElem, pNext, *pAdvDataLen - (uint8_t)(pNext - pAdvData));
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen - totalLen;
|
||||
}
|
||||
|
||||
/* if name will fit */
|
||||
if (*pAdvDataLen <= (advDataBufLen - 2))
|
||||
{
|
||||
/* if full device name won't fit */
|
||||
if ((*pAdvDataLen + len + 2) > advDataBufLen)
|
||||
{
|
||||
/* adjust length so that it will fit */
|
||||
len = (advDataBufLen - 2) - *pAdvDataLen;
|
||||
|
||||
/* set ad type to shortened local name */
|
||||
adType = DM_ADV_TYPE_SHORT_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
adType = DM_ADV_TYPE_LOCAL_NAME;
|
||||
}
|
||||
|
||||
/* construct AD item in advertising data */
|
||||
pElem = &pAdvData[*pAdvDataLen];
|
||||
*pElem++ = len + 1;
|
||||
*pElem++ = adType;
|
||||
memcpy(pElem, pValue, len);
|
||||
|
||||
/* update length */
|
||||
*pAdvDataLen = *pAdvDataLen + len + 2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_ADV_H
|
||||
#define DM_ADV_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "sec_api.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM adv event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_ADV_MSG_API_CONFIG = DM_MSG_START(DM_ID_ADV),
|
||||
DM_ADV_MSG_API_SET_DATA,
|
||||
DM_ADV_MSG_API_START,
|
||||
DM_ADV_MSG_API_STOP,
|
||||
DM_ADV_MSG_API_REMOVE,
|
||||
DM_ADV_MSG_API_CLEAR,
|
||||
DM_ADV_MSG_API_SET_RAND_ADDR,
|
||||
DM_ADV_MSG_TIMEOUT
|
||||
};
|
||||
|
||||
/* DM adv periodic event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_ADV_PER_MSG_API_CONFIG = DM_MSG_START(DM_ID_ADV_PER),
|
||||
DM_ADV_PER_MSG_API_SET_DATA,
|
||||
DM_ADV_PER_MSG_API_START,
|
||||
DM_ADV_PER_MSG_API_STOP,
|
||||
};
|
||||
|
||||
/* DM advertising states */
|
||||
enum
|
||||
{
|
||||
DM_ADV_STATE_IDLE, /* idle */
|
||||
DM_ADV_STATE_ADVERTISING, /* advertising */
|
||||
DM_ADV_STATE_STARTING_DIRECTED, /* starting high duty cycle directed advertising */
|
||||
DM_ADV_STATE_STARTING, /* starting undirected or low duty cycle directed advertising */
|
||||
DM_ADV_STATE_STOPPING_DIRECTED, /* stopping high duty cycle directed advertising */
|
||||
DM_ADV_STATE_STOPPING, /* stopping undirected or low duty cycle directed advertising */
|
||||
DM_ADV_STATE_REMOVING_SET, /* removing advertising set */
|
||||
DM_ADV_STATE_CLEARING_SETS /* clearing all advertising sets */
|
||||
};
|
||||
|
||||
/* DM periodic advertising states */
|
||||
enum
|
||||
{
|
||||
DM_ADV_PER_STATE_IDLE,
|
||||
DM_ADV_PER_STATE_ADVERTISING,
|
||||
DM_ADV_PER_STATE_STARTING,
|
||||
DM_ADV_PER_STATE_STOPPING
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t advType;
|
||||
uint8_t peerAddrType;
|
||||
bdAddr_t peerAddr;
|
||||
bool_t scanReqNotifEna;
|
||||
} dmAdvApiConfig_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_SET_DATA */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t op;
|
||||
uint8_t location;
|
||||
uint8_t len;
|
||||
uint8_t pData[];
|
||||
} dmAdvApiSetData_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t numSets;
|
||||
uint8_t advHandle[DM_NUM_ADV_SETS];
|
||||
uint16_t duration[DM_NUM_ADV_SETS];
|
||||
uint8_t maxEaEvents[DM_NUM_ADV_SETS];
|
||||
} dmAdvApiStart_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t numSets;
|
||||
uint8_t advHandle[DM_NUM_ADV_SETS];
|
||||
} dmAdvApiStop_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_REMOVE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvApiRemove_t;
|
||||
|
||||
/* Data structure for DM_ADV_MSG_API_SET_RAND_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
bdAddr_t addr;
|
||||
} dmAdvApiSetRandAddr_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiConfig_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_SET_DATA */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
uint8_t op;
|
||||
uint8_t len;
|
||||
uint8_t pData[];
|
||||
} dmAdvPerApiSetData_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiStart_t;
|
||||
|
||||
/* Data structure for DM_ADV_PER_MSG_API_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
} dmAdvPerApiStop_t;
|
||||
|
||||
/* Union of all adv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmAdvApiConfig_t apiConfig;
|
||||
dmAdvApiSetData_t apiSetData;
|
||||
dmAdvApiStart_t apiStart;
|
||||
dmAdvApiStop_t apiStop;
|
||||
dmAdvApiRemove_t apiRemove;
|
||||
dmAdvApiSetRandAddr_t apiSetRandAddr;
|
||||
dmAdvPerApiConfig_t apiPerConfig;
|
||||
dmAdvPerApiSetData_t apiPerSetData;
|
||||
dmAdvPerApiStart_t apiPerStart;
|
||||
dmAdvPerApiStop_t apiPerStop;
|
||||
secAes_t aes;
|
||||
} dmAdvMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmAdvAct_t)(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* Control block for advertising module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t advTimer;
|
||||
uint16_t intervalMin[DM_NUM_ADV_SETS];
|
||||
uint16_t intervalMax[DM_NUM_ADV_SETS];
|
||||
uint8_t advType[DM_NUM_ADV_SETS];
|
||||
uint8_t channelMap[DM_NUM_ADV_SETS];
|
||||
uint8_t localAddrType;
|
||||
uint8_t advState[DM_NUM_ADV_SETS];
|
||||
uint16_t advDuration[DM_NUM_ADV_SETS];
|
||||
bool_t advEnabled;
|
||||
bdAddr_t peerAddr[DM_NUM_ADV_SETS];
|
||||
uint8_t peerAddrType[DM_NUM_ADV_SETS];
|
||||
} dmAdvCb_t;
|
||||
|
||||
extern dmAdvCb_t dmAdvCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* legacy adv component inteface */
|
||||
void dmAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmAdvReset(void);
|
||||
|
||||
/* legacy adv action functions */
|
||||
void dmAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActStop(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActRemoveSet(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActClearSets(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActSetRandAddr(dmAdvMsg_t *pMsg);
|
||||
void dmAdvActTimeout(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* extended adv component inteface */
|
||||
void dmExtAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmExtAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmExtAdvReset(void);
|
||||
|
||||
/* extended adv action functions */
|
||||
void dmExtAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActStop(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActRemoveSet(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActClearSets(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActSetRandAddr(dmAdvMsg_t *pMsg);
|
||||
void dmExtAdvActTimeout(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* periodic adv action functions */
|
||||
void dmPerAdvActConfig(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActSetData(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActStart(dmAdvMsg_t *pMsg);
|
||||
void dmPerAdvActStop(dmAdvMsg_t *pMsg);
|
||||
|
||||
/* periodic adv component inteface */
|
||||
void dmPerAdvMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPerAdvHciHandler(hciEvt_t *pEvent);
|
||||
void dmPerAdvReset(void);
|
||||
|
||||
/* legacy adv directed advertising interface */
|
||||
void dmAdvStartDirected(uint8_t advType, uint16_t duration, uint8_t addrType, uint8_t *pAddr);
|
||||
void dmAdvStopDirected(void);
|
||||
void dmAdvConnected(void);
|
||||
void dmAdvConnectFailed(void);
|
||||
|
||||
/* extended adv directed advertising interface */
|
||||
void dmExtAdvStartDirected(dmConnId_t connId, uint8_t advHandle, uint8_t advType,
|
||||
uint16_t duration, uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr);
|
||||
void dmExtAdvStopDirected(dmConnId_t connId);
|
||||
void dmExtAdvConnected(dmConnId_t connId);
|
||||
void dmExtAdvConnectFailed(dmConnId_t connId);
|
||||
|
||||
/* adv utility functions */
|
||||
void dmAdvInit(void);
|
||||
void dmAdvCbInit(uint8_t advHandle);
|
||||
void dmAdvGenConnCmpl(uint8_t advHandle, uint8_t status);
|
||||
|
||||
/* extended and periodic adv utility functions */
|
||||
void dmExtAdvInit(void);
|
||||
void dmPerAdvInit(void);
|
||||
uint8_t dmPerAdvState(uint8_t advHandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_ADV_H */
|
||||
+1941
File diff suppressed because it is too large
Load Diff
Vendored
+562
@@ -0,0 +1,562 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager advertising module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block for legacy advertising module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t advType; /*!< Advertising type. */
|
||||
} dmLegAdvCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmAdvAct_t dmAdvAct[] =
|
||||
{
|
||||
dmAdvActConfig,
|
||||
dmAdvActSetData,
|
||||
dmAdvActStart,
|
||||
dmAdvActStop,
|
||||
dmAdvActRemoveSet,
|
||||
dmAdvActClearSets,
|
||||
dmAdvActSetRandAddr,
|
||||
dmAdvActTimeout
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmAdvFcnIf =
|
||||
{
|
||||
dmAdvReset,
|
||||
dmAdvHciHandler,
|
||||
dmAdvMsgHandler
|
||||
};
|
||||
|
||||
/* control block */
|
||||
static dmLegAdvCb_t dmLegAdvCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising parameters using the given advertising type, and peer address.
|
||||
*
|
||||
* \param advType Advertising type.
|
||||
* \param peerAddrType Peer address type.
|
||||
* \param pPeerAddr Peer address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmAdvConfig(uint8_t advType, uint8_t peerAddrType, uint8_t *pPeerAddr)
|
||||
{
|
||||
/* set advertising parameters */
|
||||
HciLeSetAdvParamCmd(dmAdvCb.intervalMin[DM_ADV_HANDLE_DEFAULT], /* advIntervalMin */
|
||||
dmAdvCb.intervalMax[DM_ADV_HANDLE_DEFAULT], /* advIntervalMax */
|
||||
advType, /* advType */
|
||||
DmLlAddrType(dmCb.advAddrType), /* ownAddrType */
|
||||
peerAddrType, /* peerAddrType */
|
||||
pPeerAddr, /* pPeerAddr */
|
||||
dmAdvCb.channelMap[DM_ADV_HANDLE_DEFAULT], /* advChanMap */
|
||||
dmCb.advFiltPolicy[DM_ADV_HANDLE_DEFAULT]); /* advFiltPolicy */
|
||||
|
||||
/* store advertising type */
|
||||
dmLegAdvCb.advType = advType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActConfig(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActConfig: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("DmAdvConfig during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set advertising parameters */
|
||||
dmAdvConfig(pMsg->apiConfig.advType, pMsg->apiConfig.peerAddrType, pMsg->apiConfig.peerAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the advertising or scan response data to the given data.
|
||||
*
|
||||
* \param location Data location.
|
||||
* \param len Length of the data. Maximum length is 31 bytes.
|
||||
* \param pData Pointer to the data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActSetData(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
WSF_ASSERT(pMsg->apiSetData.len <= HCI_ADV_DATA_LEN);
|
||||
|
||||
DM_TRACE_INFO1("dmAdvActSetData: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* set new data in HCI */
|
||||
if (pMsg->apiSetData.location == DM_DATA_LOC_ADV)
|
||||
{
|
||||
HciLeSetAdvDataCmd(pMsg->apiSetData.len, pMsg->apiSetData.pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
HciLeSetScanRespDataCmd(pMsg->apiSetData.len, pMsg->apiSetData.pData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActStart(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActStart: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("dmAdvActStart during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STARTING;
|
||||
dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] = pMsg->apiStart.duration[DM_ADV_HANDLE_DEFAULT];
|
||||
HciLeSetAdvEnableCmd(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop advertising action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActStop(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvActStop: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING)
|
||||
{
|
||||
/* if doing directed advertising ignore the request */
|
||||
if ((dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT) ||
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] == DM_ADV_CONN_DIRECT_LO_DUTY))
|
||||
{
|
||||
DM_TRACE_WARN0("DmAdvStop during directed advertising!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove an advertising set action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActRemoveSet(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear advertising sets action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActClearSets(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random device address for a given advertising set.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActSetRandAddr(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an advertising timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvActTimeout(dmAdvMsg_t *pMsg)
|
||||
{
|
||||
DM_TRACE_INFO0("dmAdvActTimeout!");
|
||||
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING)
|
||||
{
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the legacy adv module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvReset(void)
|
||||
{
|
||||
wsfMsgHdr_t advStop;
|
||||
|
||||
/* if stopping undirected advertisement or advertising but not high duty cycle directed adv */
|
||||
if ((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STOPPING) ||
|
||||
((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING) &&
|
||||
(dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] != DM_ADV_CONN_DIRECT)))
|
||||
{
|
||||
/* stop advertising timer */
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* generate advertising stop event */
|
||||
advStop.status = HCI_SUCCESS;
|
||||
advStop.event = DM_ADV_STOP_IND;
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) &advStop);
|
||||
}
|
||||
|
||||
/* reset legacy adv module */
|
||||
dmAdvInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM adv HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
if (pEvent->hdr.event == HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
uint8_t cbackEvent = 0;
|
||||
|
||||
DM_TRACE_INFO1("HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
switch (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT])
|
||||
{
|
||||
case DM_ADV_STATE_STARTING:
|
||||
case DM_ADV_STATE_STARTING_DIRECTED:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING)
|
||||
{
|
||||
/* start advertising timer if applicable */
|
||||
if (dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] > 0)
|
||||
{
|
||||
dmAdvCb.advTimer.msg.event = DM_ADV_MSG_TIMEOUT;
|
||||
WsfTimerStartMs(&dmAdvCb.advTimer, dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT]);
|
||||
}
|
||||
|
||||
/* Application callbacks only sent in undirected state */
|
||||
if (dmLegAdvCb.advType != DM_ADV_CONN_DIRECT_LO_DUTY)
|
||||
{
|
||||
cbackEvent = DM_ADV_START_IND;
|
||||
}
|
||||
}
|
||||
|
||||
/* pass advertising start event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_START, DM_ADV_START_IND, 0, 0);
|
||||
|
||||
/* store advertising type and state */
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = dmLegAdvCb.advType;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_ADVERTISING;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_ADV_STATE_STOPPING:
|
||||
case DM_ADV_STATE_STOPPING_DIRECTED:
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STOPPING)
|
||||
{
|
||||
/* stop advertising timer */
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* Application and DM callbacks only sent in undirected or low duty cycle directed state */
|
||||
if (dmLegAdvCb.advType == DM_ADV_CONN_DIRECT_LO_DUTY)
|
||||
{
|
||||
cbackEvent = HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT;
|
||||
}
|
||||
else
|
||||
{
|
||||
cbackEvent = DM_ADV_STOP_IND;
|
||||
}
|
||||
}
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
/* store advertising type and state */
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_ADVERTISING;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore the event */
|
||||
break;
|
||||
}
|
||||
|
||||
/* if DM conn notify needed */
|
||||
if (cbackEvent == HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmAdvGenConnCmpl(DM_ADV_HANDLE_DEFAULT, HCI_ERR_ADV_TIMEOUT);
|
||||
}
|
||||
/* else if app callback needed */
|
||||
else if (cbackEvent)
|
||||
{
|
||||
pEvent->hdr.event = cbackEvent;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM adv event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmAdvAct[DM_MSG_MASK(pMsg->event)])((dmAdvMsg_t *)pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start directed advertising.
|
||||
*
|
||||
* \param advType Advertising type.
|
||||
* \param duration Advertising duration (in ms).
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvStartDirected(uint8_t advType, uint16_t duration, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvStartDirected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
/* if not advertising */
|
||||
if (dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_IDLE)
|
||||
{
|
||||
/* start advertising */
|
||||
HciLeSetAdvEnableCmd(TRUE);
|
||||
|
||||
/* store advertising info */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = (advType == DM_ADV_CONN_DIRECT) ? \
|
||||
DM_ADV_STATE_STARTING_DIRECTED : DM_ADV_STATE_STARTING;
|
||||
|
||||
dmAdvCb.advDuration[DM_ADV_HANDLE_DEFAULT] = duration;
|
||||
BdaCpy(dmAdvCb.peerAddr[DM_ADV_HANDLE_DEFAULT], pAddr);
|
||||
dmAdvCb.peerAddrType[DM_ADV_HANDLE_DEFAULT] = addrType;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop directed advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvStopDirected(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvStopDirected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
/* if advertising or starting advertising */
|
||||
if ((dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_ADVERTISING) ||
|
||||
(dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING) ||
|
||||
(dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] == DM_ADV_STATE_STARTING_DIRECTED))
|
||||
{
|
||||
/* disable advertising */
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = (dmLegAdvCb.advType == DM_ADV_CONN_DIRECT) ? \
|
||||
DM_ADV_STATE_STOPPING_DIRECTED : DM_ADV_STATE_STOPPING;
|
||||
HciLeSetAdvEnableCmd(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called when a connection is established from directed advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvConnected(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvConnected: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called when a directed advertising connection fails.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmAdvConnectFailed(void)
|
||||
{
|
||||
DM_TRACE_INFO1("dmAdvConnectFailed: state: %d", dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT]);
|
||||
|
||||
WsfTimerStop(&dmAdvCb.advTimer);
|
||||
|
||||
/* pass advertising stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_ADV_STOP_IND, 0, 0);
|
||||
|
||||
dmAdvCb.advType[DM_ADV_HANDLE_DEFAULT] = DM_ADV_NONE;
|
||||
dmAdvCb.advState[DM_ADV_HANDLE_DEFAULT] = DM_ADV_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM legacy advertising.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmAdvInit(void)
|
||||
{
|
||||
WsfTaskLock();
|
||||
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_ADV] = (dmFcnIf_t *) &dmAdvFcnIf;
|
||||
|
||||
/* initialize legacy adv module */
|
||||
dmAdvInit();
|
||||
|
||||
/* clear set advertising set random address callback */
|
||||
dmDevCb.advSetRandAddrCback = NULL;
|
||||
|
||||
/* initialize HCI VS module */
|
||||
HciVsInit(0);
|
||||
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether DM advertising is in legacy mode.
|
||||
*
|
||||
* \return TRUE if DM advertising is in legacy mode. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmAdvModeLeg(void)
|
||||
{
|
||||
return (dmFcnIfTbl[DM_ID_ADV] == (dmFcnIf_t *) &dmAdvFcnIf) ? TRUE : FALSE;
|
||||
}
|
||||
+1595
File diff suppressed because it is too large
Load Diff
+369
@@ -0,0 +1,369 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM connection management module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_CONN_H
|
||||
#define DM_CONN_H
|
||||
|
||||
#include "dm_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Uninitialized HCI handle */
|
||||
#define DM_CONN_HCI_HANDLE_NONE 0xFFFF
|
||||
|
||||
/* Action set initializer */
|
||||
#define DM_CONN_ACT_SET_INIT(n) ((n) << 4)
|
||||
|
||||
/* Get action set ID from action */
|
||||
#define DM_CONN_ACT_SET_ID(action) ((action) >> 4)
|
||||
|
||||
/* Get action ID from action */
|
||||
#define DM_CONN_ACT_ID(action) ((action) & 0x0F)
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM conn event handler messages for state machine */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_CONN_MSG_API_OPEN = DM_MSG_START(DM_ID_CONN), /*!< Open Connection */
|
||||
DM_CONN_MSG_API_CLOSE, /*!< Close Connection */
|
||||
DM_CONN_MSG_API_ACCEPT, /*!< Accept Connection */
|
||||
DM_CONN_MSG_API_UPDATE_MASTER, /*!< Master Connection Parameter Update */
|
||||
DM_CONN_MSG_API_UPDATE_SLAVE, /*!< Slave Connecteion Parameter Update */
|
||||
|
||||
/* messages from L2C */
|
||||
DM_CONN_MSG_L2C_UPDATE_IND, /*!< L2CAP Parameter update indication */
|
||||
DM_CONN_MSG_L2C_UPDATE_CNF, /*!< L2CAP Parameter update confirmation */
|
||||
|
||||
/* messages from HCI */
|
||||
DM_CONN_MSG_HCI_LE_CONN_CMPL_FAIL, /*!< HCI LE Connection Complete Failure Event */
|
||||
DM_CONN_MSG_HCI_LE_CONN_CMPL, /*!< HCI LE Connection Compelte Event */
|
||||
DM_CONN_MSG_HCI_DISCONNECT_CMPL, /*!< HCI Disconnection Complete Event */
|
||||
DM_CONN_MSG_HCI_LE_CONN_UPDATE_CMPL, /*!< HCI LE Connection Update Complete Event */
|
||||
DM_CONN_MSG_HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL, /*!< HCI LE Create Connection Cancel Command Complet Event */
|
||||
|
||||
/* other internal messages */
|
||||
DM_CONN_MSG_INT_UPDATE_TIMEOUT /*!< Internal Update Timeout */
|
||||
};
|
||||
|
||||
/* Number of messages */
|
||||
#define DM_CONN_NUM_MSGS (DM_CONN_MSG_INT_UPDATE_TIMEOUT - DM_CONN_MSG_API_OPEN + 1)
|
||||
|
||||
/* DM conn event handler messages, non-state machine */
|
||||
enum
|
||||
{
|
||||
DM_CONN_MSG_API_FEAT = DM_MSG_START(DM_ID_CONN_2),
|
||||
DM_CONN_MSG_API_READ_RSSI,
|
||||
DM_CONN_MSG_API_REM_CONN_PARAM_REQ_REPLY,
|
||||
DM_CONN_MSG_API_REM_CONN_PARAM_REQ_NEG_REPLY,
|
||||
DM_CONN_MSG_API_SET_DATA_LEN,
|
||||
DM_CONN_MSG_API_WRITE_AUTH_TO,
|
||||
|
||||
/* messages from HCI */
|
||||
DM_CONN_MSG_HCI_READ_RSSI_CMPL,
|
||||
DM_CONN_MSG_HCI_FEAT_CMPL
|
||||
};
|
||||
|
||||
/* State machine action function sets */
|
||||
enum
|
||||
{
|
||||
DM_CONN_ACT_SET_MAIN,
|
||||
DM_CONN_ACT_SET_MASTER,
|
||||
DM_CONN_ACT_SET_SLAVE,
|
||||
DM_CONN_NUM_ACT_SETS
|
||||
};
|
||||
|
||||
/*! State machine actions */
|
||||
enum
|
||||
{
|
||||
DM_CONN_SM_ACT_NONE = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_MAIN), /*!< No Action */
|
||||
DM_CONN_SM_ACT_CLOSE, /*!< Process Connection Close */
|
||||
DM_CONN_SM_ACT_CONN_OPENED, /*!< Procoess Connection Opened */
|
||||
DM_CONN_SM_ACT_CONN_FAILED, /*!< Process Connection Failed */
|
||||
DM_CONN_SM_ACT_CONN_CLOSED, /*!< Process Connection Closed */
|
||||
DM_CONN_SM_ACT_HCI_UPDATED, /*!< Process HCI Connection Update */
|
||||
|
||||
DM_CONN_SM_ACT_OPEN = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_MASTER), /*!< Process Master Connection Open */
|
||||
DM_CONN_SM_ACT_CANCEL_OPEN, /*!< Process Master Cancel Connection Open */
|
||||
DM_CONN_SM_ACT_UPDATE_MASTER, /*!< Process Master Connection Parameter Update */
|
||||
DM_CONN_SM_ACT_L2C_UPDATE_IND, /*!< Process Master L2CAP Connection Parameter Update Indication */
|
||||
|
||||
DM_CONN_SM_ACT_ACCEPT = DM_CONN_ACT_SET_INIT(DM_CONN_ACT_SET_SLAVE), /*!< Process Slave Connection Accept */
|
||||
DM_CONN_SM_ACT_CANCEL_ACCEPT, /*!< Process Slave Cancel Connection Accept */
|
||||
DM_CONN_SM_ACT_UPDATE_SLAVE, /*!< Process Slave Connection Update */
|
||||
DM_CONN_SM_ACT_CONN_ACCEPTED, /*!< Process Slave Connection Accepted */
|
||||
DM_CONN_SM_ACT_ACCEPT_FAILED, /*!< Process Slave Connection Accept Failure */
|
||||
DM_CONN_SM_ACT_L2C_UPDATE_CNF /*!< Process Slave L2CAP Connection Parameter Update Confirmation */
|
||||
};
|
||||
|
||||
/*! State machine states */
|
||||
enum
|
||||
{
|
||||
DM_CONN_SM_ST_IDLE, /*!< Idle State */
|
||||
DM_CONN_SM_ST_CONNECTING, /*!< Connecting State */
|
||||
DM_CONN_SM_ST_ACCEPTING, /*!< Accepting State */
|
||||
DM_CONN_SM_ST_CONNECTED, /*!< Connected State */
|
||||
DM_CONN_SM_ST_DISCONNECTING, /*!< Disconnecting State */
|
||||
DM_CONN_SM_NUM_STATES
|
||||
};
|
||||
|
||||
/* Data structure for DM_CONN_MSG_API_OPEN and DM_CONN_MSG_API_ACCEPT */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t initPhys;
|
||||
uint8_t advHandle;
|
||||
uint8_t advType;
|
||||
uint16_t duration;
|
||||
uint8_t maxEaEvents;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t addrType;
|
||||
uint8_t clientId;
|
||||
} dmConnApiOpen_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_CLOSE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t reason;
|
||||
uint8_t clientId;
|
||||
} dmConnApiClose_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_UPDATE_MASTER and SLAVE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t connSpec;
|
||||
} dmConnApiUpdate_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_L2C_UPDATE_IND */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t *pConnSpec;
|
||||
uint8_t identifier;
|
||||
} dmConnL2cUpdateInd_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_L2C_UPDATE_CNF */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t result;
|
||||
} dmConnL2cUpdateCnf_t;
|
||||
|
||||
/*! Union of all DM Conn state machine messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmConnApiOpen_t apiOpen;
|
||||
dmConnApiClose_t apiClose;
|
||||
dmConnApiUpdate_t apiUpdate;
|
||||
dmConnL2cUpdateInd_t l2cUpdateInd;
|
||||
dmConnL2cUpdateCnf_t l2cUpdateCnf;
|
||||
hciLeConnCmplEvt_t hciLeConnCmpl;
|
||||
hciDisconnectCmplEvt_t hciDisconnectCmpl;
|
||||
hciLeConnUpdateCmplEvt_t hciLeConnUpdateCmpl;
|
||||
} dmConnMsg_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_FEAT */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t handle;
|
||||
uint8_t type;
|
||||
uint8_t feature;
|
||||
} dmConnApiFeat_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_READ_RSSI */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
} dmConnApiReadRssi_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_REM_CONN_PARAM_REQ_REPLY */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
hciConnSpec_t connSpec;
|
||||
} dmConnApiRemConnParamReqReply_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_REM_CONN_PARAM_REQ_NEG_REPLY */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t reason;
|
||||
} dmConnApiRemConnParamReqNegReply_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_SET_DATA_LEN */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t txOctets;
|
||||
uint16_t txTime;
|
||||
} dmConnApiSetDataLen_t;
|
||||
|
||||
/*! Data structure for DM_CONN_MSG_API_WRITE_AUTH_TO */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t timeout;
|
||||
} dmConnApiWriteAuthPayloadTo_t;
|
||||
|
||||
/*! Union of all DM Conn 2 messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmConnApiFeat_t apiFeat;
|
||||
dmConnApiReadRssi_t apiReadRssi;
|
||||
dmConnApiRemConnParamReqReply_t apiRemConnParamReqReply;
|
||||
dmConnApiRemConnParamReqNegReply_t apiRemConnParamReqNegReply;
|
||||
dmConnApiSetDataLen_t apiSetDataLen;
|
||||
dmConnApiWriteAuthPayloadTo_t apiWriteAuthPayloadTo;
|
||||
} dmConn2Msg_t;
|
||||
|
||||
/*! Connection control block */
|
||||
typedef struct
|
||||
{
|
||||
bdAddr_t peerAddr;
|
||||
bdAddr_t localAddr;
|
||||
uint16_t handle;
|
||||
uint16_t idleMask;
|
||||
dmConnId_t connId;
|
||||
bool_t updating;
|
||||
bool_t usingLtk;
|
||||
uint8_t peerAddrType;
|
||||
uint8_t localAddrType;
|
||||
uint8_t state;
|
||||
uint8_t inUse;
|
||||
uint8_t secLevel;
|
||||
uint8_t tmpSecLevel;
|
||||
uint8_t role;
|
||||
|
||||
/* enhanced fields */
|
||||
bdAddr_t localRpa;
|
||||
bdAddr_t peerRpa;
|
||||
|
||||
uint32_t features;
|
||||
bool_t featuresPresent;
|
||||
} dmConnCcb_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmConnAct_t)(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/*! Control block of the DM conn module */
|
||||
typedef struct
|
||||
{
|
||||
dmConnCcb_t ccb[DM_CONN_MAX];
|
||||
dmCback_t connCback[DM_CLIENT_ID_MAX];
|
||||
hciConnSpec_t connSpec[DM_NUM_PHYS];
|
||||
uint16_t scanInterval[DM_NUM_PHYS];
|
||||
uint16_t scanWindow[DM_NUM_PHYS];
|
||||
} dmConnCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! State machine action sets */
|
||||
extern dmConnAct_t *dmConnActSet[DM_CONN_NUM_ACT_SETS];
|
||||
|
||||
/*! Control block */
|
||||
extern dmConnCb_t dmConnCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* utility functions */
|
||||
dmConnCcb_t *dmConnCcbAlloc(uint8_t *pAddr);
|
||||
void dmConnCcbDealloc(dmConnCcb_t *pCcb);
|
||||
dmConnCcb_t *dmConnCcbByHandle(uint16_t handle);
|
||||
dmConnCcb_t *dmConnCcbByBdAddr(uint8_t *pAddr);
|
||||
dmConnCcb_t *dmConnCcbById(dmConnId_t connId);
|
||||
uint8_t dmConnNum(void);
|
||||
dmConnId_t dmConnOpenAccept(uint8_t clientId, uint8_t initPhys, uint8_t advHandle, uint8_t advType,
|
||||
uint16_t duration, uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr,
|
||||
uint8_t role);
|
||||
void dmConnExecCback(dmConnMsg_t *pMsg);
|
||||
|
||||
/* component inteface */
|
||||
void dmConnReset(void);
|
||||
void dmConnMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmConnHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* component 2 inteface */
|
||||
void dmConn2MsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmConn2HciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* state machine */
|
||||
void dmConnSmExecute(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* main action functions */
|
||||
void dmConnSmActNone(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActClose(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnOpened(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnClosed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActHciUpdated(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* common master action functions */
|
||||
void dmConnSmActCancelOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActUpdateMaster(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActL2cUpdateInd(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* legacy master action functions */
|
||||
void dmConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* extended master action functions */
|
||||
void dmExtConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* common slave action functions */
|
||||
void dmConnSmActUpdateSlave(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActL2cUpdateCnf(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* legacy slave action functions */
|
||||
void dmConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
/* extended slave action functions */
|
||||
void dmExtConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
void dmExtConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_CONN_H */
|
||||
Vendored
+840
@@ -0,0 +1,840 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager Connection Constant Tone Extension (CTE) module.
|
||||
*
|
||||
* Copyright (c) 2018-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM connection CTE states */
|
||||
enum
|
||||
{
|
||||
DM_CONN_CTE_STATE_IDLE, /*!< Idle */
|
||||
DM_CONN_CTE_STATE_INITIATING, /*!< Initiating CTE request */
|
||||
DM_CONN_CTE_STATE_RESPONDING, /*!< Responding to CTE request */
|
||||
DM_CONN_CTE_STATE_SAMPLING, /*!< Sampling received CTE */
|
||||
DM_CONN_CTE_STATE_STARTING, /*!< Starting CTE request, CTE response or sampling received CTE */
|
||||
DM_CONN_CTE_STATE_STOPPING, /*!< Stopping CTE request, CTE response or sampling received CTE */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RX_SAMPLE_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint8_t slotDurations; /*!< Switching and sampling slot durations */
|
||||
uint8_t switchPatternLen; /*!< Number of Antenna IDs in switching pattern */
|
||||
uint8_t *pAntennaIDs; /*!< List of Antenna IDs in switching pattern */
|
||||
} dmConnCteApiRxSampleStart_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiRxSampleStop_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_TX_CFG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint8_t cteTypeBits; /*!< Permitted CTE type bits */
|
||||
uint8_t switchPatternLen; /*!< Number of Antenna IDs in switching pattern */
|
||||
uint8_t *pAntennaIDs; /*!< List of Antenna IDs in switching pattern */
|
||||
} dmConnCteApiTxConfig_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_REQ_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
uint16_t cteReqInt; /*!< CTE request interval */
|
||||
uint8_t reqCteLen; /*!< Minimum length of CTE being requested in 8 us units */
|
||||
uint8_t reqCteType; /*!< Requested CTE type */
|
||||
} dmConnCteApiReqStart_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_REQ_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiReqStop_t;
|
||||
|
||||
/*! Data structure for DM_CONN_CTE_MSG_API_RSP_START and DM_CONN_CTE_MSG_API_RSP_STOP */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmConnCteApiRspEnable_t;
|
||||
|
||||
/*! Union of all DM Connection CTE API messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
dmConnCteApiRxSampleStart_t rxSampleStart; /*!< Start sampling received CTE, and configure CTE Rx parameters to be used */
|
||||
dmConnCteApiRxSampleStop_t rxSampleStop; /*!< Stop sampling received CTE */
|
||||
dmConnCteApiTxConfig_t txCfg; /*!< Configure CTE Tx parameters */
|
||||
dmConnCteApiReqStart_t reqStart; /*!< Start initiating CTE request */
|
||||
dmConnCteApiReqStop_t reqStop; /*!< Stop initiating CTE request */
|
||||
dmConnCteApiRspEnable_t rspEnable; /*!< Start or stop responding to CTE request */
|
||||
} dmConnCteMsg_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmConnCteAct_t)(dmConnCteMsg_t *pMsg);
|
||||
|
||||
/*! Control block for connection CTE module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rxSampleState; /*!< Sampling received CTE state */
|
||||
uint8_t reqState; /*!< Connection CTE Request state */
|
||||
uint8_t rspState; /*!< Connection CTE Response state */
|
||||
} dmConnCteCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
void dmConnCteInit(void);
|
||||
void dmConnCteReset(void);
|
||||
void dmConnCteHciHandler(hciEvt_t *pEvent);
|
||||
void dmConnCteMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*! Action functions */
|
||||
static void dmConnCteActRxSampleStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRxSampleStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActTxCfg(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActReqStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActReqStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRspStart(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActRspStop(dmConnCteMsg_t *pMsg);
|
||||
static void dmConnCteActState(dmConnCteMsg_t *pMsg);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table */
|
||||
static const dmConnCteAct_t dmConnCteAct[] =
|
||||
{
|
||||
dmConnCteActRxSampleStart,
|
||||
dmConnCteActRxSampleStop,
|
||||
dmConnCteActTxCfg,
|
||||
dmConnCteActReqStart,
|
||||
dmConnCteActReqStop,
|
||||
dmConnCteActRspStart,
|
||||
dmConnCteActRspStop,
|
||||
dmConnCteActState
|
||||
};
|
||||
|
||||
/*! DM Connection CTE component function interface */
|
||||
static const dmFcnIf_t dmConnCteFcnIf =
|
||||
{
|
||||
dmConnCteReset,
|
||||
dmConnCteHciHandler,
|
||||
dmConnCteMsgHandler
|
||||
};
|
||||
|
||||
/*! Connection CTE control block */
|
||||
static dmConnCteCb_t dmConnCteCb[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize connection CTE control block entry.
|
||||
*
|
||||
* \param pCteCb Pointer to connection CTE control block structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteCbInit(dmConnCteCb_t *pCteCb)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize connection CTE control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
dmConnCteCbInit(&dmConnCteCb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM Connection Constant Tone Extension (CTE) module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteInit(void)
|
||||
{
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_CONN_CTE] = (dmFcnIf_t *) &dmConnCteFcnIf;
|
||||
|
||||
/* initialize control block */
|
||||
dmConnCteInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the connection CTE module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteReset(void)
|
||||
{
|
||||
/* reset control block */
|
||||
dmConnCteInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_READ_ANTENNA_INFO_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if ccb found */
|
||||
if ((pCcb = dmConnCcbByHandle(pEvent->hdr.param)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* set conn id */
|
||||
pEvent->hdr.param = pCcb->connId;
|
||||
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_CONN_IQ_REPORT_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CONN_IQ_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CTE_REQ_FAILED_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CTE_REQ_FAIL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_CONN_CTE_RX_PARAMS_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling sampling */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_SAMPLING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RX_SAMPLE_START_IND;
|
||||
}
|
||||
/* else if disabling sampling */
|
||||
else if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_SAMPLING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RX_SAMPLE_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_CONN_CTE_TX_PARAMS_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_CONN_CTE_TX_CFG_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CONN_CTE_REQ_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling request */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_INITIATING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_REQ_START_IND;
|
||||
}
|
||||
/* else if disabing request */
|
||||
else if (pCteCb->reqState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_INITIATING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_REQ_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_CONN_CTE_RSP_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
/* if enabling response */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_STARTING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_RESPONDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RSP_START_IND;
|
||||
}
|
||||
/* else if disabling response */
|
||||
else if (pCteCb->rspState == DM_CONN_CTE_STATE_STOPPING)
|
||||
{
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_RESPONDING;
|
||||
}
|
||||
|
||||
pEvent->hdr.event = DM_CONN_CTE_RSP_STOP_IND;
|
||||
}
|
||||
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM Connection CTE event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmConnCteAct[DM_MSG_MASK(pMsg->event)])((dmConnCteMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start sampling received CTE, and configure CTE receive parameters action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActRxSampleStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rxSampleStart.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeSetConnCteRxParamsCmd(pCcb->handle, TRUE, pMsg->rxSampleStart.slotDurations,
|
||||
pMsg->rxSampleStart.switchPatternLen,
|
||||
pMsg->rxSampleStart.pAntennaIDs);
|
||||
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRxSampleStart ignored due to rxSampleState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop sampling received CTE action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActRxSampleStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rxSampleStop.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently sampling */
|
||||
if (pCteCb->rxSampleState == DM_CONN_CTE_STATE_SAMPLING)
|
||||
{
|
||||
HciLeSetConnCteRxParamsCmd(pCcb->handle, FALSE, 0, 0, NULL);
|
||||
|
||||
pCteCb->rxSampleState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRxSampleStop ignored due to rxSampleState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure connection CTE transmit action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActTxCfg(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->txCfg.connId)) != NULL)
|
||||
{
|
||||
HciLeSetConnCteTxParamsCmd(pCcb->handle, pMsg->txCfg.cteTypeBits, pMsg->txCfg.switchPatternLen,
|
||||
pMsg->txCfg.pAntennaIDs);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start initiating CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActReqStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->reqStart.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeConnCteReqEnableCmd(pCcb->handle, TRUE, pMsg->reqStart.cteReqInt,
|
||||
pMsg->reqStart.reqCteLen, pMsg->reqStart.reqCteType);
|
||||
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteReqStart ignored due to reqState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop initiating CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnCteActReqStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->reqStop.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently initiating */
|
||||
if (pCteCb->reqState == DM_CONN_CTE_STATE_INITIATING)
|
||||
{
|
||||
HciLeConnCteReqEnableCmd(pCcb->handle, FALSE, 0, 0, 0);
|
||||
|
||||
pCteCb->reqState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteReqStop ignored due to reqState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start responding to CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActRspStart(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rspEnable.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently idle */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_IDLE)
|
||||
{
|
||||
HciLeConnCteRspEnableCmd(pCcb->handle, TRUE);
|
||||
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_STARTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRspStart ignored due to rspState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop responding to CTE request action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActRspStop(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->rspEnable.connId)) != NULL)
|
||||
{
|
||||
dmConnCteCb_t *pCteCb = &dmConnCteCb[pCcb->connId - 1];
|
||||
|
||||
/* if currently responding */
|
||||
if (pCteCb->rspState == DM_CONN_CTE_STATE_RESPONDING)
|
||||
{
|
||||
HciLeConnCteRspEnableCmd(pCcb->handle, FALSE);
|
||||
|
||||
pCteCb->rspState = DM_CONN_CTE_STATE_STOPPING;
|
||||
}
|
||||
else
|
||||
{
|
||||
DM_TRACE_WARN0("DmConnCteRspStop ignored due to rspState or pending command complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection state change action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnCteActState(dmConnCteMsg_t *pMsg)
|
||||
{
|
||||
/* if connection closed */
|
||||
if (pMsg->hdr.status == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* reset all states */
|
||||
dmConnCteCbInit(&dmConnCteCb[pMsg->hdr.param - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable sampling received CTE fields on the specified connection, and configure the
|
||||
* antenna switching pattern, and switching and sampling slot durations to be used.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param slotDurations Switching and sampling slot durations to be used while receiving CTE.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRxSampleStart(dmConnId_t connId, uint8_t slotDurations, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
dmConnCteApiRxSampleStart_t *pMsg;
|
||||
|
||||
WSF_ASSERT((switchPatternLen >= HCI_MIN_NUM_ANTENNA_IDS) && \
|
||||
(switchPatternLen <= HCI_MAX_NUM_ANTENNA_IDS));
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRxSampleStart_t) + switchPatternLen)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RX_SAMPLE_START;
|
||||
pMsg->connId = connId;
|
||||
pMsg->slotDurations = slotDurations;
|
||||
pMsg->switchPatternLen = switchPatternLen;
|
||||
|
||||
/* Copy antenna IDs to space after end of config struct */
|
||||
pMsg->pAntennaIDs = (uint8_t *)(pMsg + 1);
|
||||
memcpy(pMsg->pAntennaIDs, pAntennaIDs, switchPatternLen);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Disable sampling received CTE fields on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRxSampleStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRxSampleStop_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRxSampleStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure the antenna switching pattern, and permitted CTE types used for transmitting
|
||||
* CTEs requested by the peer device on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param cteTypeBits Permitted CTE type bits used for transmitting CTEs requested by peer.
|
||||
* \param switchPatternLen Number of Antenna IDs in switching pattern.
|
||||
* \param pAntennaIDs List of Antenna IDs in switching pattern.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteTxConfig(dmConnId_t connId, uint8_t cteTypeBits, uint8_t switchPatternLen,
|
||||
uint8_t *pAntennaIDs)
|
||||
{
|
||||
dmConnCteApiTxConfig_t *pMsg;
|
||||
|
||||
WSF_ASSERT((switchPatternLen >= HCI_MIN_NUM_ANTENNA_IDS) && \
|
||||
(switchPatternLen <= HCI_MAX_NUM_ANTENNA_IDS));
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiTxConfig_t) + switchPatternLen)) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_TX_CFG;
|
||||
pMsg->connId = connId;
|
||||
pMsg->cteTypeBits = cteTypeBits;
|
||||
pMsg->switchPatternLen = switchPatternLen;
|
||||
|
||||
/* Copy antenna IDs to space after end of config struct */
|
||||
pMsg->pAntennaIDs = (uint8_t *)(pMsg + 1);
|
||||
memcpy(pMsg->pAntennaIDs, pAntennaIDs, switchPatternLen);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate the CTE Request procedure on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param cteReqInt CTE request interval.
|
||||
* \param reqCteLen Minimum length of CTE being requested in 8 us units.
|
||||
* \param reqCteType Requested CTE type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteReqStart(dmConnId_t connId, uint16_t cteReqInt, uint8_t reqCteLen,
|
||||
uint8_t reqCteType)
|
||||
{
|
||||
dmConnCteApiReqStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiReqStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_REQ_START;
|
||||
pMsg->connId = connId;
|
||||
pMsg->cteReqInt = cteReqInt;
|
||||
pMsg->reqCteLen = reqCteLen;
|
||||
pMsg->reqCteType = reqCteType;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop initiating the CTE Request procedure on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteReqStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiReqStop_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiReqStop_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_REQ_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start responding to LL_CTE_REQ PDUs with LL_CTE_RSP PDUs on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRspStart(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRspEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRspEnable_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RSP_START;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop responding to LL_CTE_REQ PDUs with LL_CTE_RSP PDUs on the specified connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnCteRspStop(dmConnId_t connId)
|
||||
{
|
||||
dmConnCteApiRspEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmConnCteApiRspEnable_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_CONN_CTE_MSG_API_RSP_STOP;
|
||||
pMsg->connId = connId;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the switching rates, the sampling rates, the number of antennae, and the maximum
|
||||
* length of a transmitted Constant Tone Extension supported by the Controller.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \note The antenna info will be returned with DM indication \ref DM_READ_ANTENNA_INFO_IND.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmReadAntennaInfo(void)
|
||||
{
|
||||
HciLeReadAntennaInfoCmd();
|
||||
}
|
||||
Vendored
+145
@@ -0,0 +1,145 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for master.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_os.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel an opening connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActCancelOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* cancel create connection */
|
||||
HciLeCreateConnCancelCmd();
|
||||
|
||||
/* pass connection initiation stopped to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_STOP, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update a connection as a master.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActUpdateMaster(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* send HCI command */
|
||||
HciLeConnUpdateCmd(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an L2CAP connection update indication.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActL2cUpdateInd(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* always send back response */
|
||||
L2cDmConnUpdateRsp(pMsg->l2cUpdateInd.identifier, pCcb->handle, L2C_CONN_PARAM_ACCEPTED);
|
||||
|
||||
/* send HCI command */
|
||||
HciLeConnUpdateCmd(pCcb->handle, pMsg->l2cUpdateInd.pConnSpec);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function when it receives a connection update
|
||||
* request from a peer device.
|
||||
*
|
||||
* \param identifier Identifier value.
|
||||
* \param handle Connection handle.
|
||||
* \param pConnSpec Connection spec parameters.
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cConnUpdateInd(uint8_t identifier, uint16_t handle, hciConnSpec_t *pConnSpec)
|
||||
{
|
||||
dmConnL2cUpdateInd_t updateInd;
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if ((pCcb = dmConnCcbByHandle(handle)) != NULL)
|
||||
{
|
||||
updateInd.hdr.event = DM_CONN_MSG_L2C_UPDATE_IND;
|
||||
updateInd.pConnSpec = pConnSpec;
|
||||
updateInd.identifier = identifier;
|
||||
|
||||
dmConnSmExecute(pCcb, (dmConnMsg_t *) &updateInd);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param clientId The client identifier.
|
||||
* \param initPhys Initiator PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmConnId_t DmConnOpen(uint8_t clientId, uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
return dmConnOpenAccept(clientId, initPhys, 0, 0, 0, 0, addrType, pAddr, DM_ROLE_MASTER);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used for connections created with DmConnOpen().
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.connAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management module for extended master.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetMaster[] =
|
||||
{
|
||||
dmExtConnSmActOpen,
|
||||
dmConnSmActCancelOpen,
|
||||
dmConnSmActUpdateMaster,
|
||||
dmConnSmActL2cUpdateInd
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param initPhys Initiating PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmExtConnOpen(uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t idx;
|
||||
uint8_t phyIdx;
|
||||
hciExtInitParam_t initParam;
|
||||
hciConnSpec_t connSpec[DM_NUM_PHYS];
|
||||
hciExtInitScanParam_t scanParam[DM_NUM_PHYS];
|
||||
|
||||
/* set initiating parameters */
|
||||
initParam.filterPolicy = dmCb.initFiltPolicy;
|
||||
initParam.ownAddrType = DmLlAddrType(dmCb.connAddrType);
|
||||
initParam.peerAddrType = addrType;
|
||||
initParam.pPeerAddr = pAddr;
|
||||
initParam.initPhys = initPhys;
|
||||
|
||||
/* see advertising packets to be received on which PHY */
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (initPhys & (1 << i))
|
||||
{
|
||||
phyIdx = DmInitPhyToIdx(1 << i);
|
||||
|
||||
/* set extended create conection parameters for this PHY */
|
||||
scanParam[idx].scanInterval = dmConnCb.scanInterval[phyIdx];
|
||||
scanParam[idx].scanWindow = dmConnCb.scanWindow[phyIdx];
|
||||
connSpec[idx] = dmConnCb.connSpec[phyIdx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create connection */
|
||||
HciLeExtCreateConnCmd(&initParam, scanParam, connSpec);
|
||||
|
||||
/* pass connection initiation started to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_START, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtConnOpen(pMsg->apiOpen.initPhys, pMsg->apiOpen.addrType, pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as extended master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtConnMasterInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_MASTER] = (dmConnAct_t *) dmConnActSetMaster;
|
||||
}
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management module for legacy master.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetMaster[] =
|
||||
{
|
||||
dmConnSmActOpen,
|
||||
dmConnSmActCancelOpen,
|
||||
dmConnSmActUpdateMaster,
|
||||
dmConnSmActL2cUpdateInd
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection to a peer device with the given address.
|
||||
*
|
||||
* \param initPhys Initiating PHYs.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnOpen(uint8_t initPhys, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
uint8_t phyIdx = DmScanPhyToIdx(HCI_SCAN_PHY_LE_1M_BIT);
|
||||
|
||||
/* Create connection */
|
||||
HciLeCreateConnCmd(dmConnCb.scanInterval[phyIdx], dmConnCb.scanWindow[phyIdx], dmCb.initFiltPolicy,
|
||||
addrType, pAddr, DmLlAddrType(dmCb.connAddrType), &(dmConnCb.connSpec[phyIdx]));
|
||||
|
||||
/* pass connection initiation started to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_CTRL, DM_DEV_PRIV_MSG_CONN_INIT_START, 0, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Open a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActOpen(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmConnOpen(pMsg->apiOpen.initPhys, pMsg->apiOpen.addrType, pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as legacy master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnMasterInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_MASTER] = (dmConnAct_t *) dmConnActSetMaster;
|
||||
}
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager slave connection management for slave.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Call application callback with the connection update complete event.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param status Status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmConnUpdateCback(dmConnCcb_t *pCcb, uint8_t status)
|
||||
{
|
||||
hciLeConnUpdateCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_CONN_UPDATE_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = status;
|
||||
evt.handle = pCcb->handle;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *) &evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update a connection as a slave.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActUpdateSlave(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
if ((pCcb->features & HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC) &&
|
||||
(HciGetLeSupFeat() & HCI_LE_SUP_FEAT_CONN_PARAM_REQ_PROC))
|
||||
{
|
||||
HciLeConnUpdateCmd(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
/* else if L2CAP connection update not already in progress */
|
||||
else if (!pCcb->updating)
|
||||
{
|
||||
pCcb->updating = TRUE;
|
||||
|
||||
/* send request via L2CAP */
|
||||
L2cDmConnUpdateReq(pCcb->handle, &pMsg->apiUpdate.connSpec);
|
||||
}
|
||||
/* else L2CAP connection update pending */
|
||||
else
|
||||
{
|
||||
/* call callback */
|
||||
dmConnUpdateCback(pCcb, (uint8_t) HCI_ERR_CMD_DISALLOWED);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an L2CAP connection update confirm.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActL2cUpdateCnf(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
/* if connection update in progress */
|
||||
if (pCcb->updating)
|
||||
{
|
||||
pCcb->updating = FALSE;
|
||||
|
||||
/* if reason indicates failure */
|
||||
if (pMsg->l2cUpdateCnf.result != L2C_CONN_PARAM_ACCEPTED)
|
||||
{
|
||||
/* call callback */
|
||||
dmConnUpdateCback(pCcb, (uint8_t) pMsg->l2cUpdateCnf.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function to send the result of an L2CAP
|
||||
* connection update response to DM.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
* \param result Connection update result code.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cConnUpdateCnf(uint16_t handle, uint16_t result)
|
||||
{
|
||||
dmConnL2cUpdateCnf_t updateCnf;
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if ((pCcb = dmConnCcbByHandle(handle)) != NULL)
|
||||
{
|
||||
updateCnf.hdr.event = DM_CONN_MSG_L2C_UPDATE_CNF;
|
||||
updateCnf.result = result;
|
||||
|
||||
dmConnSmExecute(pCcb, (dmConnMsg_t *) &updateCnf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For internal use only. L2C calls this function to send the result of an L2CAP
|
||||
* Command Reject indication up to the application.
|
||||
*
|
||||
* \param handle Connection handle.
|
||||
* \param result Connection update result code.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmL2cCmdRejInd(uint16_t handle, uint16_t result)
|
||||
{
|
||||
dmL2cCmdRejEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_L2C_CMD_REJ_IND;
|
||||
evt.hdr.status = HCI_SUCCESS;
|
||||
evt.reason = result;
|
||||
evt.handle = handle;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection from the given peer device by initiating directed advertising.
|
||||
*
|
||||
* \param clientId The client identifier.
|
||||
* \param advHandle Advertising handle.
|
||||
* \param advType Advertising type.
|
||||
* \param duration Advertising duration (in ms).
|
||||
* \param maxEaEvents Maximum number of extended advertising events.
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return Connection identifier.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
dmConnId_t DmConnAccept(uint8_t clientId, uint8_t advHandle, uint8_t advType, uint16_t duration,
|
||||
uint8_t maxEaEvents, uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
return dmConnOpenAccept(clientId, 0, advHandle, advType, duration, maxEaEvents, addrType, pAddr,
|
||||
DM_ROLE_SLAVE);
|
||||
}
|
||||
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for extended slave.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetSlave[] =
|
||||
{
|
||||
dmExtConnSmActAccept,
|
||||
dmExtConnSmActCancelAccept,
|
||||
dmConnSmActUpdateSlave,
|
||||
dmExtConnSmActConnAccepted,
|
||||
dmExtConnSmActAcceptFailed,
|
||||
dmConnSmActL2cUpdateCnf
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvStartDirected(pCcb->connId, pMsg->apiOpen.advHandle, pMsg->apiOpen.advType,
|
||||
pMsg->apiOpen.duration, pMsg->apiOpen.maxEaEvents, pMsg->apiOpen.addrType,
|
||||
pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel a connection accept.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvStopDirected(pCcb->connId);
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accepted.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvConnected(pCcb->connId);
|
||||
|
||||
dmConnSmActConnOpened(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accept failed.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmExtAdvConnectFailed(pCcb->connId);
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as extended slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtConnSlaveInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_SLAVE] = (dmConnAct_t *) dmConnActSetSlave;
|
||||
}
|
||||
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management for legacy slave.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_adv.h"
|
||||
#include "l2c_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Action set for this module */
|
||||
static const dmConnAct_t dmConnActSetSlave[] =
|
||||
{
|
||||
dmConnSmActAccept,
|
||||
dmConnSmActCancelAccept,
|
||||
dmConnSmActUpdateSlave,
|
||||
dmConnSmActConnAccepted,
|
||||
dmConnSmActAcceptFailed,
|
||||
dmConnSmActL2cUpdateCnf
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Accept a connection.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvStartDirected(pMsg->apiOpen.advType, pMsg->apiOpen.duration, pMsg->apiOpen.addrType,
|
||||
pMsg->apiOpen.peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cancel a connection accept.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActCancelAccept(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvStopDirected();
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accepted.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActConnAccepted(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvConnected();
|
||||
|
||||
dmConnSmActConnOpened(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Connection accept failed.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmActAcceptFailed(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmAdvConnectFailed();
|
||||
|
||||
dmConnSmActConnFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM connection manager for operation as legacy slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmConnSlaveInit(void)
|
||||
{
|
||||
dmConnActSet[DM_CONN_ACT_SET_SLAVE] = (dmConnAct_t *) dmConnActSetSlave;
|
||||
}
|
||||
Vendored
+187
@@ -0,0 +1,187 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager connection management state machine.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Column position of next state */
|
||||
#define DM_CONN_NEXT_STATE 0
|
||||
|
||||
/*! Column position of action */
|
||||
#define DM_CONN_ACTION 1
|
||||
|
||||
/*! Number of columns in the state machine state tables */
|
||||
#define DM_CONN_NUM_COLS 2
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM Conn state machine state tables */
|
||||
static const uint8_t dmConnStateTbl[DM_CONN_SM_NUM_STATES][DM_CONN_NUM_MSGS][DM_CONN_NUM_COLS] =
|
||||
{
|
||||
/* Idle state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_OPEN},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_ACCEPT},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_ACCEPTED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Connecting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CANCEL_OPEN},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_FAILED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_OPENED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_FAILED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_CONNECTING, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Accepting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CANCEL_ACCEPT},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_ACCEPT_FAILED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_CONN_ACCEPTED},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_ACCEPT_FAILED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_ACCEPTING, DM_CONN_SM_ACT_NONE}
|
||||
},
|
||||
/* Connected state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CLOSE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_UPDATE_MASTER},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_UPDATE_SLAVE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_L2C_UPDATE_IND},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_L2C_UPDATE_CNF},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_HCI_UPDATED},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_CONNECTED, DM_CONN_SM_ACT_HCI_UPDATED}
|
||||
},
|
||||
/* Disconnecting state */
|
||||
{
|
||||
/* Event Next state Action */
|
||||
/* API_OPEN */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_CLOSE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_ACCEPT */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_MASTER */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* API_UPDATE_SLAVE */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_IND */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* L2C_UPDATE_CNF */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CONN_CMPL_FAIL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_CLOSE},
|
||||
/* HCI_DISCONNECT_CMPL */ {DM_CONN_SM_ST_IDLE, DM_CONN_SM_ACT_CONN_CLOSED},
|
||||
/* HCI_LE_CONN_UPDATE_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE},
|
||||
/* INT_UPDATE_TIMEOUT */ {DM_CONN_SM_ST_DISCONNECTING, DM_CONN_SM_ACT_NONE}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! State machine action set array */
|
||||
dmConnAct_t *dmConnActSet[DM_CONN_NUM_ACT_SETS];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the DM connection state machine.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmConnSmExecute(dmConnCcb_t *pCcb, dmConnMsg_t *pMsg)
|
||||
{
|
||||
dmConnAct_t *actSet;
|
||||
uint8_t action;
|
||||
uint8_t event;
|
||||
|
||||
DM_TRACE_INFO2("dmConnSmExecute event=%d state=%d", pMsg->hdr.event, pCcb->state);
|
||||
|
||||
/* get the event */
|
||||
event = DM_MSG_MASK(pMsg->hdr.event);
|
||||
|
||||
/* get action */
|
||||
action = dmConnStateTbl[pCcb->state][event][DM_CONN_ACTION];
|
||||
|
||||
/* set next state */
|
||||
pCcb->state = dmConnStateTbl[pCcb->state][event][DM_CONN_NEXT_STATE];
|
||||
|
||||
/* look up action set */
|
||||
actSet = dmConnActSet[DM_CONN_ACT_SET_ID(action)];
|
||||
|
||||
/* if action set present */
|
||||
if (actSet != NULL)
|
||||
{
|
||||
/* execute action function in action set */
|
||||
(*actSet[DM_CONN_ACT_ID(action)])(pCcb, pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no action */
|
||||
dmConnSmActNone(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM local device management module.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmDevAct_t dmDevAct[] =
|
||||
{
|
||||
dmDevActReset
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
const dmFcnIf_t dmDevFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmDevHciHandler,
|
||||
dmDevMsgHandler
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmDevCb_t dmDevCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevActReset(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if DM not resetting */
|
||||
if (!dmCb.resetting)
|
||||
{
|
||||
/* set resetting state */
|
||||
dmCb.resetting = TRUE;
|
||||
|
||||
/* for each DM component */
|
||||
for (i = 0; i < DM_NUM_IDS; i++)
|
||||
{
|
||||
/* call component's reset function */
|
||||
(*(dmFcnIfTbl[i]->reset))();
|
||||
}
|
||||
|
||||
/* start HCI reset sequence */
|
||||
HciResetSequence();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a reset complete event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtReset(hciEvt_t *pEvent)
|
||||
{
|
||||
/* reset resetting state */
|
||||
dmCb.resetting = FALSE;
|
||||
|
||||
pEvent->hdr.event = DM_RESET_CMPL_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a vendor specific event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtVendorSpec(hciEvt_t *pEvent)
|
||||
{
|
||||
pEvent->hdr.event = DM_VENDOR_SPEC_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an hardware error event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevHciEvtHwError(hciEvt_t *pEvent)
|
||||
{
|
||||
pEvent->hdr.event = DM_HW_ERROR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_RESET_SEQ_CMPL_CBACK_EVT:
|
||||
dmDevHciEvtReset(pEvent);
|
||||
break;
|
||||
|
||||
case HCI_VENDOR_SPEC_CBACK_EVT:
|
||||
dmDevHciEvtVendorSpec(pEvent);
|
||||
break;
|
||||
|
||||
case HCI_HW_ERROR_CBACK_EVT:
|
||||
dmDevHciEvtHwError(pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore event */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM dev event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmDevAct[DM_MSG_MASK(pMsg->event)])(pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass an event to the device privacy module.
|
||||
*
|
||||
* \param event Device privacy event.
|
||||
* \param param DM or Privacy event.
|
||||
* \param advHandle Advertising handle.
|
||||
* \param connectable TRUE if connectable extended advertising. FALSE, otherwise.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassEvtToDevPriv(uint8_t event, uint8_t param, uint8_t advHandle, bool_t connectable)
|
||||
{
|
||||
dmDevPrivMsg_t evt;
|
||||
|
||||
DM_TRACE_INFO3("dmDevPassEvtToDevPriv: event: %d, param: %d, advHandle: %d", event, param, advHandle);
|
||||
|
||||
/* build event */
|
||||
evt.hdr.event = event;
|
||||
evt.hdr.param = param;
|
||||
evt.privCtrl.advHandle = advHandle;
|
||||
evt.privCtrl.connectable = connectable;
|
||||
|
||||
/* pass event to device privacy */
|
||||
(*(dmFcnIfTbl[DM_ID_DEV_PRIV]->msgHandler))((wsfMsgHdr_t *) &evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass a connection state change event to the Connection CTE module.
|
||||
*
|
||||
* \param state Connection state.
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassEvtToConnCte(uint8_t state, dmConnId_t connId)
|
||||
{
|
||||
wsfMsgHdr_t evt;
|
||||
|
||||
/* build event */
|
||||
evt.event = DM_CONN_CTE_MSG_STATE;
|
||||
evt.status = state;
|
||||
evt.param = connId;
|
||||
|
||||
/* pass event to Connection CTE */
|
||||
(*(dmFcnIfTbl[DM_ID_CONN_CTE]->msgHandler))(&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the device.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevReset(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_DEV_MSG_API_RESET;
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the random address to be used by the local device.
|
||||
*
|
||||
* \param pAddr Random address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevSetRandAddr(uint8_t *pAddr)
|
||||
{
|
||||
BdaCpy(dmCb.localAddr, pAddr);
|
||||
HciLeSetRandAddrCmd(pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add a peer device to the white list. Note that this function cannot be called
|
||||
* while advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListAdd(uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
HciLeAddDevWhiteListCmd(addrType, pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove a peer device from the white list. Note that this function cannot be called
|
||||
* while advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
* \param pAddr Peer device address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListRemove(uint8_t addrType, uint8_t *pAddr)
|
||||
{
|
||||
HciLeRemoveDevWhiteListCmd(addrType, pAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear the white list. Note that this function cannot be called while
|
||||
* advertising, scanning, or connecting with white list filtering active.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevWhiteListClear(void)
|
||||
{
|
||||
HciLeClearWhiteListCmd();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising, Scanning or Initiator filter policy.
|
||||
*
|
||||
* \param advHandle Advertising handle (only applicable to advertising).
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t dmDevSetFilterPolicy(uint8_t advHandle, uint8_t mode, uint8_t policy)
|
||||
{
|
||||
bool_t policySet = FALSE;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DM_FILT_POLICY_MODE_ADV:
|
||||
/* if Advertising filter policy is valid */
|
||||
if (policy <= HCI_ADV_FILT_ALL)
|
||||
{
|
||||
WSF_ASSERT(advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* update the filter policy */
|
||||
dmCb.advFiltPolicy[advHandle] = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_SCAN:
|
||||
/* if Scanning filter policy is valid */
|
||||
if (policy <= HCI_FILT_WHITE_LIST_RES_INIT)
|
||||
{
|
||||
/* update the filter policy */
|
||||
dmCb.scanFiltPolicy = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_INIT:
|
||||
/* if Initiator filter policy is valid */
|
||||
if (policy <= HCI_FILT_WHITE_LIST)
|
||||
{
|
||||
/* update the filter policy */
|
||||
dmCb.initFiltPolicy = policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_FILT_POLICY_MODE_SYNC:
|
||||
/* if Synchronization filter policy is valid */
|
||||
if (policy <= HCI_FILT_PER_ADV_LIST)
|
||||
{
|
||||
/* clear the filter policy bit */
|
||||
dmCb.syncOptions &= ~HCI_OPTIONS_FILT_POLICY_BIT;
|
||||
|
||||
/* set the filter policy bit */
|
||||
dmCb.syncOptions |= policy;
|
||||
policySet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid filter policy mode */
|
||||
break;
|
||||
}
|
||||
|
||||
return policySet;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising, Scanning or Initiator filter policy.
|
||||
*
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmDevSetFilterPolicy(uint8_t mode, uint8_t policy)
|
||||
{
|
||||
return dmDevSetFilterPolicy(DM_ADV_HANDLE_DEFAULT, mode, policy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the Advertising filter policy for the given advertising, Scanning or Initiator
|
||||
* filter policy.
|
||||
*
|
||||
* \param advHandle Advertising handle (only applicable to advertising).
|
||||
* \param mode Policy mode.
|
||||
* \param policy Filter policy.
|
||||
*
|
||||
* \return TRUE if the filter policy was successfully set, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmDevSetExtFilterPolicy(uint8_t advHandle, uint8_t mode, uint8_t policy)
|
||||
{
|
||||
return dmDevSetFilterPolicy(advHandle, mode, policy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Vendor-specific controller initialization function.
|
||||
*
|
||||
* \param param Vendor-specific parameter.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevVsInit(uint8_t param)
|
||||
{
|
||||
HciVsInit(param);
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM local device management module.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_DEV_H
|
||||
#define DM_DEV_H
|
||||
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM device event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_MSG_API_RESET = DM_MSG_START(DM_ID_DEV)
|
||||
};
|
||||
|
||||
/* DM device privacy event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_PRIV_MSG_API_START = DM_MSG_START(DM_ID_DEV_PRIV),
|
||||
DM_DEV_PRIV_MSG_API_STOP,
|
||||
DM_DEV_PRIV_MSG_TIMEOUT,
|
||||
DM_DEV_PRIV_MSG_AES_CMPL,
|
||||
DM_DEV_PRIV_MSG_RPA_START,
|
||||
DM_DEV_PRIV_MSG_RPA_STOP,
|
||||
DM_DEV_PRIV_MSG_CTRL,
|
||||
};
|
||||
|
||||
/* DM device privacy control messages */
|
||||
enum
|
||||
{
|
||||
DM_DEV_PRIV_MSG_CONN_INIT_START, /* connection initiation started */
|
||||
DM_DEV_PRIV_MSG_CONN_INIT_STOP, /* connection initiation stopped */
|
||||
DM_DEV_PRIV_MSG_ADV_SET_ADD, /* advertising set created */
|
||||
DM_DEV_PRIV_MSG_ADV_SET_REMOVE, /* advertising set removed */
|
||||
DM_DEV_PRIV_MSG_ADV_SETS_CLEAR /* advertising sets cleared */
|
||||
};
|
||||
|
||||
/*! DM connection CTE event handler messages */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_CONN_CTE_MSG_API_RX_SAMPLE_START = DM_MSG_START(DM_ID_CONN_CTE), /*!< Start sampling received CTE, and configure CTE Rx parameters to be used */
|
||||
DM_CONN_CTE_MSG_API_RX_SAMPLE_STOP, /*!< Stop sampling received CTE */
|
||||
DM_CONN_CTE_MSG_API_TX_CFG, /*!< Configure CTE Tx parameters */
|
||||
DM_CONN_CTE_MSG_API_REQ_START, /*!< Start initiating CTE request */
|
||||
DM_CONN_CTE_MSG_API_REQ_STOP, /*!< Stop initiating CTE request */
|
||||
DM_CONN_CTE_MSG_API_RSP_START, /*!< Start responding to CTE request */
|
||||
DM_CONN_CTE_MSG_API_RSP_STOP, /*!< Stop responding to CTE request */
|
||||
DM_CONN_CTE_MSG_STATE /*!< DM connection state change event */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_DEV_PRIV_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint16_t changeInterval;
|
||||
} dmDevPrivApiStart_t;
|
||||
|
||||
/* Data structure for DM_DEV_PRIV_MSG_CTRL */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advHandle;
|
||||
bool_t connectable;
|
||||
} dmDevPrivCtrl_t;
|
||||
|
||||
/* Union of all dev priv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmDevPrivApiStart_t apiPrivStart;
|
||||
dmDevPrivCtrl_t privCtrl;
|
||||
secAes_t aes;
|
||||
} dmDevPrivMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmDevAct_t)(wsfMsgHdr_t *pMsg);
|
||||
typedef void (*dmDevPrivAct_t)(dmDevPrivMsg_t *pMsg);
|
||||
|
||||
/* DM device set advertising set random address callback type */
|
||||
typedef void (*dmDevAdvSetRandAddrCback_t)(uint8_t advHandle, const uint8_t *pAddr);
|
||||
|
||||
/* Main control block of the DM Dev subsystem */
|
||||
typedef struct
|
||||
{
|
||||
/* Set advertising set random address callback */
|
||||
dmDevAdvSetRandAddrCback_t advSetRandAddrCback;
|
||||
} dmDevCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
extern const dmFcnIf_t dmDevFcnIf;
|
||||
|
||||
/* Control block */
|
||||
extern dmDevCb_t dmDevCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* dev component inteface */
|
||||
void dmDevActReset(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/* dev action functions */
|
||||
void dmDevMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmDevHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* dev priv component inteface */
|
||||
void dmDevPrivHciHandler(hciEvt_t *pEvent);
|
||||
void dmDevPrivMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmDevPrivReset(void);
|
||||
|
||||
/* dev priv action functions */
|
||||
void dmDevPrivActStart(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActStop(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActTimeout(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActAesCmpl(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActRpaStart(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActRpaStop(dmDevPrivMsg_t *pMsg);
|
||||
void dmDevPrivActCtrl(dmDevPrivMsg_t *pMsg);
|
||||
|
||||
/* utility function */
|
||||
void dmDevPassEvtToDevPriv(uint8_t event, uint8_t param, uint8_t advHandle, bool_t connectable);
|
||||
void dmDevPassEvtToConnCte(uint8_t state, dmConnId_t connId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_DEV_H */
|
||||
Vendored
+653
@@ -0,0 +1,653 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager device privacy module.
|
||||
*
|
||||
* Copyright (c) 2009-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "hci_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Structure for extended advertising */
|
||||
typedef struct
|
||||
{
|
||||
bool_t configured;
|
||||
bool_t connectable;
|
||||
bool_t advertising;
|
||||
} dmDevPrivExtAdv_t;
|
||||
|
||||
/* Control block for device privacy module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t addrTimer;
|
||||
bool_t addrTimerStarted;
|
||||
uint8_t prand[DM_PRIV_PRAND_LEN];
|
||||
uint16_t changeInterval;
|
||||
bool_t useResolvable;
|
||||
bool_t addrInitialized;
|
||||
bdAddr_t pendingAddr;
|
||||
bool_t advertising;
|
||||
bool_t scanning;
|
||||
bool_t connecting;
|
||||
bool_t connected;
|
||||
dmDevPrivExtAdv_t extAdv[DM_NUM_ADV_SETS];
|
||||
} dmDevPrivCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmDevPrivAct_t dmDevPrivAct[] =
|
||||
{
|
||||
dmDevPrivActStart,
|
||||
dmDevPrivActStop,
|
||||
dmDevPrivActTimeout,
|
||||
dmDevPrivActAesCmpl,
|
||||
dmDevPrivActRpaStart,
|
||||
dmDevPrivActRpaStop,
|
||||
dmDevPrivActCtrl
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmDevPrivFcnIf =
|
||||
{
|
||||
dmDevPrivReset,
|
||||
dmDevPrivHciHandler,
|
||||
dmDevPrivMsgHandler
|
||||
};
|
||||
|
||||
/* control block */
|
||||
static dmDevPrivCb_t dmDevPrivCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether the legacy advertising or an advertising set using (non)connectable advertising
|
||||
* is enabled.
|
||||
*
|
||||
* \param nonconnectable Non-connectable advertising.
|
||||
*
|
||||
* \return TRUE if advertising is enabled. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t dmDevPrivAdvertising(bool_t nonconnectable)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* if legacy advertising enabled */
|
||||
if (dmDevPrivCb.advertising)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* if (non)connectable extended advertising is enabled */
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
if (dmDevPrivCb.extAdv[i].configured &&
|
||||
dmDevPrivCb.extAdv[i].advertising &&
|
||||
(dmDevPrivCb.extAdv[i].connectable || nonconnectable))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start the address generation timer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivTimerStart(void)
|
||||
{
|
||||
/* if LL Privacy not enabled and device advertising, scanning or connected */
|
||||
if (!dmCb.llPrivEnabled && (dmDevPrivAdvertising(TRUE) || dmDevPrivCb.scanning || dmDevPrivCb.connected))
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivCb.addrTimerStarted = TRUE;
|
||||
dmDevPrivCb.addrTimer.msg.event = DM_DEV_PRIV_MSG_TIMEOUT;
|
||||
WsfTimerStartSec(&dmDevPrivCb.addrTimer, dmDevPrivCb.changeInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start resolvable address calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivAddrCalc(void)
|
||||
{
|
||||
uint8_t buf[DM_PRIV_PLAINTEXT_LEN];
|
||||
|
||||
/* get random number */
|
||||
SecRand(buf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set address type in random number */
|
||||
buf[2] = (buf[2] & 0x3F) | DM_RAND_ADDR_RESOLV;
|
||||
|
||||
/* pad buffer */
|
||||
memset(buf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* run calculation */
|
||||
SecAes(DmSecGetLocalIrk(), buf, dmCb.handlerId, 0, DM_DEV_PRIV_MSG_AES_CMPL);
|
||||
|
||||
/* store random number */
|
||||
memcpy(dmDevPrivCb.prand, buf, DM_PRIV_PRAND_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the RPA to be used by the local device.
|
||||
*
|
||||
* \param pAddr New RPA.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivSetRpa(uint8_t *pAddr)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* set new RPA as local address */
|
||||
BdaCpy(dmCb.localAddr, pAddr);
|
||||
|
||||
/* set RPA in device */
|
||||
HciLeSetRandAddrCmd(dmCb.localAddr);
|
||||
|
||||
if (dmDevCb.advSetRandAddrCback)
|
||||
{
|
||||
for (i = 0; i < DM_NUM_ADV_SETS; i++)
|
||||
{
|
||||
if (dmDevPrivCb.extAdv[i].configured)
|
||||
{
|
||||
/* set RPA for advertising set */
|
||||
(*dmDevCb.advSetRandAddrCback)(i, dmCb.localAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the pending RPA to be used by the local device.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmDevPrivSetPendingRpa(void)
|
||||
{
|
||||
/* if not advertising, scanning or initiating connection, and new RPA has been generated */
|
||||
if (!(dmDevPrivAdvertising(FALSE) || dmDevPrivCb.scanning || dmDevPrivCb.connecting) &&
|
||||
!BdaIsZeros(dmDevPrivCb.pendingAddr))
|
||||
{
|
||||
/* use pending RPA as local address */
|
||||
dmDevPrivSetRpa(dmDevPrivCb.pendingAddr);
|
||||
|
||||
/* clear out pending RPA */
|
||||
memset(dmDevPrivCb.pendingAddr, 0, BDA_ADDR_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start device privacy action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActStart(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* initialize and store parameters */
|
||||
dmDevPrivCb.useResolvable = TRUE;
|
||||
dmDevPrivCb.changeInterval = pMsg->apiPrivStart.changeInterval;
|
||||
dmDevPrivCb.addrTimer.handlerId = dmCb.handlerId;
|
||||
|
||||
/* set the local address type to random */
|
||||
DmAdvSetAddrType(DM_ADDR_RANDOM);
|
||||
DmScanSetAddrType(DM_ADDR_RANDOM);
|
||||
DmConnSetAddrType(DM_ADDR_RANDOM);
|
||||
|
||||
/* start the address generation timer if applicable */
|
||||
if (dmDevPrivCb.changeInterval > 0)
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
|
||||
/* if LL Privacy is supported */
|
||||
if (HciLlPrivacySupported())
|
||||
{
|
||||
/* Set LL resolvable private address timeout */
|
||||
DmPrivSetResolvablePrivateAddrTimeout(dmDevPrivCb.changeInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/* if private address has never been generated */
|
||||
if (dmDevPrivCb.addrInitialized == FALSE)
|
||||
{
|
||||
/* start address calculation */
|
||||
dmDevPrivAddrCalc();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop device privacy action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActStop(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* stop address generation timer */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
|
||||
dmDevPrivCb.useResolvable = FALSE;
|
||||
memset(dmDevPrivCb.pendingAddr, 0, BDA_ADDR_LEN);
|
||||
|
||||
/* set the local address type to public */
|
||||
DmAdvSetAddrType(DM_ADDR_PUBLIC);
|
||||
DmScanSetAddrType(DM_ADDR_PUBLIC);
|
||||
DmConnSetAddrType(DM_ADDR_PUBLIC);
|
||||
|
||||
/* if LL Privacy is supported */
|
||||
if (HciLlPrivacySupported())
|
||||
{
|
||||
/* remove all devices from resolving list and disable LL Privacy */
|
||||
DmPrivClearResList();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a private address generation timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActTimeout(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
/* if Host Privacy still enabled */
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* address generation timer has timed out */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
|
||||
/* restart address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
|
||||
/* start address calculation */
|
||||
dmDevPrivAddrCalc();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle AES calculation complete.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActAesCmpl(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
bdAddr_t localAddr;
|
||||
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* build and store address; hash is in ls bytes, random part in ms bytes */
|
||||
memcpy(localAddr, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN);
|
||||
memcpy(&localAddr[DM_PRIV_HASH_LEN], dmDevPrivCb.prand, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set generated address as random resolvable */
|
||||
DM_RAND_ADDR_SET(localAddr, DM_RAND_ADDR_RESOLV);
|
||||
|
||||
/* if not advertising, scanning or initiating connection */
|
||||
if (!(dmDevPrivAdvertising(FALSE) || dmDevPrivCb.scanning || dmDevPrivCb.connecting))
|
||||
{
|
||||
/* use new RPA as local address */
|
||||
dmDevPrivSetRpa(localAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* save new RPA for later */
|
||||
BdaCpy(dmDevPrivCb.pendingAddr, localAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy RPA start event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActRpaStart(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_ADV_START_IND:
|
||||
/* advertising started */
|
||||
dmDevPrivCb.advertising = TRUE;
|
||||
break;
|
||||
|
||||
case DM_ADV_SET_START_IND:
|
||||
/* extended advertising started */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].advertising = TRUE;
|
||||
break;
|
||||
|
||||
case DM_SCAN_START_IND:
|
||||
case DM_EXT_SCAN_START_IND:
|
||||
/* scanning started */
|
||||
dmDevPrivCb.scanning = TRUE;
|
||||
break;
|
||||
|
||||
case DM_CONN_OPEN_IND:
|
||||
/* connection opened */
|
||||
dmDevPrivCb.connected = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* LL Privacy disabled */
|
||||
break;
|
||||
}
|
||||
|
||||
/* if Host Privacy enabled and address generation timer not already running */
|
||||
if (dmDevPrivCb.useResolvable && !dmDevPrivCb.addrTimerStarted)
|
||||
{
|
||||
/* start address generation timer */
|
||||
dmDevPrivTimerStart();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy RPA stop event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActRpaStop(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_ADV_STOP_IND:
|
||||
/* advertising stopped */
|
||||
dmDevPrivCb.advertising = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_ADV_SET_STOP_IND:
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* extended advertising stopped */
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].advertising = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_SCAN_STOP_IND:
|
||||
case DM_EXT_SCAN_STOP_IND:
|
||||
/* scanning stopped */
|
||||
dmDevPrivCb.scanning = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
/* connection closed */
|
||||
dmDevPrivCb.connected = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* LL Privacy enabled see if address generation timer running */
|
||||
if (dmDevPrivCb.addrTimerStarted)
|
||||
{
|
||||
/* stop address generation timer (LL will generate RPAs) */
|
||||
dmDevPrivCb.addrTimerStarted = FALSE;
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* let address generation timer timeout (if still running) and update address */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a device privacy control event.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivActCtrl(dmDevPrivMsg_t *pMsg)
|
||||
{
|
||||
switch (pMsg->hdr.param)
|
||||
{
|
||||
case DM_DEV_PRIV_MSG_CONN_INIT_START:
|
||||
/* connection initiation started */
|
||||
dmDevPrivCb.connecting = TRUE;
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_CONN_INIT_STOP:
|
||||
/* connection initiation stopped */
|
||||
dmDevPrivCb.connecting = FALSE;
|
||||
|
||||
/* use pending RPA */
|
||||
dmDevPrivSetPendingRpa();
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SET_ADD:
|
||||
/* advertising set created */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].configured = TRUE;
|
||||
dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle].connectable = pMsg->privCtrl.connectable;
|
||||
|
||||
/* if Host Privacy enabled and private address has been generated */
|
||||
if (dmDevPrivCb.useResolvable && dmDevPrivCb.addrInitialized)
|
||||
{
|
||||
WSF_ASSERT(dmDevCb.advSetRandAddrCback != NULL);
|
||||
|
||||
/* set RPA for advertising set */
|
||||
(*dmDevCb.advSetRandAddrCback)(pMsg->privCtrl.advHandle, dmCb.localAddr);
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SET_REMOVE:
|
||||
/* advertising set removed */
|
||||
WSF_ASSERT(pMsg->privCtrl.advHandle < DM_NUM_ADV_SETS);
|
||||
|
||||
/* clear advertising set */
|
||||
/* note: advertising handle is checked before reaching this function */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
memset(&dmDevPrivCb.extAdv[pMsg->privCtrl.advHandle], 0, sizeof(dmDevPrivExtAdv_t));
|
||||
break;
|
||||
|
||||
case DM_DEV_PRIV_MSG_ADV_SETS_CLEAR:
|
||||
/* clear advertising sets */
|
||||
memset(dmDevPrivCb.extAdv, 0, sizeof(dmDevPrivCb.extAdv));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unknown state message */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM device priv HCI callback event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
/* if Host Privacy enabled */
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* handle incoming event */
|
||||
if (pEvent->hdr.event == HCI_LE_SET_RAND_ADDR_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmAdvNewAddrIndEvt_t msg;
|
||||
|
||||
msg.hdr.event = DM_ADV_NEW_ADDR_IND;
|
||||
msg.hdr.status = pEvent->hdr.status;
|
||||
BdaCpy(msg.addr, dmCb.localAddr);
|
||||
msg.firstTime = !dmDevPrivCb.addrInitialized;
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *) &msg);
|
||||
|
||||
dmDevPrivCb.addrInitialized = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM device privacy event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmDevPrivAct[DM_MSG_MASK(pMsg->event)])((dmDevPrivMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the device privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPrivReset(void)
|
||||
{
|
||||
if (dmDevPrivCb.useResolvable)
|
||||
{
|
||||
/* stop address generation timer */
|
||||
WsfTimerStop(&dmDevPrivCb.addrTimer);
|
||||
}
|
||||
|
||||
/* initialize control block */
|
||||
memset(&dmDevPrivCb, 0, sizeof(dmDevPrivCb));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize device privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_DEV_PRIV] = (dmFcnIf_t *) &dmDevPrivFcnIf;
|
||||
|
||||
/* initialize set advertising set random address callback */
|
||||
dmDevCb.advSetRandAddrCback = NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start using a private resolvable address.
|
||||
*
|
||||
* \param changeInterval Interval between automatic address changes, in seconds.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivStart(uint16_t changeInterval)
|
||||
{
|
||||
dmDevPrivApiStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmDevPrivApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_DEV_PRIV_MSG_API_START;
|
||||
pMsg->changeInterval = changeInterval;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop using a private resolvable address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmDevPrivStop(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_DEV_PRIV_MSG_API_STOP;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
+580
@@ -0,0 +1,580 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager main module.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "hci_api.h"
|
||||
#include "l2c_defs.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_dev.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* HCI callback event routing table */
|
||||
static const uint8_t dmHciToIdTbl[] =
|
||||
{
|
||||
DM_ID_DEV, /* HCI_RESET_SEQ_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CONN_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_ENHANCED_CONN_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_DISCONNECT_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CONN_UPDATE_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN, /* HCI_LE_CREATE_CONN_CANCEL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_RSSI_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_READ_CHAN_MAP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_TX_PWR_LVL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_READ_REMOTE_VER_INFO_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_READ_REMOTE_FEAT_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_REPL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_NEG_REPL_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_ENC_KEY_REFRESH_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_ENC_CHANGE_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_LTK_REQ_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CMD_STATUS_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_VENDOR_SPEC_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_HW_ERROR_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_ADD_DEV_TO_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_REM_DEV_FROM_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_CLEAR_RES_LIST_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_READ_PEER_RES_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_READ_LOCAL_RES_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PRIV, /* HCI_LE_SET_ADDR_RES_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_ENCRYPT_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_RAND_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_REP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_NEG_REP_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_READ_DEF_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_WRITE_DEF_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_SET_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_READ_MAX_DATA_LEN_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_REM_CONN_PARAM_REQ_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_LE_DATA_LEN_CHANGE_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_READ_LOCAL_P256_PUB_KEY_CMPL_CBACK_EVT */
|
||||
DM_ID_SEC, /* HCI_LE_GENERATE_DHKEY_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_WRITE_AUTH_PAYLOAD_TO_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_2, /* HCI_AUTH_PAYLOAD_TO_EXPIRED_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_READ_PHY_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_SET_DEF_PHY_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PHY, /* HCI_LE_PHY_UPDATE_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_EXT_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_SCAN_TIMEOUT_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_ADV_SET_TERM_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_SCAN_REQ_RCVD_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_SYNC_EST_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_REPORT_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_ADV_SYNC_LOST_CBACK_EVT */
|
||||
DM_ID_DEV, /* HCI_LE_CH_SEL_ALGO_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_SCAN_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SCAN, /* HCI_LE_EXT_SCAN_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV, /* HCI_LE_EXT_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_ADV_PER, /* HCI_LE_PER_ADV_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_DEV_PRIV, /* HCI_LE_SET_RAND_ADDR_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_SYNC, /* HCI_LE_PER_SYNC_TRSF_RCVD_CBACK_EVT */
|
||||
DM_ID_PAST, /* HCI_LE_PER_ADV_SYNC_TRSF_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_PAST, /* HCI_LE_PER_ADV_SET_INFO_TRSF_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_IQ_REPORT_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CTE_REQ_FAILED_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_SET_CONN_CTE_RX_PARAMS_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_SET_CONN_CTE_TX_PARAMS_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_REQ_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE, /* HCI_LE_CONN_CTE_RSP_ENABLE_CMD_CMPL_CBACK_EVT */
|
||||
DM_ID_CONN_CTE /* HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT */
|
||||
};
|
||||
|
||||
/* DM callback event length table */
|
||||
static const uint16_t dmEvtCbackLen[] =
|
||||
{
|
||||
sizeof(wsfMsgHdr_t), /* DM_RESET_CMPL_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ADV_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ADV_STOP_IND */
|
||||
sizeof(dmAdvNewAddrIndEvt_t), /* DM_ADV_NEW_ADDR_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SCAN_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SCAN_STOP_IND */
|
||||
sizeof(hciLeAdvReportEvt_t), /* DM_SCAN_REPORT_IND */
|
||||
sizeof(hciLeConnCmplEvt_t), /* DM_CONN_OPEN_IND */
|
||||
sizeof(hciDisconnectCmplEvt_t), /* DM_CONN_CLOSE_IND */
|
||||
sizeof(hciLeConnUpdateCmplEvt_t), /* DM_CONN_UPDATE_IND */
|
||||
sizeof(dmSecPairCmplIndEvt_t), /* DM_SEC_PAIR_CMPL_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SEC_PAIR_FAIL_IND */
|
||||
sizeof(dmSecEncryptIndEvt_t), /* DM_SEC_ENCRYPT_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_SEC_ENCRYPT_FAIL_IND */
|
||||
sizeof(dmSecAuthReqIndEvt_t), /* DM_SEC_AUTH_REQ_IND */
|
||||
sizeof(dmSecKeyIndEvt_t), /* DM_SEC_KEY_IND */
|
||||
sizeof(hciLeLtkReqEvt_t), /* DM_SEC_LTK_REQ_IND */
|
||||
sizeof(dmSecPairIndEvt_t), /* DM_SEC_PAIR_IND */
|
||||
sizeof(dmSecSlaveIndEvt_t), /* DM_SEC_SLAVE_REQ_IND */
|
||||
sizeof(dmSecOobCalcIndEvt_t), /* DM_SEC_CALC_OOB_IND */
|
||||
sizeof(secEccMsg_t), /* DM_SEC_ECC_KEY_IND */
|
||||
sizeof(dmSecCnfIndEvt_t), /* DM_SEC_COMPARE_IND */
|
||||
sizeof(dmSecKeypressIndEvt_t), /* DM_SEC_KEYPRESS_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_PRIV_RESOLVED_ADDR_IND */
|
||||
sizeof(dmPrivGenAddrIndEvt_t), /* DM_PRIV_GENERATE_RPA_IND */
|
||||
sizeof(hciReadRssiCmdCmplEvt_t), /* DM_CONN_READ_RSSI_IND */
|
||||
sizeof(hciLeAddDevToResListCmdCmplEvt_t), /* DM_PRIV_ADD_DEV_TO_RES_LIST_IND */
|
||||
sizeof(hciLeRemDevFromResListCmdCmplEvt_t), /* DM_PRIV_REM_DEV_FROM_RES_LIST_IND */
|
||||
sizeof(hciLeClearResListCmdCmplEvt_t), /* DM_PRIV_CLEAR_RES_LIST_IND */
|
||||
sizeof(hciLeReadPeerResAddrCmdCmplEvt_t), /* DM_PRIV_READ_PEER_RES_ADDR_IND */
|
||||
sizeof(hciLeReadLocalResAddrCmdCmplEvt_t), /* DM_PRIV_READ_LOCAL_RES_ADDR_IND */
|
||||
sizeof(hciLeSetAddrResEnableCmdCmplEvt_t), /* DM_PRIV_SET_ADDR_RES_ENABLE_IND */
|
||||
sizeof(hciLeRemConnParamReqEvt_t), /* DM_REM_CONN_PARAM_REQ_IND */
|
||||
sizeof(hciLeDataLenChangeEvt_t), /* DM_CONN_DATA_LEN_CHANGE_IND */
|
||||
sizeof(hciWriteAuthPayloadToCmdCmplEvt_t), /* DM_CONN_WRITE_AUTH_TO_IND */
|
||||
sizeof(hciAuthPayloadToExpiredEvt_t), /* DM_CONN_AUTH_TO_EXPIRED_IND */
|
||||
sizeof(hciLeReadPhyCmdCmplEvt_t), /* DM_PHY_READ_IND */
|
||||
sizeof(hciLeSetDefPhyCmdCmplEvt_t), /* DM_PHY_SET_DEF_IND */
|
||||
sizeof(hciLePhyUpdateEvt_t), /* DM_PHY_UPDATE_IND */
|
||||
sizeof(dmAdvSetStartEvt_t), /* DM_ADV_SET_START_IND */
|
||||
sizeof(hciLeAdvSetTermEvt_t), /* DM_ADV_SET_STOP_IND */
|
||||
sizeof(hciLeScanReqRcvdEvt_t), /* DM_SCAN_REQ_RCVD_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_EXT_SCAN_START_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_EXT_SCAN_STOP_IND */
|
||||
sizeof(hciLeExtAdvReportEvt_t), /* DM_EXT_SCAN_REPORT_IND */
|
||||
sizeof(dmPerAdvSetStartEvt_t), /* DM_PER_ADV_SET_START_IND */
|
||||
sizeof(dmPerAdvSetStopEvt_t), /* DM_PER_ADV_SET_STOP_IND */
|
||||
sizeof(hciLePerAdvSyncEstEvt_t), /* DM_PER_ADV_SYNC_EST_IND */
|
||||
sizeof(hciLePerAdvSyncEstEvt_t), /* DM_PER_ADV_SYNC_EST_FAIL_IND */
|
||||
sizeof(hciLePerAdvSyncLostEvt_t), /* DM_PER_ADV_SYNC_LOST_IND */
|
||||
sizeof(HciLePerAdvSyncTrsfRcvdEvt_t), /* DM_PER_ADV_SYNC_TRSF_EST_IND */
|
||||
sizeof(HciLePerAdvSyncTrsfRcvdEvt_t), /* DM_PER_ADV_SYNC_TRSF_EST_FAIL_IND */
|
||||
sizeof(hciLePerAdvSyncTrsfCmdCmplEvt_t), /* DM_PER_ADV_SYNC_TRSF_IND */
|
||||
sizeof(hciLePerAdvSetInfoTrsfCmdCmplEvt_t), /* DM_PER_ADV_SET_INFO_TRSF_IND */
|
||||
sizeof(hciLePerAdvReportEvt_t), /* DM_PER_ADV_REPORT_IND */
|
||||
sizeof(hciLeReadRemoteFeatCmplEvt_t), /* DM_REMOTE_FEATURES_IND */
|
||||
sizeof(hciReadRemoteVerInfoCmplEvt_t), /* DM_READ_REMOTE_VER_INFO_IND */
|
||||
sizeof(hciLeConnIQReportEvt_t), /* DM_CONN_IQ_REPORT_IND */
|
||||
sizeof(hciLeCteReqFailedEvt_t), /* DM_CTE_REQ_FAIL_IND */
|
||||
sizeof(hciLeSetConnCteRxParamsCmdCmplEvt_t), /* DM_CONN_CTE_RX_SAMPLE_START_IND */
|
||||
sizeof(hciLeSetConnCteRxParamsCmdCmplEvt_t), /* DM_CONN_CTE_RX_SAMPLE_START_IND */
|
||||
sizeof(hciLeSetConnCteTxParamsCmdCmplEvt_t), /* DM_CONN_CTE_TX_CFG_IND */
|
||||
sizeof(hciLeConnCteReqEnableCmdCmplEvt_t), /* DM_CONN_CTE_REQ_START_IND */
|
||||
sizeof(hciLeConnCteReqEnableCmdCmplEvt_t), /* DM_CONN_CTE_REQ_STOP_IND */
|
||||
sizeof(hciLeConnCteRspEnableCmdCmplEvt_t), /* DM_CONN_CTE_RSP_START_IND */
|
||||
sizeof(hciLeConnCteRspEnableCmdCmplEvt_t), /* DM_CONN_CTE_RSP_STOP_IND */
|
||||
sizeof(hciLeReadAntennaInfoCmdCmplEvt_t), /* DM_READ_ANTENNA_INFO_IND */
|
||||
sizeof(dmL2cCmdRejEvt_t), /* DM_L2C_CMD_REJ_IND */
|
||||
sizeof(wsfMsgHdr_t), /* DM_ERROR_IND */
|
||||
sizeof(hciHwErrorEvt_t), /* DM_HW_ERROR_IND */
|
||||
sizeof(hciVendorSpecEvt_t) /* DM_VENDOR_SPEC_IND */
|
||||
};
|
||||
|
||||
/* Default component function inteface */
|
||||
static const dmFcnIf_t dmFcnDefault =
|
||||
{
|
||||
dmEmptyReset,
|
||||
(dmHciHandler_t) dmEmptyHandler,
|
||||
(dmMsgHandler_t) dmEmptyHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface table indexed DM component ID */
|
||||
dmFcnIf_t *dmFcnIfTbl[DM_NUM_IDS] =
|
||||
{
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_ADV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_DEV_PRIV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SCAN */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_CONN */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_CONN_2 */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SEC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PRIV */
|
||||
(dmFcnIf_t *) &dmDevFcnIf, /* DM_ID_DEV */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_LESC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PHY */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_ADV_PER */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_SYNC */
|
||||
(dmFcnIf_t *) &dmFcnDefault, /* DM_ID_PAST */
|
||||
(dmFcnIf_t *) &dmFcnDefault /* DM_ID_CONN_CTE */
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmCb_t dmCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI event callback function.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmHciEvtCback(hciEvt_t *pEvent)
|
||||
{
|
||||
WSF_ASSERT(pEvent->hdr.event <= HCI_LE_READ_ANTENNA_INFO_CMD_CMPL_CBACK_EVT);
|
||||
|
||||
/* if DM not resetting or resetting but incoming event is HCI reset sequence complete event */
|
||||
if (!dmCb.resetting || (pEvent->hdr.event == HCI_RESET_SEQ_CMPL_CBACK_EVT))
|
||||
{
|
||||
/* route event to DM component handling function */
|
||||
(*(dmFcnIfTbl[dmHciToIdTbl[pEvent->hdr.event]]->hciHandler))(pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM empty reset handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmEmptyReset(void)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM empty event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmEmptyHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pass an HCI event to the DM connection management module.
|
||||
*
|
||||
* \param pEvent HCI event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmDevPassHciEvtToConn(hciEvt_t *pEvent)
|
||||
{
|
||||
/* pass event to DM connection management module */
|
||||
(*(dmFcnIfTbl[DM_ID_CONN]->hciHandler))(pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a callback with DM for scan and advertising events.
|
||||
*
|
||||
* \param cback Client callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmRegister(dmCback_t cback)
|
||||
{
|
||||
dmCb.cback = cback;
|
||||
|
||||
/* if LESC is enabled */
|
||||
if (dmFcnIfTbl[DM_ID_LESC] != &dmFcnDefault)
|
||||
{
|
||||
/* if largest LESC key length is larger than maximum RX PDU length */
|
||||
if (SMP_PUB_KEY_MSG_LEN > (HciGetMaxRxAclLen() - L2C_HDR_LEN))
|
||||
{
|
||||
dmEvt_t evt;
|
||||
|
||||
evt.hdr.param = 0;
|
||||
evt.hdr.event = DM_ERROR_IND;
|
||||
evt.hdr.status = DM_ERR_SMP_RX_PDU_LEN_EXCEEDED;
|
||||
|
||||
(*dmCb.cback)(&evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find an advertising data element in the given advertising or scan response data.
|
||||
*
|
||||
* \param adType Advertising data element type to find.
|
||||
* \param dataLen Data length.
|
||||
* \param pData Pointer to advertising or scan response data.
|
||||
*
|
||||
* \return Pointer to advertising data element byte array or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *DmFindAdType(uint8_t adType, uint16_t dataLen, uint8_t *pData)
|
||||
{
|
||||
/* while not at end of data and
|
||||
* data element length is not zero and
|
||||
* data element length is not erroneously more than the data length
|
||||
*/
|
||||
while ((dataLen != 0) && (pData[DM_AD_LEN_IDX] != 0) && (pData[DM_AD_LEN_IDX] < dataLen))
|
||||
{
|
||||
/* if found */
|
||||
if (pData[DM_AD_TYPE_IDX] == adType)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
/* else go to next element */
|
||||
dataLen = dataLen - pData[DM_AD_LEN_IDX] - 1;
|
||||
pData = pData + pData[DM_AD_LEN_IDX] + 1;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID for DM.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
/* store handler ID */
|
||||
dmCb.handlerId = handlerId;
|
||||
|
||||
dmCb.llPrivEnabled = FALSE;
|
||||
dmCb.resetting = FALSE;
|
||||
|
||||
/* register with the HCI event interface */
|
||||
HciEvtRegister(dmHciEvtCback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for DM.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
WSF_ASSERT(DM_ID_FROM_MSG(pMsg->event) < DM_NUM_IDS);
|
||||
|
||||
/* if DM not resetting */
|
||||
if (!dmCb.resetting)
|
||||
{
|
||||
/* route message to DM component handling function */
|
||||
(*(dmFcnIfTbl[DM_ID_FROM_MSG(pMsg->event)]->msgHandler))(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether LL Privacy is enabled.
|
||||
*
|
||||
* \return TRUE if LL Privacy is enabled. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmLlPrivEnabled(void)
|
||||
{
|
||||
return dmCb.llPrivEnabled;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Map an address type to a type used by LL.
|
||||
*
|
||||
* \param addrType Address type used by Host.
|
||||
*
|
||||
* \return Address type used by LL.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmLlAddrType(uint8_t addrType)
|
||||
{
|
||||
uint8_t llAddrType = addrType;
|
||||
|
||||
/* if LL Privacy is enabled */
|
||||
if (dmCb.llPrivEnabled)
|
||||
{
|
||||
if (addrType == DM_ADDR_PUBLIC)
|
||||
{
|
||||
llAddrType = DM_ADDR_PUBLIC_IDENTITY;
|
||||
}
|
||||
else if (addrType == DM_ADDR_RANDOM)
|
||||
{
|
||||
llAddrType = DM_ADDR_RANDOM_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
return llAddrType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Map an address type to a type used by Host.
|
||||
*
|
||||
* \param addrType Address type used by LL.
|
||||
*
|
||||
* \return Address type used by Host.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmHostAddrType(uint8_t addrType)
|
||||
{
|
||||
uint8_t hostAddrType = addrType;
|
||||
|
||||
/* if LL Privacy is enabled */
|
||||
if (dmCb.llPrivEnabled)
|
||||
{
|
||||
if (addrType == DM_ADDR_PUBLIC_IDENTITY)
|
||||
{
|
||||
hostAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
else if (addrType == DM_ADDR_RANDOM_IDENTITY)
|
||||
{
|
||||
hostAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
return hostAddrType;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return size of a DM callback event.
|
||||
*
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return Size of DM callback event.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t DmSizeOfEvt(dmEvt_t *pDmEvt)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
/* if a valid DM event ID */
|
||||
if ((pDmEvt->hdr.event >= DM_CBACK_START) && (pDmEvt->hdr.event <= DM_CBACK_END))
|
||||
{
|
||||
len = dmEvtCbackLen[pDmEvt->hdr.event - DM_CBACK_START];
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sizeof(wsfMsgHdr_t);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given scanner PHY.
|
||||
*
|
||||
* \param numPhys Number of scanner PHYs.
|
||||
* \param scanPhy Scanner PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t dmScanPhyToIdx(uint8_t numPhys, uint8_t scanPhy)
|
||||
{
|
||||
/* if number of supported PHYs is 1 */
|
||||
if (numPhys == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if number of supported PHYs is 2 */
|
||||
if (numPhys == 2)
|
||||
{
|
||||
return (scanPhy == HCI_SCAN_PHY_LE_1M_BIT) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* all three PHYs are supported */
|
||||
return (scanPhy == HCI_SCAN_PHY_LE_1M_BIT) ? 0 : (scanPhy == HCI_SCAN_PHY_LE_2M_BIT) ? 1 : 2;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given scanner PHY.
|
||||
*
|
||||
* \param scanPhy Scanner PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmScanPhyToIdx(uint8_t scanPhy)
|
||||
{
|
||||
return dmScanPhyToIdx(DM_NUM_PHYS, scanPhy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given initiator PHY.
|
||||
*
|
||||
* \param numPhys Number of initiator PHYs.
|
||||
* \param initPhy Initiator PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t dmInitPhyToIdx(uint8_t numPhys, uint8_t initPhy)
|
||||
{
|
||||
/* if number of supported PHYs is 1 */
|
||||
if (numPhys == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if number of supported PHYs is 2 */
|
||||
if (numPhys == 2)
|
||||
{
|
||||
return (initPhy == HCI_INIT_PHY_LE_1M_BIT) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* all three PHYs are supported */
|
||||
return (initPhy == HCI_INIT_PHY_LE_1M_BIT) ? 0 : (initPhy == HCI_INIT_PHY_LE_2M_BIT) ? 1 : 2;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the PHY index for the given initiator PHY.
|
||||
*
|
||||
* \param initPhy Initiator PHY.
|
||||
*
|
||||
* \return PHY index.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DmInitPhyToIdx(uint8_t initPhy)
|
||||
{
|
||||
return dmInitPhyToIdx(DM_NUM_PHYS, initPhy);
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM main module.
|
||||
*
|
||||
* Copyright (c) 2009-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_MAIN_H
|
||||
#define DM_MAIN_H
|
||||
|
||||
#include "util/bda.h"
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM component IDs */
|
||||
#define DM_ID_ADV 0
|
||||
#define DM_ID_DEV_PRIV 1
|
||||
#define DM_ID_SCAN 2
|
||||
#define DM_ID_CONN 3
|
||||
#define DM_ID_CONN_2 4
|
||||
#define DM_ID_SEC 5
|
||||
#define DM_ID_PRIV 6
|
||||
#define DM_ID_DEV 7
|
||||
#define DM_ID_LESC 8
|
||||
#define DM_ID_PHY 9
|
||||
#define DM_ID_ADV_PER 10
|
||||
#define DM_ID_SYNC 11
|
||||
#define DM_ID_PAST 12
|
||||
#define DM_ID_CONN_CTE 13
|
||||
#define DM_NUM_IDS 14
|
||||
|
||||
/* Start of component message enumeration */
|
||||
#define DM_MSG_START(id) ((id) << 4)
|
||||
|
||||
/* Get the component ID from a message ID */
|
||||
#define DM_ID_FROM_MSG(msg) ((msg) >> 4)
|
||||
|
||||
/* Mask off the ID from the message ID */
|
||||
#define DM_MSG_MASK(msg) ((msg) & 0x0F)
|
||||
|
||||
/* Length of hash part of private resolvable address */
|
||||
#define DM_PRIV_HASH_LEN 3
|
||||
|
||||
/* Length of random part of private resolvable address */
|
||||
#define DM_PRIV_PRAND_LEN 3
|
||||
|
||||
/* Length of plaintext used for private resolvable address calculation */
|
||||
#define DM_PRIV_PLAINTEXT_LEN 16
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM reset function type */
|
||||
typedef void (*dmReset_t)(void);
|
||||
|
||||
/* DM message handling function types */
|
||||
typedef void (*dmMsgHandler_t)(wsfMsgHdr_t *pMsg);
|
||||
typedef void (*dmHciHandler_t)(hciEvt_t *pEvent);
|
||||
|
||||
/* DM component reset and handler function interface */
|
||||
typedef struct
|
||||
{
|
||||
dmReset_t reset;
|
||||
dmHciHandler_t hciHandler;
|
||||
dmMsgHandler_t msgHandler;
|
||||
} dmFcnIf_t;
|
||||
|
||||
/* Main control block of the DM subsystem */
|
||||
typedef struct
|
||||
{
|
||||
bdAddr_t localAddr;
|
||||
dmCback_t cback;
|
||||
wsfHandlerId_t handlerId;
|
||||
uint8_t connAddrType;
|
||||
uint8_t advAddrType;
|
||||
uint8_t scanAddrType;
|
||||
bool_t resetting;
|
||||
|
||||
/* Filter policies for Advertising, Scanning, Initiator and Synchronization */
|
||||
uint8_t advFiltPolicy[DM_NUM_ADV_SETS];
|
||||
uint8_t scanFiltPolicy;
|
||||
uint8_t initFiltPolicy;
|
||||
|
||||
/* Options (filter policies and periodic advertising report enablement) for Synchronization */
|
||||
uint8_t syncOptions;
|
||||
|
||||
/* LL Privacy */
|
||||
bool_t llPrivEnabled;
|
||||
} dmCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface table indexed DM component ID */
|
||||
extern dmFcnIf_t *dmFcnIfTbl[DM_NUM_IDS];
|
||||
|
||||
/* Control block */
|
||||
extern dmCb_t dmCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void dmEmptyReset(void);
|
||||
void dmEmptyHandler(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/* utility functions */
|
||||
uint8_t DmScanPhyToIdx(uint8_t scanPhy);
|
||||
uint8_t DmInitPhyToIdx(uint8_t initPhy);
|
||||
void dmDevPassHciEvtToConn(hciEvt_t *pEvent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_MAIN_H */
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager periodic advertising sync transfer (PAST) module.
|
||||
*
|
||||
* Copyright (c) 2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_adv.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_scan.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DM past event handler messages */
|
||||
enum
|
||||
{
|
||||
/* messages from API */
|
||||
DM_PAST_MSG_API_RCV_ENABLE = DM_MSG_START(DM_ID_PAST), /*!< Enable receiving report */
|
||||
DM_PAST_MSG_API_SYNC_TRSF, /*!< Transfer sync */
|
||||
DM_PAST_MSG_API_SET_INFO_TRSF, /*!< Transfer set info */
|
||||
DM_PAST_MSG_API_CFG, /*!< Configure PAST parameters */
|
||||
DM_PAST_MSG_API_DEFAULT_CFG /*!< Configure PAST default parameters */
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmPastAct_t dmPastAct[] =
|
||||
{
|
||||
dmPastActRptRcvEnable,
|
||||
dmPastActSyncTsfr,
|
||||
dmPastActSetInfoTrsf,
|
||||
dmPastActConfig,
|
||||
dmPastActDefaultConfig
|
||||
};
|
||||
|
||||
/*! DM PAST component function interface */
|
||||
static const dmFcnIf_t dmPastFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmPastHciHandler,
|
||||
dmPastMsgHandler
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM Periodic Advertising Sync Transfer (PAST) module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastInit(void)
|
||||
{
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_PAST] = (dmFcnIf_t *) &dmPastFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST HCI event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb = dmConnCcbByHandle(pEvent->hdr.param);
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
/* set conn id */
|
||||
pEvent->hdr.param = pCcb->connId;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_PER_ADV_SYNC_TRSF_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_PER_ADV_SYNC_TRSF_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_PER_ADV_SET_INFO_TRSF_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
pEvent->hdr.event = DM_PER_ADV_SET_INFO_TRSF_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PAST event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmPastAct[DM_MSG_MASK(pMsg->event)])((dmPastMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable receiving report action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActRptRcvEnable(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* look up scb from sync id */
|
||||
if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
HciLeSetPerAdvRcvEnableCmd(pScb->handle, (pMsg->hdr.status ? TRUE : FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transfer sync action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActSyncTsfr(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmSyncCb_t *pScb;
|
||||
|
||||
/* look up scb from sync id */
|
||||
if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL)
|
||||
{
|
||||
HciLePerAdvSyncTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, pScb->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transfer set info action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActSetInfoTrsf(dmPastMsg_t *pMsg)
|
||||
{
|
||||
uint8_t advHandle = (uint8_t) pMsg->hdr.param;
|
||||
|
||||
/* if periodic advertising is currently in progress for the advertising set */
|
||||
if (dmPerAdvState(advHandle) == DM_ADV_PER_STATE_ADVERTISING)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL)
|
||||
{
|
||||
HciLePerAdvSetInfoTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, advHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure PAST action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActConfig(dmPastMsg_t *pMsg)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
/* look up ccb from conn id */
|
||||
if ((pCcb = dmConnCcbById((dmConnId_t) pMsg->hdr.param)) != NULL)
|
||||
{
|
||||
HciLeSetPerAdvSyncTrsfParamsCmd(pCcb->handle, pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip,
|
||||
pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure default PAST action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPastActDefaultConfig(dmPastMsg_t *pMsg)
|
||||
{
|
||||
HciLeSetDefaultPerAdvSyncTrsfParamsCmd(pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip,
|
||||
pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable or disable reports for the periodic advertising identified by the sync id.
|
||||
*
|
||||
* \param syncId Sync identifier.
|
||||
* \param enable TRUE to enable reporting, FALSE to disable reporting.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastRptRcvEnable(dmSyncId_t syncId, bool_t enable)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->param = syncId;
|
||||
pMsg->event = DM_PAST_MSG_API_RCV_ENABLE;
|
||||
pMsg->status = enable;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send synchronization information about the periodic advertising identified by the
|
||||
* sync id to a connected device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param serviceData Value provided by the Host.
|
||||
* \param syncId Sync identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastSyncTrsf(dmConnId_t connId, uint16_t serviceData, dmSyncId_t syncId)
|
||||
{
|
||||
dmPastApiTrsf_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = syncId;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_SYNC_TRSF;
|
||||
pMsg->serviceData = serviceData;
|
||||
pMsg->connId = connId;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send synchronization information about the periodic advertising in an advertising
|
||||
* set to a connected device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param serviceData Value provided by the Host.
|
||||
* \param advHandle Advertising handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastSetInfoTrsf(dmConnId_t connId, uint16_t serviceData, uint8_t advHandle)
|
||||
{
|
||||
dmPastApiTrsf_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = advHandle;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_SET_INFO_TRSF;
|
||||
pMsg->serviceData = serviceData;
|
||||
pMsg->connId = connId;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Specify how the Controller should process periodic advertising synchronization
|
||||
* information received from the device identified by the connection handle.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param mode Action to be taken when periodic advertising info is received.
|
||||
* \param skip Number of consecutive periodic advertising packets that the receiver
|
||||
* may skip after successfully receiving a periodic advertising packet.
|
||||
* \param syncTimeout Maximum permitted time between successful receives. If this time is
|
||||
* exceeded, synchronization is lost.
|
||||
* \param cteType Whether to only synchronize to periodic advertising with certain
|
||||
* types of Constant Tone Extension.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastConfig(dmConnId_t connId, uint8_t mode, uint16_t skip, uint16_t syncTimeout,
|
||||
uint8_t cteType)
|
||||
{
|
||||
dmPastApiCfg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.param = connId;
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_CFG;
|
||||
pMsg->mode = mode;
|
||||
pMsg->skip = skip;
|
||||
pMsg->syncTimeout = syncTimeout;
|
||||
pMsg->cteType = cteType;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Specify the initial value for the mode, skip, timeout, and Constant Tone Extension type
|
||||
* to be used for all subsequent connections over the LE transport.
|
||||
*
|
||||
* \param mode Action to be taken when periodic advertising info is received.
|
||||
* \param skip Number of consecutive periodic advertising packets that the receiver
|
||||
* may skip after successfully receiving a periodic advertising packet.
|
||||
* \param syncTimeout Maximum permitted time between successful receives. If this time is
|
||||
* exceeded, synchronization is lost.
|
||||
* \param cteType Whether to only synchronize to periodic advertising with certain
|
||||
* types of Constant Tone Extension.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPastDefaultConfig(uint8_t mode, uint16_t skip, uint16_t syncTimeout, uint8_t cteType)
|
||||
{
|
||||
dmPastApiCfg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PAST_MSG_API_DEFAULT_CFG;
|
||||
pMsg->mode = mode;
|
||||
pMsg->skip = skip;
|
||||
pMsg->syncTimeout = syncTimeout;
|
||||
pMsg->cteType = cteType;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM PHY module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_phy.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmPhyFcnIf =
|
||||
{
|
||||
dmEmptyReset,
|
||||
dmPhyHciHandler,
|
||||
(dmMsgHandler_t)dmEmptyHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
static void dmPhyActDefPhySet(hciEvt_t *pEvent);
|
||||
static void dmPhyActPhyRead(dmConnCcb_t *pCcb, hciEvt_t *pEvent);
|
||||
static void dmPhyActPhyUpdate(dmConnCcb_t *pCcb, hciEvt_t *pEvent);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM PHY HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPhyHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_SET_DEF_PHY_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
dmPhyActDefPhySet(pEvent);
|
||||
}
|
||||
/* look up ccb from conn handle */
|
||||
else if ((pCcb = dmConnCcbByHandle(pEvent->hdr.param)) != NULL)
|
||||
{
|
||||
/* handle incoming event */
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_READ_PHY_CMD_CMPL_CBACK_EVT:
|
||||
dmPhyActPhyRead(pCcb, pEvent);
|
||||
break;
|
||||
|
||||
case HCI_LE_PHY_UPDATE_CMPL_CBACK_EVT:
|
||||
dmPhyActPhyUpdate(pCcb, pEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never get here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a read PHY event from HCI.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActPhyRead(dmConnCcb_t *pCcb, hciEvt_t *pEvent)
|
||||
{
|
||||
hciLeReadPhyCmdCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_READ_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->leReadPhyCmdCmpl.status;
|
||||
evt.handle = pCcb->handle;
|
||||
evt.txPhy = pEvent->leReadPhyCmdCmpl.txPhy;
|
||||
evt.rxPhy = pEvent->leReadPhyCmdCmpl.rxPhy;
|
||||
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a set default PHY event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActDefPhySet(hciEvt_t *pEvent)
|
||||
{
|
||||
hciLeSetDefPhyCmdCmplEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_SET_DEF_IND;
|
||||
evt.hdr.param = 0;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->leSetDefPhyCmdCmpl.status;
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a PHY update event from HCI.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPhyActPhyUpdate(dmConnCcb_t *pCcb, hciEvt_t *pEvent)
|
||||
{
|
||||
hciLePhyUpdateEvt_t evt;
|
||||
|
||||
/* call callback */
|
||||
evt.hdr.event = DM_PHY_UPDATE_IND;
|
||||
evt.hdr.param = pCcb->connId;
|
||||
evt.status = evt.hdr.status = (uint8_t)pEvent->lePhyUpdate.status;
|
||||
evt.handle = pCcb->handle;
|
||||
evt.txPhy = pEvent->lePhyUpdate.txPhy;
|
||||
evt.rxPhy = pEvent->lePhyUpdate.rxPhy;
|
||||
|
||||
(*dmConnCb.connCback[DM_CLIENT_ID_APP])((dmEvt_t *)&evt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the current transmitter PHY and receiver PHY for a given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmReadPhy(dmConnId_t connId)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
WsfTaskLock();
|
||||
/* look up ccb from conn id */
|
||||
pCcb = dmConnCcbById(connId);
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
HciLeReadPhyCmd(pCcb->handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the preferred values for the transmitter PHY and receiver PHY for all subsequent
|
||||
* connections.
|
||||
*
|
||||
* \param allPhys All PHYs preferences.
|
||||
* \param txPhys Preferred transmitter PHYs.
|
||||
* \param rxPhys Preferred receiver PHYs.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSetDefaultPhy(uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys)
|
||||
{
|
||||
HciLeSetDefaultPhyCmd(allPhys, txPhys, rxPhys);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the PHY preferences for a given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param allPhys All PHYs preferences.
|
||||
* \param txPhys Preferred transmitter PHYs.
|
||||
* \param rxPhys Preferred receiver PHYs.
|
||||
* \param phyOptions PHY options.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmSetPhy(dmConnId_t connId, uint8_t allPhys, uint8_t txPhys, uint8_t rxPhys, uint16_t phyOptions)
|
||||
{
|
||||
dmConnCcb_t *pCcb;
|
||||
|
||||
WsfTaskLock();
|
||||
/* look up ccb from conn id */
|
||||
pCcb = dmConnCcbById(connId);
|
||||
WsfTaskUnlock();
|
||||
|
||||
/* if ccb found */
|
||||
if (pCcb != NULL)
|
||||
{
|
||||
HciLeSetPhyCmd(pCcb->handle, allPhys, txPhys, rxPhys, phyOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM PHY.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPhyInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_PHY] = (dmFcnIf_t *) &dmPhyFcnIf;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM PHY module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_PHY_H
|
||||
#define DM_PHY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data types
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* component interface */
|
||||
void dmPhyHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_PHY_H */
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager privacy module.
|
||||
*
|
||||
* Copyright (c) 2011-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "util/calc128.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_priv.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* progress (dmPrivCb.inProgress) bitmask bits */
|
||||
#define DM_PRIV_INPROGRESS_RES_ADDR (1 << 0) /* resolve address in progress */
|
||||
#define DM_PRIV_INPROGRESS_GEN_ADDR (1 << 1) /* generate address in progress */
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* action function table */
|
||||
static const dmPrivAct_t dmPrivAct[] =
|
||||
{
|
||||
dmPrivActResolveAddr,
|
||||
dmPrivActResAddrAesCmpl,
|
||||
dmPrivActAddDevToResList,
|
||||
dmPrivActRemDevFromResList,
|
||||
dmPrivActClearResList,
|
||||
dmPrivActSetAddrResEnable,
|
||||
dmPrivActSetPrivacyMode,
|
||||
dmPrivActGenAddr,
|
||||
dmPrivActGenAddrAesCmpl
|
||||
};
|
||||
|
||||
/* Component function interface */
|
||||
static const dmFcnIf_t dmPrivFcnIf =
|
||||
{
|
||||
dmPrivReset,
|
||||
dmPrivHciHandler,
|
||||
dmPrivMsgHandler
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
dmPrivCb_t dmPrivCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void dmPrivSetAddrResEnable(bool_t enable);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start address resolution procedure
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActResolveAddr(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
uint8_t buf[DM_PRIV_PLAINTEXT_LEN];
|
||||
|
||||
/* verify no resolution procedure currently in progress */
|
||||
if ((dmPrivCb.inProgress & DM_PRIV_INPROGRESS_RES_ADDR) == 0)
|
||||
{
|
||||
/* store hash */
|
||||
memcpy(dmPrivCb.hash, pMsg->apiResolveAddr.addr, DM_PRIV_HASH_LEN);
|
||||
|
||||
/* copy random part of address with padding for address resolution calculation */
|
||||
memcpy(buf, &pMsg->apiResolveAddr.addr[3], DM_PRIV_PRAND_LEN);
|
||||
memset(buf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* set in progress */
|
||||
dmPrivCb.inProgress |= DM_PRIV_INPROGRESS_RES_ADDR;
|
||||
|
||||
/* run calculation */
|
||||
SecAes(pMsg->apiResolveAddr.irk, buf, dmCb.handlerId,
|
||||
pMsg->hdr.param, DM_PRIV_MSG_RESOLVE_AES_CMPL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call callback with error (note hdr.param is already set) */
|
||||
pMsg->hdr.status = HCI_ERR_MEMORY_EXCEEDED;
|
||||
pMsg->hdr.event = DM_PRIV_RESOLVED_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Finish address resolution procedure upon completion of AES calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActResAddrAesCmpl(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
/* compare calculated value with hash */
|
||||
if (memcmp(dmPrivCb.hash, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN) == 0)
|
||||
{
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = HCI_ERR_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
/* clear in progress */
|
||||
dmPrivCb.inProgress &= ~DM_PRIV_INPROGRESS_RES_ADDR;
|
||||
|
||||
/* call client callback (note hdr.param is already set) */
|
||||
pMsg->hdr.event = DM_PRIV_RESOLVED_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add device to resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActAddDevToResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiAddDevToResList_t *pDev = &pMsg->apiAddDevToResList;
|
||||
|
||||
/* save whether asked to enable address resolution */
|
||||
dmPrivCb.enableLlPriv = pDev->enableLlPriv;
|
||||
|
||||
/* save client-defined parameter for callback event */
|
||||
dmPrivCb.addDevToResListParam = pMsg->hdr.param;
|
||||
|
||||
/* add device to resolving list */
|
||||
HciLeAddDeviceToResolvingListCmd(pDev->addrType, pDev->peerAddr, pDev->peerIrk, pDev->localIrk);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove device from resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActRemDevFromResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiRemDevFromResList_t *pDev = &pMsg->apiRemDevFromResList;
|
||||
|
||||
/* save client-defined parameter for callback event */
|
||||
dmPrivCb.remDevFromResListParam = pMsg->hdr.param;
|
||||
|
||||
/* remove device from resolving list */
|
||||
HciLeRemoveDeviceFromResolvingList(pDev->addrType, pDev->peerAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear resolving list command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActClearResList(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
/* clear resolving list */
|
||||
HciLeClearResolvingList();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set address resolution enable command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActSetAddrResEnable(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiSetAddrResEnable_t *pAddrRes = &pMsg->apiSetAddrResEnable;
|
||||
|
||||
/* enable or disable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(pAddrRes->enable);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set privacy mode command.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActSetPrivacyMode(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivApiSetPrivacyMode_t *pPrivacyMode = &pMsg->apiSetPrivacyMode;
|
||||
|
||||
/* set privacy mode */
|
||||
HciLeSetPrivacyModeCmd(pPrivacyMode->addrType, pPrivacyMode->peerAddr, pPrivacyMode->mode);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start address generation procedure.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActGenAddr(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
if ((dmPrivCb.inProgress & DM_PRIV_INPROGRESS_GEN_ADDR) == 0)
|
||||
{
|
||||
/* get random number */
|
||||
SecRand(dmPrivCb.genAddrBuf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* set address type in random number */
|
||||
dmPrivCb.genAddrBuf[2] = (dmPrivCb.genAddrBuf[2] & 0x3F) | DM_RAND_ADDR_RESOLV;
|
||||
|
||||
/* pad buffer */
|
||||
memset(dmPrivCb.genAddrBuf + DM_PRIV_PRAND_LEN, 0, (DM_PRIV_PLAINTEXT_LEN - DM_PRIV_PRAND_LEN));
|
||||
|
||||
/* set in progress */
|
||||
dmPrivCb.inProgress |= DM_PRIV_INPROGRESS_GEN_ADDR;
|
||||
|
||||
/* run calculation */
|
||||
SecAes(pMsg->apiGenerateAddr.irk, dmPrivCb.genAddrBuf, dmCb.handlerId,
|
||||
pMsg->hdr.param, DM_PRIV_MSG_GEN_ADDR_AES_CMPL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* call callback with error (note hdr.param is already set) */
|
||||
pMsg->hdr.status = HCI_ERR_MEMORY_EXCEEDED;
|
||||
pMsg->hdr.event = DM_PRIV_GENERATE_ADDR_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Finish generate RPA procedure upon completion of AES calculation.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivActGenAddrAesCmpl(dmPrivMsg_t *pMsg)
|
||||
{
|
||||
dmPrivGenAddrIndEvt_t *pAddrEvt = (dmPrivGenAddrIndEvt_t*) pMsg;
|
||||
|
||||
/* copy the hash and address to buffer */
|
||||
memcpy(pAddrEvt->addr, pMsg->aes.pCiphertext, DM_PRIV_HASH_LEN);
|
||||
memcpy(pAddrEvt->addr + DM_PRIV_HASH_LEN, dmPrivCb.genAddrBuf, DM_PRIV_PRAND_LEN);
|
||||
|
||||
/* clear in progress */
|
||||
dmPrivCb.inProgress &= ~DM_PRIV_INPROGRESS_GEN_ADDR;
|
||||
|
||||
/* call client callback */
|
||||
pAddrEvt->hdr.event = DM_PRIV_GENERATE_ADDR_IND;
|
||||
pMsg->hdr.status = HCI_SUCCESS;
|
||||
(*dmCb.cback)((dmEvt_t *) pAddrEvt);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM priv HCI callback event handler.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
/* handle incoming event */
|
||||
switch (pEvent->hdr.event)
|
||||
{
|
||||
case HCI_LE_ADD_DEV_TO_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_ADD_DEV_TO_RES_LIST_IND;
|
||||
pEvent->hdr.param = dmPrivCb.addDevToResListParam;
|
||||
|
||||
/* if LE add device to resolving list command succeeded and been asked to enable address
|
||||
* resolution in LL and it's not enabled yet
|
||||
*/
|
||||
if ((pEvent->hdr.status == HCI_SUCCESS) && dmPrivCb.enableLlPriv && !dmCb.llPrivEnabled)
|
||||
{
|
||||
/* enable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LE_REM_DEV_FROM_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_REM_DEV_FROM_RES_LIST_IND;
|
||||
pEvent->hdr.param = dmPrivCb.remDevFromResListParam;
|
||||
break;
|
||||
|
||||
case HCI_LE_CLEAR_RES_LIST_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_CLEAR_RES_LIST_IND;
|
||||
|
||||
/* if LE clear resolving list command succeeded and address resolution's enabled in LL */
|
||||
if ((pEvent->hdr.status == HCI_SUCCESS) && dmCb.llPrivEnabled)
|
||||
{
|
||||
/* disable address resolution in LL */
|
||||
dmPrivSetAddrResEnable(FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_LE_READ_PEER_RES_ADDR_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_READ_PEER_RES_ADDR_IND;
|
||||
break;
|
||||
|
||||
case HCI_LE_READ_LOCAL_RES_ADDR_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_READ_LOCAL_RES_ADDR_IND;
|
||||
break;
|
||||
|
||||
case HCI_LE_SET_ADDR_RES_ENABLE_CMD_CMPL_CBACK_EVT:
|
||||
pEvent->hdr.event = DM_PRIV_SET_ADDR_RES_ENABLE_IND;
|
||||
|
||||
/* if LE set address resoultion enable command succeeded */
|
||||
if (pEvent->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
/* update LL Privacy Enabled flag */
|
||||
dmCb.llPrivEnabled = dmPrivCb.addrResEnable;
|
||||
|
||||
/* pass LL Privacy enable/disable event to dev priv */
|
||||
dmDevPassEvtToDevPriv(dmCb.llPrivEnabled ? DM_DEV_PRIV_MSG_RPA_STOP : DM_DEV_PRIV_MSG_RPA_START,
|
||||
dmCb.llPrivEnabled ? TRUE : FALSE, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never get here */
|
||||
return;
|
||||
}
|
||||
|
||||
/* call callback (note hdr.status is already set) */
|
||||
(*dmCb.cback)((dmEvt_t *)pEvent);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set address resolution enable command.
|
||||
*
|
||||
* \param enable Set to TRUE to enable address resolution or FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmPrivSetAddrResEnable(bool_t enable)
|
||||
{
|
||||
/* save input parameter */
|
||||
dmPrivCb.addrResEnable = enable;
|
||||
|
||||
/* enable or disable address resolution in LL */
|
||||
HciLeSetAddrResolutionEnable(enable);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM priv event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmPrivAct[DM_MSG_MASK(pMsg->event)])((dmPrivMsg_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Reset the privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmPrivReset(void)
|
||||
{
|
||||
/* initialize control block */
|
||||
dmPrivCb.inProgress = 0;
|
||||
dmCb.llPrivEnabled = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM privacy module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivInit(void)
|
||||
{
|
||||
dmFcnIfTbl[DM_ID_PRIV] = (dmFcnIf_t *) &dmPrivFcnIf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Resolve a private resolvable address. When complete the client's callback function
|
||||
* is called with a DM_PRIV_RESOLVED_ADDR_IND event. The client must wait to receive
|
||||
* this event before executing this function again.
|
||||
*
|
||||
* \param pAddr Peer device address.
|
||||
* \param pIrk The peer's identity resolving key.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivResolveAddr(uint8_t *pAddr, uint8_t *pIrk, uint16_t param)
|
||||
{
|
||||
dmPrivApiResolveAddr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiResolveAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_RESOLVE_ADDR;
|
||||
pMsg->hdr.param = param;
|
||||
Calc128Cpy(pMsg->irk, pIrk);
|
||||
BdaCpy(pMsg->addr, pAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add device to resolving list. When complete the client's callback function
|
||||
* is called with a DM_PRIV_ADD_DEV_TO_RES_LIST_IND event. The client must wait
|
||||
* to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param pPeerIrk The peer's identity resolving key.
|
||||
* \param pLocalIrk The local identity resolving key.
|
||||
* \param enableLlPriv Set to TRUE to enable address resolution in LL.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*
|
||||
* \Note If the local or peer IRK associated with the peer Identity Address is all zeros then
|
||||
* the Controller will use or accept the local or peer Identity Address respectively.
|
||||
*
|
||||
* \Note Parameter 'enableLlPriv' should be set to TRUE when the last device is being added
|
||||
* to resolving list to enable address resolution in the Controller.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivAddDevToResList(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t *pPeerIrk,
|
||||
uint8_t *pLocalIrk, bool_t enableLlPriv, uint16_t param)
|
||||
{
|
||||
dmPrivApiAddDevToResList_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiAddDevToResList_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
Calc128Cpy(pMsg->peerIrk, pPeerIrk);
|
||||
Calc128Cpy(pMsg->localIrk, pLocalIrk);
|
||||
pMsg->enableLlPriv = enableLlPriv;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove device from resolving list. When complete the client's callback function
|
||||
* is called with a DM_PRIV_REM_DEV_FROM_RES_LIST_IND event. The client must wait to
|
||||
* receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param param client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivRemDevFromResList(uint8_t addrType, const uint8_t *pIdentityAddr, uint16_t param)
|
||||
{
|
||||
dmPrivApiRemDevFromResList_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiRemDevFromResList_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST;
|
||||
pMsg->hdr.param = param;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Clear resolving list. When complete the client's callback function is called with a
|
||||
* DM_PRIV_CLEAR_RES_LIST_IND event. The client must wait to receive this event before
|
||||
* executing this function again.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command cannot be used when address resolution is enabled in the Controller and:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*
|
||||
* \Note Address resolution in the Controller will be disabled when resolving list's cleared
|
||||
* successfully.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivClearResList(void)
|
||||
{
|
||||
dmPrivMsg_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivMsg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_CLEAR_RES_LIST;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI read peer resolvable address command. When complete the client's callback
|
||||
* function is called with a DM_PRIV_READ_PEER_RES_ADDR_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivReadPeerResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr)
|
||||
{
|
||||
HciLeReadPeerResolvableAddr(addrType, pIdentityAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read local resolvable address command. When complete the client's callback
|
||||
* function is called with a DM_PRIV_READ_LOCAL_RES_ADDR_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivReadLocalResolvableAddr(uint8_t addrType, const uint8_t *pIdentityAddr)
|
||||
{
|
||||
HciLeReadLocalResolvableAddr(addrType, pIdentityAddr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable or disable address resolution in LL. When complete the client's callback
|
||||
* function is called with a DM_PRIV_SET_ADDR_RES_ENABLE_IND event. The client must
|
||||
* wait to receive this event before executing this function again.
|
||||
*
|
||||
* \param enable Set to TRUE to enable address resolution or FALSE to disable it.
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command can be used at any time except when:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetAddrResEnable(bool_t enable)
|
||||
{
|
||||
dmPrivApiSetAddrResEnable_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivMsg_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE;
|
||||
pMsg->hdr.param = 0;
|
||||
pMsg->enable = enable;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set resolvable private address timeout command.
|
||||
*
|
||||
* \param rpaTimeout Timeout measured in seconds.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetResolvablePrivateAddrTimeout(uint16_t rpaTimeout)
|
||||
{
|
||||
HciLeSetResolvablePrivateAddrTimeout(rpaTimeout);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set privacy mode for a given entry in the resolving list.
|
||||
*
|
||||
* \param addrType Peer identity address type.
|
||||
* \param pIdentityAddr Peer identity address.
|
||||
* \param mode Privacy mode (by default, network privacy mode is used).
|
||||
*
|
||||
* \return None.
|
||||
*
|
||||
* \Note This command can be used at any time except when:
|
||||
* - Advertising (other than periodic advertising) is enabled,
|
||||
* - Scanning is enabled, or
|
||||
* - (Extended) Create connection or Create Sync command is outstanding.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivSetPrivacyMode(uint8_t addrType, const uint8_t *pIdentityAddr, uint8_t mode)
|
||||
{
|
||||
dmPrivApiSetPrivacyMode_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiSetPrivacyMode_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_SET_PRIVACY_MODE;
|
||||
pMsg->addrType = addrType;
|
||||
BdaCpy(pMsg->peerAddr, pIdentityAddr);
|
||||
pMsg->mode = mode;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a Resolvable Private Address (RPA).
|
||||
*
|
||||
* \param pIrk The identity resolving key.
|
||||
* \param param Client-defined parameter returned with callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmPrivGenerateAddr(uint8_t *pIrk, uint16_t param)
|
||||
{
|
||||
dmPrivApiGenAddr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmPrivApiGenAddr_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_PRIV_MSG_API_GEN_ADDR;
|
||||
pMsg->hdr.param = param;
|
||||
Calc128Cpy(pMsg->irk, pIrk);
|
||||
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM privacy module.
|
||||
*
|
||||
* Copyright (c) 2011-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_PRIV_H
|
||||
#define DM_PRIV_H
|
||||
|
||||
#include "util/bda.h"
|
||||
#include "wsf_os.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "sec_api.h"
|
||||
#include "dm_main.h"
|
||||
#include "smp_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM priv event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_PRIV_MSG_API_RESOLVE_ADDR = DM_MSG_START(DM_ID_PRIV),
|
||||
DM_PRIV_MSG_RESOLVE_AES_CMPL,
|
||||
DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST,
|
||||
DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST,
|
||||
DM_PRIV_MSG_API_CLEAR_RES_LIST,
|
||||
DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE,
|
||||
DM_PRIV_MSG_API_SET_PRIVACY_MODE,
|
||||
DM_PRIV_MSG_API_GEN_ADDR,
|
||||
DM_PRIV_MSG_GEN_ADDR_AES_CMPL
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_RESOLVE_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t irk[SMP_KEY_LEN];
|
||||
bdAddr_t addr;
|
||||
} dmPrivApiResolveAddr_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_GEN_ADDR */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t irk[SMP_KEY_LEN];
|
||||
} dmPrivApiGenAddr_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_ADD_DEV_TO_RES_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t peerIrk[SMP_KEY_LEN];
|
||||
uint8_t localIrk[SMP_KEY_LEN];
|
||||
bool_t enableLlPriv;
|
||||
} dmPrivApiAddDevToResList_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_REM_DEV_FROM_RES_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
} dmPrivApiRemDevFromResList_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_SET_ADDR_RES_ENABLE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
bool_t enable;
|
||||
} dmPrivApiSetAddrResEnable_t;
|
||||
|
||||
/* Data structure for DM_PRIV_MSG_API_SET_PRIVACY_MODE */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t addrType;
|
||||
bdAddr_t peerAddr;
|
||||
uint8_t mode;
|
||||
} dmPrivApiSetPrivacyMode_t;
|
||||
|
||||
/* Union of all priv messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmPrivApiResolveAddr_t apiResolveAddr;
|
||||
dmPrivApiAddDevToResList_t apiAddDevToResList;
|
||||
dmPrivApiRemDevFromResList_t apiRemDevFromResList;
|
||||
dmPrivApiSetAddrResEnable_t apiSetAddrResEnable;
|
||||
dmPrivApiSetPrivacyMode_t apiSetPrivacyMode;
|
||||
dmPrivApiGenAddr_t apiGenerateAddr;
|
||||
dmPrivGenAddrIndEvt_t genAddrInd;
|
||||
secAes_t aes;
|
||||
} dmPrivMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmPrivAct_t)(dmPrivMsg_t *pMsg);
|
||||
|
||||
/* Control block for privacy module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t hash[DM_PRIV_HASH_LEN]; /* Hash part of resolvable address */
|
||||
bool_t inProgress; /* Address resolution in progress */
|
||||
uint16_t addDevToResListParam; /* 'Add device to resolving list' callback param */
|
||||
uint16_t remDevFromResListParam; /* 'Remove device from resolving list' callback param */
|
||||
bool_t enableLlPriv; /* 'Add device to resolving list' input param */
|
||||
bool_t addrResEnable; /* 'Set address resolution enable' input param */
|
||||
uint8_t genAddrBuf[HCI_ENCRYPT_DATA_LEN]; /* Random value buffer for generating an RPA */
|
||||
} dmPrivCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* component inteface */
|
||||
void dmPrivMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPrivHciHandler(hciEvt_t *pEvent);
|
||||
void dmPrivReset(void);
|
||||
|
||||
/* action functions */
|
||||
void dmPrivActResolveAddr(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActResAddrAesCmpl(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActAddDevToResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActRemDevFromResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActSetAddrResEnable(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActClearResList(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActSetPrivacyMode(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActGenAddr(dmPrivMsg_t *pMsg);
|
||||
void dmPrivActGenAddrAesCmpl(dmPrivMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_PRIV_H */
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager scan module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
dmScanCb_t dmScanCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the scan module.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmScanInit(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* initialize control block */
|
||||
for (i = 0; i < DM_NUM_PHYS; i++)
|
||||
{
|
||||
dmScanCb.scanInterval[i] = DM_GAP_SCAN_FAST_INT_MIN;
|
||||
dmScanCb.scanWindow[i] = DM_GAP_SCAN_FAST_WINDOW;
|
||||
}
|
||||
|
||||
dmCb.scanFiltPolicy = HCI_FILT_NONE;
|
||||
dmScanCb.scanTimer.handlerId = dmCb.handlerId;
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
dmCb.scanAddrType = DM_ADDR_PUBLIC;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start scanning on the given PHYs.
|
||||
*
|
||||
* \param scanPhys Scanner PHYs.
|
||||
* \param mode Discoverability mode.
|
||||
* \param pScanType Scan type array.
|
||||
* \param filterDup Filter duplicates. Set to TRUE to filter duplicate responses received
|
||||
* from the same device. Set to FALSE to receive all responses.
|
||||
* \param duration The scan duration, in milliseconds. If set to zero or both duration and
|
||||
* period set to non-zero, scanning will continue until DmScanStop() is called.
|
||||
* \param period The scan period, in 1.28 sec units (only applicable to AE). If set to zero,
|
||||
* periodic scanning is disabled.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanStart(uint8_t scanPhys, uint8_t mode, const uint8_t *pScanType, bool_t filterDup,
|
||||
uint16_t duration, uint16_t period)
|
||||
{
|
||||
uint8_t i; /* scanPhy bit position */
|
||||
uint8_t idx; /* param array index */
|
||||
dmScanApiStart_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(dmScanApiStart_t))) != NULL)
|
||||
{
|
||||
pMsg->hdr.event = DM_SCAN_MSG_API_START;
|
||||
pMsg->scanPhys = scanPhys;
|
||||
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
/* scan type for this PHY */
|
||||
pMsg->scanType[idx] = pScanType[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
pMsg->mode = mode;
|
||||
pMsg->duration = duration;
|
||||
pMsg->period = period;
|
||||
pMsg->filterDup = filterDup;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop scanning.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanStop(void)
|
||||
{
|
||||
wsfMsgHdr_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pMsg->event = DM_SCAN_MSG_API_STOP;
|
||||
WsfMsgSend(dmCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the scan interval and window.
|
||||
*
|
||||
* \param phyIdx The scanning PHY.
|
||||
* \param scanInterval The scan interval.
|
||||
* \param scanWindow The scan window.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmScanSetInterval(uint8_t scanPhy, uint16_t scanInterval, uint16_t scanWindow)
|
||||
{
|
||||
uint8_t phyIdx;
|
||||
|
||||
WSF_ASSERT((scanPhy == HCI_INIT_PHY_LE_1M_BIT) || (scanPhy == HCI_INIT_PHY_LE_CODED_BIT));
|
||||
|
||||
WsfTaskLock();
|
||||
phyIdx = DmScanPhyToIdx(scanPhy);
|
||||
dmScanCb.scanInterval[phyIdx] = scanInterval;
|
||||
dmScanCb.scanWindow[phyIdx] = scanWindow;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the scan interval and window for the specified PHYs.
|
||||
*
|
||||
* \param scanPhys Scanning PHYs.
|
||||
* \param pScanInterval Scan interval array.
|
||||
* \param pScanWindow Scan window array.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanSetInterval(uint8_t scanPhys, uint16_t *pScanInterval, uint16_t *pScanWindow)
|
||||
{
|
||||
uint8_t i; /* scanPhy bit position */
|
||||
uint8_t idx; /* param array index */
|
||||
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (scanPhys & (1 << i))
|
||||
{
|
||||
dmScanSetInterval((1 << i), pScanInterval[idx], pScanWindow[idx]);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the local address type used while scanning. This function can be used to
|
||||
* configure scanning to use a random address.
|
||||
*
|
||||
* \param addrType Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmScanSetAddrType(uint8_t addrType)
|
||||
{
|
||||
WsfTaskLock();
|
||||
dmCb.scanAddrType = addrType;
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief DM scan module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef DM_SCAN_H
|
||||
#define DM_SCAN_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* DM scan event handler messages */
|
||||
enum
|
||||
{
|
||||
DM_SCAN_MSG_API_START = DM_MSG_START(DM_ID_SCAN),
|
||||
DM_SCAN_MSG_API_STOP,
|
||||
DM_SCAN_MSG_TIMEOUT
|
||||
};
|
||||
|
||||
/* DM scan states */
|
||||
enum
|
||||
{
|
||||
DM_SCAN_STATE_IDLE,
|
||||
DM_SCAN_STATE_STARTING,
|
||||
DM_SCAN_STATE_SCANNING,
|
||||
DM_SCAN_STATE_STOPPING
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data structure for DM_SCAN_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t scanPhys;
|
||||
uint8_t scanType[DM_NUM_PHYS];
|
||||
uint8_t mode;
|
||||
uint16_t duration;
|
||||
uint16_t period;
|
||||
bool_t filterDup;
|
||||
} dmScanApiStart_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_START */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advSid;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint16_t skip;
|
||||
uint16_t syncTimeout;
|
||||
uint8_t unused;
|
||||
} dmSyncApiStart_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_ADD_DEV_TO_PER_ADV_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint8_t advSid;
|
||||
} dmSyncApiAddDevToPerAdvList_t;
|
||||
|
||||
/* Data structure for DM_SYNC_MSG_API_REM_DEV_FROM_PER_ADV_LIST */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
uint8_t advAddrType;
|
||||
bdAddr_t advAddr;
|
||||
uint8_t advSid;
|
||||
} dmSyncApiRemDevFromPerAdvList_t;
|
||||
|
||||
/* Union of all scan messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmScanApiStart_t apiStart;
|
||||
} dmScanMsg_t;
|
||||
|
||||
/* Union of all DM Sync state machine messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmSyncApiStart_t apiSyncStart;
|
||||
hciLePerAdvSyncEstEvt_t perAdvSyncEst;
|
||||
hciLePerAdvSyncLostEvt_t perAdvSyncLost;
|
||||
HciLePerAdvSyncTrsfRcvdEvt_t perAdvSyncTrsfEst;
|
||||
} dmSyncMsg_t;
|
||||
|
||||
/* Action function */
|
||||
typedef void (*dmScanAct_t)(dmScanMsg_t *pMsg);
|
||||
|
||||
/* Control block for scan module */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t scanTimer;
|
||||
uint16_t scanInterval[DM_NUM_PHYS];
|
||||
uint16_t scanWindow[DM_NUM_PHYS];
|
||||
bool_t scanState;
|
||||
uint16_t scanDuration;
|
||||
bool_t filterNextScanRsp;
|
||||
uint8_t discFilter;
|
||||
} dmScanCb_t;
|
||||
|
||||
/* Control block for periodic advertising sync module */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t advSid; /*!< advertising SID */
|
||||
bdAddr_t advAddr; /*!< advertiser address */
|
||||
uint8_t advAddrType; /*!< advertiser address type */
|
||||
uint16_t handle; /*!< sync handle */
|
||||
dmSyncId_t syncId; /*!< sync id */
|
||||
uint8_t state; /*!< sync state */
|
||||
uint8_t inUse; /*!< TRUE if entry in use */
|
||||
} dmSyncCb_t;
|
||||
|
||||
/* Data structure for DM_PAST_MSG_API_SYNC_TRSF and DM_PAST_MSG_API_INFO_TRSF */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
uint16_t serviceData; /*!< Value provided by the Host */
|
||||
dmConnId_t connId; /*!< Connection id */
|
||||
} dmPastApiTrsf_t;
|
||||
|
||||
/* Data structure for DM_PAST_MSG_API_CONFIG and DM_PAST_MSG_API_DEFAULT_CONFIG */
|
||||
typedef struct
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< Header */
|
||||
uint8_t mode; /*!< Mode */
|
||||
uint16_t skip; /*!< Skip */
|
||||
uint16_t syncTimeout; /*!< Sync timeout */
|
||||
uint8_t cteType; /*!< CTE type */
|
||||
} dmPastApiCfg_t;
|
||||
|
||||
/* Union of all DM PAST API messages */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
dmPastApiTrsf_t apiPastTrsf;
|
||||
dmPastApiCfg_t apiPastCfg;
|
||||
} dmPastMsg_t;
|
||||
|
||||
/*! Action function */
|
||||
typedef void (*dmPastAct_t)(dmPastMsg_t *pMsg);
|
||||
|
||||
extern dmScanCb_t dmScanCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* common scanning component inteface */
|
||||
void dmScanInit(void);
|
||||
|
||||
/* legacy scanning component inteface */
|
||||
void dmScanReset(void);
|
||||
void dmScanMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmScanHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* legacy scanning action functions */
|
||||
void dmScanActStart(dmScanMsg_t *pMsg);
|
||||
void dmScanActStop(dmScanMsg_t *pMsg);
|
||||
void dmScanActTimeout(dmScanMsg_t *pMsg);
|
||||
|
||||
/* extended scanning component inteface */
|
||||
void dmExtScanReset(void);
|
||||
void dmExtScanMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmExtScanHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* extended scanning action functions */
|
||||
void dmExtScanActStart(dmScanMsg_t *pMsg);
|
||||
void dmExtScanActStop(dmScanMsg_t *pMsg);
|
||||
void dmExtScanActTimeout(dmScanMsg_t *pMsg);
|
||||
|
||||
/* sync and sync transfer action functions */
|
||||
void dmSyncSmActNone(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActStop(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActCancelStart(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncLost(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncTrsfEst(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
void dmSyncSmActSyncTrsfEstFailed(dmSyncCb_t *pScb, dmSyncMsg_t *pMsg);
|
||||
|
||||
/* sync component inteface */
|
||||
void dmSyncInit(void);
|
||||
void dmSyncReset(void);
|
||||
void dmSyncMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmSyncHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* past action functions */
|
||||
void dmPastActRptRcvEnable(dmPastMsg_t *pMsg);
|
||||
void dmPastActSyncTsfr(dmPastMsg_t *pMsg);
|
||||
void dmPastActSetInfoTrsf(dmPastMsg_t *pMsg);
|
||||
void dmPastActConfig(dmPastMsg_t *pMsg);
|
||||
void dmPastActDefaultConfig(dmPastMsg_t *pMsg);
|
||||
|
||||
/* past component inteface */
|
||||
void dmPastMsgHandler(wsfMsgHdr_t *pMsg);
|
||||
void dmPastHciHandler(hciEvt_t *pEvent);
|
||||
|
||||
/* sync utility functions */
|
||||
dmSyncCb_t *dmSyncCbById(dmSyncId_t syncId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DM_SCAN_H */
|
||||
Vendored
+362
@@ -0,0 +1,362 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device manager extended scan module.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "dm_api.h"
|
||||
#include "dm_scan.h"
|
||||
#include "dm_conn.h"
|
||||
#include "dm_dev.h"
|
||||
#include "dm_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* extended scan action function table */
|
||||
static const dmScanAct_t dmScanAct[] =
|
||||
{
|
||||
dmExtScanActStart,
|
||||
dmExtScanActStop,
|
||||
dmExtScanActTimeout
|
||||
};
|
||||
|
||||
/* extended scan component function interface */
|
||||
static const dmFcnIf_t dmScanFcnIf =
|
||||
{
|
||||
dmExtScanReset,
|
||||
dmExtScanHciHandler,
|
||||
dmExtScanMsgHandler
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* event being reported used for a legacy advertising PDU or a scan response */
|
||||
#define DM_ADV_RPT_SCAN_RSP(evtType) ((((evtType) == HCI_ADV_RPT_LEG_CONN_UNDIRECT_SCAN_RSP) || \
|
||||
((evtType) == HCI_ADV_RPT_LEG_SCAN_UNDIRECT_SCAN_RSP)) || \
|
||||
((((evtType) & HCI_ADV_RPT_LEG_ADV_BIT) == 0) && \
|
||||
((evtType) & HCI_ADV_RPT_SCAN_RSP_BIT)))
|
||||
|
||||
/* data status field of extended advertising report event type */
|
||||
#define DM_ADV_RPT_DATA_STATUS(evtType) (((evtType) & HCI_ADV_RPT_DATA_STATUS_BITS) >> 5)
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start extended scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActStart(dmScanMsg_t *pMsg)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t idx;
|
||||
uint8_t phyIdx;
|
||||
hciExtScanParam_t scanParam[DM_NUM_PHYS];
|
||||
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_IDLE)
|
||||
{
|
||||
/* see advertising packets to be received on which PHY */
|
||||
for (i = 0, idx = 0; (i < 8) && (idx < DM_NUM_PHYS); i++)
|
||||
{
|
||||
if (pMsg->apiStart.scanPhys & (1 << i))
|
||||
{
|
||||
phyIdx = DmScanPhyToIdx(1 << i);
|
||||
|
||||
/* set extended scan parameters for this PHY */
|
||||
scanParam[idx].scanType = pMsg->apiStart.scanType[idx];
|
||||
scanParam[idx].scanInterval = dmScanCb.scanInterval[phyIdx];
|
||||
scanParam[idx].scanWindow = dmScanCb.scanWindow[phyIdx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* set extended scan parameters to be used on primary advertising channel */
|
||||
HciLeSetExtScanParamCmd(DmLlAddrType(dmCb.scanAddrType), dmCb.scanFiltPolicy,
|
||||
pMsg->apiStart.scanPhys, scanParam);
|
||||
|
||||
/* initialize scan result filtering */
|
||||
if (pMsg->apiStart.mode == DM_DISC_MODE_LIMITED)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC;
|
||||
}
|
||||
else if (pMsg->apiStart.mode == DM_DISC_MODE_GENERAL)
|
||||
{
|
||||
dmScanCb.discFilter = DM_FLAG_LE_LIMITED_DISC | DM_FLAG_LE_GENERAL_DISC;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmScanCb.discFilter = 0;
|
||||
}
|
||||
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
|
||||
/* enable scan */
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STARTING;
|
||||
HciLeExtScanEnableCmd(TRUE, pMsg->apiStart.filterDup, (pMsg->apiStart.duration / 10), pMsg->apiStart.period);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop extended scanning action function.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActStop(dmScanMsg_t *pMsg)
|
||||
{
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* disable scan */
|
||||
dmScanCb.scanState = DM_SCAN_STATE_STOPPING;
|
||||
HciLeExtScanEnableCmd(FALSE, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an scan timeout.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanActTimeout(dmScanMsg_t *pMsg)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an extended advertising report event from HCI.
|
||||
*
|
||||
* \param pEvent Pointer to HCI callback event structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void dmExtScanActHciReport(hciEvt_t *pEvent)
|
||||
{
|
||||
uint8_t *p;
|
||||
static bool_t filtered = FALSE;
|
||||
static bool_t firstFrag = TRUE;
|
||||
|
||||
/* ignore if not scanning */
|
||||
if (dmScanCb.scanState == DM_SCAN_STATE_SCANNING)
|
||||
{
|
||||
/* if filtering results for limited or general discovery, and first fragment */
|
||||
if ((dmScanCb.discFilter != 0) && firstFrag)
|
||||
{
|
||||
/* if this is a scan response */
|
||||
if (DM_ADV_RPT_SCAN_RSP(pEvent->leExtAdvReport.eventType))
|
||||
{
|
||||
/* check if filtering next scan response */
|
||||
if (dmScanCb.filterNextScanRsp)
|
||||
{
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = FALSE;
|
||||
}
|
||||
}
|
||||
/* else it's an advertising response */
|
||||
else
|
||||
{
|
||||
/* find flags in advertising data */
|
||||
p = DmFindAdType(DM_ADV_TYPE_FLAGS, pEvent->leExtAdvReport.len, pEvent->leExtAdvReport.pData);
|
||||
if (p == NULL)
|
||||
{
|
||||
/* flags not found */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
/* else flags found; check them */
|
||||
else if ((p[DM_AD_DATA_IDX] & dmScanCb.discFilter) == 0)
|
||||
{
|
||||
/* flags do not match discovery mode */
|
||||
filtered = TRUE;
|
||||
dmScanCb.filterNextScanRsp = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
firstFrag = FALSE;
|
||||
}
|
||||
|
||||
if (!filtered)
|
||||
{
|
||||
pEvent->hdr.event = DM_EXT_SCAN_REPORT_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
|
||||
/* if filtering results for limited or general discovery, and no more fragmented data to come */
|
||||
if ((dmScanCb.discFilter != 0) &&
|
||||
(DM_ADV_RPT_DATA_STATUS(pEvent->leExtAdvReport.eventType) != HCI_ADV_RPT_DATA_INCMPL_MORE))
|
||||
{
|
||||
/* reset our flags */
|
||||
filtered = FALSE;
|
||||
firstFrag = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM extended scan reset function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanReset(void)
|
||||
{
|
||||
hciLeScanTimeoutEvt_t scanTimeout;
|
||||
|
||||
/* if stopping scan or scanning */
|
||||
if ((dmScanCb.scanState == DM_SCAN_STATE_STOPPING) ||
|
||||
(dmScanCb.scanState == DM_SCAN_STATE_SCANNING))
|
||||
{
|
||||
/* generate HCI scan timeout event */
|
||||
scanTimeout.hdr.event = HCI_LE_SCAN_TIMEOUT_CBACK_EVT;
|
||||
scanTimeout.hdr.status = HCI_SUCCESS;
|
||||
|
||||
/* handle the event */
|
||||
dmExtScanHciHandler((hciEvt_t *) &scanTimeout);
|
||||
}
|
||||
|
||||
/* reset scan module */
|
||||
dmScanInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM extended scan HCI event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanHciHandler(hciEvt_t *pEvent)
|
||||
{
|
||||
DM_TRACE_INFO2("dmExtScanHciHandler: event: %d state: %d", pEvent->hdr.event, dmScanCb.scanState);
|
||||
|
||||
if (pEvent->hdr.event == HCI_LE_EXT_ADV_REPORT_CBACK_EVT)
|
||||
{
|
||||
dmExtScanActHciReport(pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_SCAN_TIMEOUT_CBACK_EVT)
|
||||
{
|
||||
dmScanCb.scanState = DM_SCAN_STATE_IDLE;
|
||||
|
||||
/* pass scanning stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv(DM_DEV_PRIV_MSG_RPA_STOP, DM_EXT_SCAN_STOP_IND, 0, 0);
|
||||
|
||||
/* call callback */
|
||||
pEvent->hdr.event = DM_EXT_SCAN_STOP_IND;
|
||||
(*dmCb.cback)((dmEvt_t *) pEvent);
|
||||
}
|
||||
else if (pEvent->hdr.event == HCI_LE_EXT_SCAN_ENABLE_CMD_CMPL_CBACK_EVT)
|
||||
{
|
||||
switch (dmScanCb.scanState)
|
||||
{
|
||||
case DM_SCAN_STATE_STARTING:
|
||||
pEvent->hdr.event = DM_EXT_SCAN_START_IND;
|
||||
dmScanCb.scanState = pEvent->hdr.status == HCI_SUCCESS? DM_SCAN_STATE_SCANNING : DM_SCAN_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case DM_SCAN_STATE_STOPPING:
|
||||
pEvent->hdr.event = DM_EXT_SCAN_STOP_IND;
|
||||
dmScanCb.scanState = pEvent->hdr.status == HCI_SUCCESS? DM_SCAN_STATE_IDLE : DM_SCAN_STATE_SCANNING;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should never happen */
|
||||
WSF_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* pass scanning start/stop event to dev priv */
|
||||
dmDevPassEvtToDevPriv((pEvent->hdr.event == DM_EXT_SCAN_START_IND) ? \
|
||||
DM_DEV_PRIV_MSG_RPA_START : DM_DEV_PRIV_MSG_RPA_STOP, pEvent->hdr.event,
|
||||
0, 0);
|
||||
|
||||
/* call callback */
|
||||
(*dmCb.cback)((dmEvt_t *)pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM scan event handler.
|
||||
*
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void dmExtScanMsgHandler(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* execute action function */
|
||||
(*dmScanAct[DM_MSG_MASK(pMsg->event)])((dmScanMsg_t *)pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize DM extended scanning.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DmExtScanInit(void)
|
||||
{
|
||||
WsfTaskLock();
|
||||
|
||||
/* set function interface table */
|
||||
dmFcnIfTbl[DM_ID_SCAN] = (dmFcnIf_t *) &dmScanFcnIf;
|
||||
|
||||
/* initialize scan/sync modules */
|
||||
dmScanInit();
|
||||
dmSyncInit();
|
||||
|
||||
WsfTaskUnlock();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Whether DM scanning is in extended mode.
|
||||
*
|
||||
* \return TRUE if DM scanning is in extended mode. FALSE, otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t DmScanModeExt(void)
|
||||
{
|
||||
return (dmFcnIfTbl[DM_ID_SCAN] == (dmFcnIf_t *) &dmScanFcnIf) ? TRUE : FALSE;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user