initial commit
This commit is contained in:
+1876
File diff suppressed because it is too large
Load Diff
+349
@@ -0,0 +1,349 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP 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 "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "l2c_api.h"
|
||||
#include "l2c_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
l2cCb_t l2cCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Default callback function for unregistered CID.
|
||||
*
|
||||
* \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 l2cDefaultDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
L2C_TRACE_WARN0("rcvd data on uregistered cid");
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Default callback function for unregistered CID.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param cid The L2CAP connection ID.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cDefaultDataCidCback(uint16_t handle, uint16_t cid, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
L2C_TRACE_WARN1("unknown cid=0x%04x", cid);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Default L2CAP control callback function.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cDefaultCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received L2CAP signaling packets.
|
||||
*
|
||||
* \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 l2cRxSignalingPkt(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t role;
|
||||
dmConnId_t connId;
|
||||
|
||||
if ((connId = DmConnIdByHandle(handle)) == DM_CONN_ID_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
role = DmConnRole(connId);
|
||||
|
||||
if ((role == DM_ROLE_MASTER) && (l2cCb.masterRxSignalingPkt != NULL))
|
||||
{
|
||||
(*l2cCb.masterRxSignalingPkt)(handle, len, pPacket);
|
||||
}
|
||||
else if ((role == DM_ROLE_SLAVE) && (l2cCb.slaveRxSignalingPkt != NULL))
|
||||
{
|
||||
(*l2cCb.slaveRxSignalingPkt)(handle, len, pPacket);
|
||||
}
|
||||
else
|
||||
{
|
||||
L2C_TRACE_ERR1("Invalid role configuration: role=%d", role);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI ACL data callback function.
|
||||
*
|
||||
* \param pPacket A buffer containing an ACL packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cHciAclCback(uint8_t *pPacket)
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t hciLen;
|
||||
uint16_t cid;
|
||||
uint16_t l2cLen;
|
||||
uint8_t *p = pPacket;
|
||||
|
||||
/* parse HCI handle and length */
|
||||
BSTREAM_TO_UINT16(handle, p);
|
||||
handle &= HCI_HANDLE_MASK;
|
||||
BSTREAM_TO_UINT16(hciLen, p);
|
||||
|
||||
/* parse L2CAP length */
|
||||
if (hciLen >= L2C_HDR_LEN)
|
||||
{
|
||||
BSTREAM_TO_UINT16(l2cLen, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
l2cLen = 0;
|
||||
}
|
||||
|
||||
/* verify L2CAP length vs HCI length */
|
||||
if (hciLen == (l2cLen + L2C_HDR_LEN))
|
||||
{
|
||||
/* parse CID */
|
||||
BSTREAM_TO_UINT16(cid, p);
|
||||
|
||||
switch (cid)
|
||||
{
|
||||
case L2C_CID_LE_SIGNALING:
|
||||
(*l2cCb.l2cSignalingCback)(handle, l2cLen, pPacket);
|
||||
break;
|
||||
|
||||
case L2C_CID_ATT:
|
||||
(*l2cCb.attDataCback)(handle, l2cLen, pPacket);
|
||||
break;
|
||||
|
||||
case L2C_CID_SMP:
|
||||
(*l2cCb.smpDataCback)(handle, l2cLen, pPacket);
|
||||
break;
|
||||
|
||||
default:
|
||||
(*l2cCb.l2cDataCidCback)(handle, cid, l2cLen, pPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else length mismatch */
|
||||
else
|
||||
{
|
||||
L2C_TRACE_WARN2("length mismatch: l2c=%u hci=%u", l2cLen, hciLen);
|
||||
}
|
||||
|
||||
/* deallocate buffer */
|
||||
WsfMsgFree(pPacket);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief HCI flow control callback function.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param flowDisabled TRUE if data flow is disabled.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cHciFlowCback(uint16_t handle, bool_t flowDisabled)
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* get conn ID for handle */
|
||||
if ((hdr.param = DmConnIdByHandle(handle)) != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* execute higher layer flow control callbacks */
|
||||
hdr.event = flowDisabled;
|
||||
(*l2cCb.attCtrlCback)(&hdr);
|
||||
hdr.event = flowDisabled;
|
||||
(*l2cCb.smpCtrlCback)(&hdr);
|
||||
|
||||
/* execute connection oriented channel flow control callback */
|
||||
hdr.event = flowDisabled;
|
||||
(*l2cCb.l2cCocCtrlCback)(&hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command reject message with reason "not understood".
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param identifier Identifier value in received message being rejected.
|
||||
* \param reason Why request was rejected.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void l2cSendCmdReject(uint16_t handle, uint8_t identifier, uint16_t reason)
|
||||
{
|
||||
uint8_t *pPacket;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate msg buffer */
|
||||
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CMD_REJ_LEN)) != NULL)
|
||||
{
|
||||
/* build message */
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, L2C_SIG_CMD_REJ); /* command code */
|
||||
UINT8_TO_BSTREAM(p, identifier); /* identifier */
|
||||
UINT16_TO_BSTREAM(p, L2C_SIG_CMD_REJ_LEN); /* parameter length */
|
||||
UINT16_TO_BSTREAM(p, reason); /* reason */
|
||||
|
||||
/* send packet */
|
||||
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CMD_REJ_LEN), pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate an L2CAP data message buffer to be used for the L2CAP protocol messages.
|
||||
*
|
||||
* \param len Message length in bytes.
|
||||
*
|
||||
* \return Pointer to data message buffer or NULL if allocation failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void *l2cMsgAlloc(uint16_t len)
|
||||
{
|
||||
return WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C subsystem.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cInit(void)
|
||||
{
|
||||
/* Initialize control block */
|
||||
l2cCb.attDataCback = l2cDefaultDataCback;
|
||||
l2cCb.smpDataCback = l2cDefaultDataCback;
|
||||
l2cCb.l2cSignalingCback = l2cRxSignalingPkt;
|
||||
l2cCb.attCtrlCback = l2cDefaultCtrlCback;
|
||||
l2cCb.smpCtrlCback = l2cDefaultCtrlCback;
|
||||
l2cCb.l2cCocCtrlCback = l2cDefaultCtrlCback;
|
||||
l2cCb.l2cDataCidCback = l2cDefaultDataCidCback;
|
||||
l2cCb.identifier = 1;
|
||||
|
||||
/* Register with HCI */
|
||||
HciAclRegister(l2cHciAclCback, l2cHciFlowCback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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)
|
||||
{
|
||||
WSF_ASSERT((cid == L2C_CID_ATT) || (cid == L2C_CID_SMP));
|
||||
|
||||
/* store the callbacks */
|
||||
if (cid == L2C_CID_ATT)
|
||||
{
|
||||
/* registering for attribute protocol */
|
||||
l2cCb.attDataCback = dataCback;
|
||||
l2cCb.attCtrlCback = ctrlCback;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* registering for security manager protocol */
|
||||
l2cCb.smpDataCback = dataCback;
|
||||
l2cCb.smpCtrlCback = 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 pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDataReq(uint16_t cid, uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *p = pPacket;
|
||||
|
||||
/* Set HCI header */
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
UINT16_TO_BSTREAM(p, (len + L2C_HDR_LEN));
|
||||
|
||||
/* Set L2CAP header */
|
||||
UINT16_TO_BSTREAM(p, len);
|
||||
UINT16_TO_BSTREAM(p, cid);
|
||||
|
||||
/* Send to HCI */
|
||||
HciSendAclData(pPacket);
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP 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 L2C_MAIN_H
|
||||
#define L2C_MAIN_H
|
||||
|
||||
#include "l2c_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Return the next L2CAP signaling req identifier. Cannot be zero. */
|
||||
#define L2C_NEXT_ID(id) (((id) == 255) ? (1) : ((id) + 1))
|
||||
|
||||
/* L2C event handler message types */
|
||||
#define L2C_MSG_REQ_TIMEOUT 1 /* L2CAP slave signaling request timeout */
|
||||
#define L2C_MSG_TYPE_MAX 1
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Data callback with CID */
|
||||
typedef void (*l2cDataCidCback_t)(uint16_t handle, uint16_t cid, uint16_t len, uint8_t *pPacket);
|
||||
|
||||
/* Main control block of the L2C subsystem */
|
||||
typedef struct
|
||||
{
|
||||
l2cDataCback_t attDataCback; /* Data callback for ATT */
|
||||
l2cDataCback_t smpDataCback; /* Data callback for SMP */
|
||||
l2cDataCback_t l2cSignalingCback; /* Data callback for L2CAP signaling */
|
||||
l2cCtrlCback_t attCtrlCback; /* Control callback for ATT */
|
||||
l2cCtrlCback_t smpCtrlCback; /* Control callback for SMP */
|
||||
l2cCtrlCback_t l2cCocCtrlCback; /* Control callback for L2CAP connection oriented channels */
|
||||
l2cDataCback_t masterRxSignalingPkt; /* Master signaling packet processing function */
|
||||
l2cDataCback_t slaveRxSignalingPkt; /* Slave signaling packet processing function */
|
||||
l2cDataCidCback_t l2cDataCidCback; /* Data callback for L2CAP on other CIDs */
|
||||
uint8_t identifier; /* Signaling request identifier */
|
||||
} l2cCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
void l2cSendCmdReject(uint16_t handle, uint8_t identifier, uint16_t reason);
|
||||
void l2cRxSignalingPkt(uint16_t handle, uint16_t len, uint8_t *pPacket);
|
||||
void *l2cMsgAlloc(uint16_t len);
|
||||
|
||||
/* Control block */
|
||||
extern l2cCb_t l2cCb;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* L2C_MAIN_H */
|
||||
Vendored
+147
@@ -0,0 +1,147 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP module for master operations.
|
||||
*
|
||||
* 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 "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "l2c_api.h"
|
||||
#include "l2c_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Master processing of received L2CAP signaling packets.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param l2cLen The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cMasterRxSignalingPkt(uint16_t handle, uint16_t l2cLen, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t code;
|
||||
uint8_t id;
|
||||
uint16_t len;
|
||||
hciConnSpec_t connSpec;
|
||||
|
||||
/* parse code, len, and identifier */
|
||||
pPacket += L2C_PAYLOAD_START;
|
||||
BSTREAM_TO_UINT8(code, pPacket);
|
||||
BSTREAM_TO_UINT8(id, pPacket);
|
||||
BSTREAM_TO_UINT16(len, pPacket);
|
||||
|
||||
/* verify signaling length vs. l2c length
|
||||
* verify this is a conn param update rsp
|
||||
* verify parameter length
|
||||
*/
|
||||
if ((l2cLen != (len + L2C_SIG_HDR_LEN)) ||
|
||||
(code != L2C_SIG_CONN_UPDATE_REQ) ||
|
||||
(len != L2C_SIG_CONN_UPDATE_REQ_LEN))
|
||||
{
|
||||
L2C_TRACE_WARN3("invalid msg code:%d len:%d l2cLen:%d", code, len, l2cLen);
|
||||
|
||||
/* reject all unknown or invalid commands except command reject. */
|
||||
if (code != L2C_SIG_CMD_REJ)
|
||||
{
|
||||
l2cSendCmdReject(handle, id, L2C_REJ_NOT_UNDERSTOOD);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse parameters */
|
||||
BSTREAM_TO_UINT16(connSpec.connIntervalMin, pPacket);
|
||||
BSTREAM_TO_UINT16(connSpec.connIntervalMax, pPacket);
|
||||
BSTREAM_TO_UINT16(connSpec.connLatency, pPacket);
|
||||
BSTREAM_TO_UINT16(connSpec.supTimeout, pPacket);
|
||||
connSpec.minCeLen = 0;
|
||||
connSpec.maxCeLen = 0;
|
||||
|
||||
/* check parameter range */
|
||||
if ((connSpec.connIntervalMin < HCI_CONN_INTERVAL_MIN) ||
|
||||
(connSpec.connIntervalMin > HCI_CONN_INTERVAL_MAX) ||
|
||||
(connSpec.connIntervalMin > connSpec.connIntervalMax) ||
|
||||
(connSpec.connIntervalMax < HCI_CONN_INTERVAL_MIN) ||
|
||||
(connSpec.connIntervalMax > HCI_CONN_INTERVAL_MAX) ||
|
||||
(connSpec.connLatency > HCI_CONN_LATENCY_MAX) ||
|
||||
(connSpec.supTimeout < HCI_SUP_TIMEOUT_MIN) ||
|
||||
(connSpec.supTimeout > HCI_SUP_TIMEOUT_MAX))
|
||||
{
|
||||
L2cDmConnUpdateRsp(id, handle, L2C_CONN_PARAM_REJECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
DmL2cConnUpdateInd(id, handle, &connSpec);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C for operation as a Bluetooth LE master.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cMasterInit(void)
|
||||
{
|
||||
l2cCb.masterRxSignalingPkt = l2cMasterRxSignalingPkt;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief 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)
|
||||
{
|
||||
uint8_t *pPacket;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate msg buffer */
|
||||
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CONN_UPDATE_RSP_LEN)) != NULL)
|
||||
{
|
||||
/* build message */
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_RSP); /* command code */
|
||||
UINT8_TO_BSTREAM(p, identifier); /* identifier */
|
||||
UINT16_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_RSP_LEN); /* parameter length */
|
||||
UINT16_TO_BSTREAM(p, result); /* result */
|
||||
|
||||
/* send packet */
|
||||
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CONN_UPDATE_RSP_LEN), pPacket);
|
||||
}
|
||||
}
|
||||
Vendored
+311
@@ -0,0 +1,311 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief L2CAP module for slave operations.
|
||||
*
|
||||
* 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_timer.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_os.h"
|
||||
#include "util/bstream.h"
|
||||
#include "l2c_api.h"
|
||||
#include "l2c_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Signaling request timeout in seconds */
|
||||
#define L2C_SIG_REQ_TIMEOUT 30
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Slave control block */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimer_t reqTimer; /* Signaling request timeout timer */
|
||||
wsfHandlerId_t handlerId; /* ID for this event handler */
|
||||
uint8_t lastCode[DM_CONN_MAX]; /* last code sent on each handle */
|
||||
uint8_t signId[DM_CONN_MAX]; /* expected signaling identifier */
|
||||
} l2cSlaveCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
static l2cSlaveCb_t l2cSlaveCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle slave signaling request timeout.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cSlaveReqTimeout(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
L2C_TRACE_WARN0("conn update req timeout");
|
||||
|
||||
/* Notify DM that connection update has failed (handle is stored in param) */
|
||||
DmL2cConnUpdateCnf(pMsg->param, L2C_CONN_PARAM_REJECTED);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Slave processing of received L2CAP signaling packets.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param l2cLen The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void l2cSlaveRxSignalingPkt(uint16_t handle, uint16_t l2cLen, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t code;
|
||||
uint8_t id;
|
||||
uint16_t len;
|
||||
uint16_t result;
|
||||
|
||||
/* parse code, len, and identifier */
|
||||
pPacket += L2C_PAYLOAD_START;
|
||||
BSTREAM_TO_UINT8(code, pPacket);
|
||||
BSTREAM_TO_UINT8(id, pPacket);
|
||||
BSTREAM_TO_UINT16(len, pPacket);
|
||||
|
||||
/* verify signal identifier is valid */
|
||||
if (id == L2C_SIGNAL_ID_INVALID)
|
||||
{
|
||||
/* not expected, ignore */
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify signal identifier is expected
|
||||
* verify signaling length vs. l2c length
|
||||
* verify this is a conn param update rsp or command reject
|
||||
* verify parameter length
|
||||
*/
|
||||
if ((id == l2cSlaveCb.signId[handle]) &&
|
||||
(l2cLen == (len + L2C_SIG_HDR_LEN)) &&
|
||||
(((code == L2C_SIG_CONN_UPDATE_RSP) && (len == L2C_SIG_CONN_UPDATE_RSP_LEN)) ||
|
||||
(code == L2C_SIG_CMD_REJ)))
|
||||
{
|
||||
/* get last sent code */
|
||||
uint8_t lastCode = l2cSlaveCb.lastCode[handle];
|
||||
|
||||
/* clear pending signal id */
|
||||
l2cSlaveCb.signId[handle] = L2C_SIGNAL_ID_INVALID;
|
||||
|
||||
/* parse result parameter */
|
||||
BSTREAM_TO_UINT16(result, pPacket);
|
||||
|
||||
/* stop req timer */
|
||||
WsfTimerStop(&l2cSlaveCb.reqTimer);
|
||||
|
||||
if (lastCode == L2C_SIG_CONN_UPDATE_REQ)
|
||||
{
|
||||
if (code == L2C_SIG_CMD_REJ)
|
||||
{
|
||||
/* got command reject */
|
||||
result = L2C_CONN_PARAM_REJECTED;
|
||||
}
|
||||
|
||||
/* send to DM */
|
||||
DmL2cConnUpdateCnf(handle, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send to DM */
|
||||
DmL2cCmdRejInd(handle, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
L2C_TRACE_WARN3("invalid msg code:%d len:%d l2cLen:%d", code, len, l2cLen);
|
||||
|
||||
/* reject all unknown, invalid or unidentified commands except command reject. */
|
||||
if (code != L2C_SIG_CMD_REJ)
|
||||
{
|
||||
l2cSendCmdReject(handle, id, L2C_REJ_NOT_UNDERSTOOD);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize L2C for operation as a Bluetooth LE slave.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cSlaveInit(void)
|
||||
{
|
||||
l2cCb.slaveRxSignalingPkt = l2cSlaveRxSignalingPkt;
|
||||
|
||||
for (uint8_t i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
l2cSlaveCb.signId[i] = L2C_SIGNAL_ID_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build and send a signaling packet.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param code Type of command.
|
||||
* \param len Length of \ref pParam.
|
||||
* \param pParam parameters of command to send.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void L2cDmSigReq(uint16_t handle, uint8_t code, uint16_t len, uint8_t *pParam)
|
||||
{
|
||||
uint8_t *pPacket;
|
||||
uint8_t *p;
|
||||
|
||||
WSF_ASSERT(handle < DM_CONN_MAX);
|
||||
|
||||
/* record code */
|
||||
l2cSlaveCb.lastCode[handle] = code;
|
||||
|
||||
/* Start signaling request timer and store handle */
|
||||
WsfTimerStartSec(&l2cSlaveCb.reqTimer, L2C_SIG_REQ_TIMEOUT);
|
||||
l2cSlaveCb.reqTimer.msg.param = handle;
|
||||
|
||||
/* allocate msg buffer */
|
||||
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + len)) != NULL)
|
||||
{
|
||||
/* build message */
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, code); /* command code */
|
||||
l2cSlaveCb.signId[handle] = l2cCb.identifier;
|
||||
UINT8_TO_BSTREAM(p, l2cCb.identifier); /* identifier */
|
||||
l2cCb.identifier = L2C_NEXT_ID(l2cCb.identifier);
|
||||
UINT16_TO_BSTREAM(p, len); /* parameter length */
|
||||
memcpy(p, pParam, len); /* parameters */
|
||||
|
||||
/* send packet */
|
||||
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + len), pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief 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)
|
||||
{
|
||||
uint8_t *pPacket;
|
||||
uint8_t *p;
|
||||
|
||||
/* record code */
|
||||
l2cSlaveCb.lastCode[handle] = L2C_SIG_CONN_UPDATE_REQ;
|
||||
|
||||
/* Start signaling request timer and store handle */
|
||||
WsfTimerStartSec(&l2cSlaveCb.reqTimer, L2C_SIG_REQ_TIMEOUT);
|
||||
l2cSlaveCb.reqTimer.msg.param = handle;
|
||||
|
||||
/* allocate msg buffer */
|
||||
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CONN_UPDATE_REQ_LEN)) != NULL)
|
||||
{
|
||||
/* build message */
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_REQ); /* command code */
|
||||
UINT8_TO_BSTREAM(p, l2cCb.identifier); /* identifier */
|
||||
l2cSlaveCb.signId[handle] = l2cCb.identifier;
|
||||
l2cCb.identifier = L2C_NEXT_ID(l2cCb.identifier);
|
||||
UINT16_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_REQ_LEN); /* parameter length */
|
||||
UINT16_TO_BSTREAM(p, pConnSpec->connIntervalMin); /* interval min */
|
||||
UINT16_TO_BSTREAM(p, pConnSpec->connIntervalMax); /* interval max */
|
||||
UINT16_TO_BSTREAM(p, pConnSpec->connLatency); /* slave latency */
|
||||
UINT16_TO_BSTREAM(p, pConnSpec->supTimeout); /* timeout multiplier */
|
||||
|
||||
/* send packet */
|
||||
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CONN_UPDATE_REQ_LEN), pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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)
|
||||
{
|
||||
l2cSlaveCb.reqTimer.msg.event = L2C_MSG_REQ_TIMEOUT;
|
||||
l2cSlaveCb.reqTimer.handlerId = handlerId;
|
||||
l2cSlaveCb.handlerId = 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)
|
||||
{
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
WSF_ASSERT(pMsg->event > 0 && pMsg->event <= L2C_MSG_TYPE_MAX);
|
||||
|
||||
/* handle slave signaling request timeout */
|
||||
if (pMsg->event == L2C_MSG_REQ_TIMEOUT)
|
||||
{
|
||||
l2cSlaveReqTimeout(pMsg);
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user