mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #13449 from paul-szczepanek-arm/fix-prep-write
BLE: Fix writing attributes larger than MTU sizepull/13468/head
commit
31701fa518
|
@ -381,13 +381,11 @@ private:
|
||||||
struct PrepareWriteResponseConverter : ResponseConverter<ATTC_PREPARE_WRITE_RSP> {
|
struct PrepareWriteResponseConverter : ResponseConverter<ATTC_PREPARE_WRITE_RSP> {
|
||||||
static AttPrepareWriteResponse convert(const attEvt_t* event)
|
static AttPrepareWriteResponse convert(const attEvt_t* event)
|
||||||
{
|
{
|
||||||
// WARNING: Not sure if correct, the stack erase the length parameter
|
|
||||||
return AttPrepareWriteResponse(
|
return AttPrepareWriteResponse(
|
||||||
event->handle,
|
event->handle,
|
||||||
to_uint16_t(event->pValue + 2),
|
0, /* offset is lost */
|
||||||
// FIXME: the stack set the lenght to 0, the data won't be seen ...
|
|
||||||
make_const_Span(
|
make_const_Span(
|
||||||
event->pValue + 4,
|
event->pValue,
|
||||||
event->valueLen
|
event->valueLen
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -260,7 +260,7 @@ void attsProcPrepWriteReq(attsCcb_t *pCcb, uint16_t len, uint8_t *pPacket)
|
||||||
}
|
}
|
||||||
/* verify write length, fixed length */
|
/* verify write length, fixed length */
|
||||||
else if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) == 0) &&
|
else if (((pAttr->settings & ATTS_SET_VARIABLE_LEN) == 0) &&
|
||||||
(writeLen != pAttr->maxLen))
|
(writeLen > pAttr->maxLen))
|
||||||
{
|
{
|
||||||
err = ATT_ERR_LENGTH;
|
err = ATT_ERR_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -637,11 +637,13 @@ struct GattClient::WriteControlBlock : public ProcedureControlBlock {
|
||||||
using ProcedureControlBlock::connection_handle;
|
using ProcedureControlBlock::connection_handle;
|
||||||
|
|
||||||
WriteControlBlock(
|
WriteControlBlock(
|
||||||
connection_handle_t connection_handle, uint16_t attribute_handle,
|
connection_handle_t connection_handle,
|
||||||
uint8_t* data, uint16_t len
|
uint16_t attribute_handle,
|
||||||
|
uint8_t* data,
|
||||||
|
uint16_t write_length
|
||||||
) : ProcedureControlBlock(WRITE_PROCEDURE, connection_handle),
|
) : ProcedureControlBlock(WRITE_PROCEDURE, connection_handle),
|
||||||
attribute_handle(attribute_handle), len(len), offset(0), data(data),
|
attribute_handle(attribute_handle), write_length(write_length), offset(0), data(data),
|
||||||
prepare_success(false), status(BLE_ERROR_UNSPECIFIED), error_code(0xFF) {
|
prepare_success(false), status(BLE_ERROR_INITIALIZATION_INCOMPLETE), error_code(0xFF) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~WriteControlBlock() {
|
virtual ~WriteControlBlock() {
|
||||||
|
@ -722,19 +724,21 @@ struct GattClient::WriteControlBlock : public ProcedureControlBlock {
|
||||||
|
|
||||||
void handle_prepare_write_response(GattClient* client, const AttPrepareWriteResponse& write_response) {
|
void handle_prepare_write_response(GattClient* client, const AttPrepareWriteResponse& write_response) {
|
||||||
ble_error_t err = BLE_ERROR_UNSPECIFIED;
|
ble_error_t err = BLE_ERROR_UNSPECIFIED;
|
||||||
|
offset += write_response.partial_value.size();
|
||||||
uint16_t mtu_size = client->get_mtu(connection_handle);
|
uint16_t data_left = write_length - offset; /* offset is guaranteed to be less of equal to write_length */
|
||||||
offset = write_response.offset + write_response.partial_value.size();
|
if (data_left) {
|
||||||
if (offset < len) {
|
uint16_t chunk_size = client->get_mtu(connection_handle) - PREPARE_WRITE_HEADER_LENGTH;
|
||||||
|
if (chunk_size > data_left) {
|
||||||
|
chunk_size = data_left;
|
||||||
|
}
|
||||||
err = client->_pal_client.queue_prepare_write(
|
err = client->_pal_client.queue_prepare_write(
|
||||||
connection_handle, attribute_handle,
|
connection_handle,
|
||||||
make_const_Span(
|
attribute_handle,
|
||||||
data + offset,
|
make_const_Span(data + offset, chunk_size),
|
||||||
std::min((len - offset), (mtu_size - 5))
|
|
||||||
),
|
|
||||||
offset
|
offset
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
prepare_success = true;
|
||||||
err = client->_pal_client.execute_write_queue(
|
err = client->_pal_client.execute_write_queue(
|
||||||
connection_handle, true
|
connection_handle, true
|
||||||
);
|
);
|
||||||
|
@ -829,7 +833,7 @@ struct GattClient::WriteControlBlock : public ProcedureControlBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t attribute_handle;
|
uint16_t attribute_handle;
|
||||||
uint16_t len;
|
uint16_t write_length;
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
bool prepare_success;
|
bool prepare_success;
|
||||||
|
@ -1199,7 +1203,7 @@ ble_error_t GattClient::write(
|
||||||
err = _pal_client.queue_prepare_write(
|
err = _pal_client.queue_prepare_write(
|
||||||
connection_handle,
|
connection_handle,
|
||||||
attribute_handle,
|
attribute_handle,
|
||||||
make_const_Span(value, mtu - PREPARE_WRITE_HEADER_LENGTH),
|
make_const_Span(data, mtu - PREPARE_WRITE_HEADER_LENGTH),
|
||||||
/* offset */0
|
/* offset */0
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -329,6 +329,7 @@ ble_error_t GattServer::insert_characteristic_value_attribute(
|
||||||
}
|
}
|
||||||
if (properties & WRITABLE_PROPERTIES) {
|
if (properties & WRITABLE_PROPERTIES) {
|
||||||
attribute_it->settings |= ATTS_SET_WRITE_CBACK;
|
attribute_it->settings |= ATTS_SET_WRITE_CBACK;
|
||||||
|
attribute_it->settings |= ATTS_SET_ALLOW_OFFSET;
|
||||||
}
|
}
|
||||||
if (value_attribute.getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
|
if (value_attribute.getUUID().shortOrLong() == UUID::UUID_TYPE_LONG) {
|
||||||
attribute_it->settings |= ATTS_SET_UUID_128;
|
attribute_it->settings |= ATTS_SET_UUID_128;
|
||||||
|
@ -990,9 +991,39 @@ uint8_t GattServer::atts_write_cb(
|
||||||
{
|
{
|
||||||
uint8_t err;
|
uint8_t err;
|
||||||
|
|
||||||
/* TODO: offset is not handled properly */
|
GattCharacteristic* auth_char = getInstance().get_auth_char(handle);
|
||||||
if ((err = AttsSetAttr(handle, len, pValue)) != ATT_SUCCESS) {
|
if (auth_char && auth_char->isWriteAuthorizationEnabled()) {
|
||||||
return err;
|
GattWriteAuthCallbackParams write_auth_params = {
|
||||||
|
connId,
|
||||||
|
handle,
|
||||||
|
offset,
|
||||||
|
len,
|
||||||
|
pValue,
|
||||||
|
AUTH_CALLBACK_REPLY_SUCCESS
|
||||||
|
};
|
||||||
|
|
||||||
|
GattAuthCallbackReply_t ret = auth_char->authorizeWrite(&write_auth_params);
|
||||||
|
if (ret!= AUTH_CALLBACK_REPLY_SUCCESS) {
|
||||||
|
return ret & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't write anything during the prepare phase */
|
||||||
|
bool write_happened = (operation != ATT_PDU_PREP_WRITE_REQ);
|
||||||
|
|
||||||
|
MBED_ASSERT(len + offset <= pAttr->maxLen);
|
||||||
|
|
||||||
|
if (write_happened) {
|
||||||
|
WsfTaskLock();
|
||||||
|
|
||||||
|
memcpy((pAttr->pValue + offset), pValue, len);
|
||||||
|
|
||||||
|
/* write the length if variable length attribute */
|
||||||
|
if ((pAttr->settings & ATTS_SET_VARIABLE_LEN) != 0) {
|
||||||
|
*(pAttr->pLen) = offset + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
WsfTaskUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
GattWriteCallbackParams::WriteOp_t writeOp;
|
GattWriteCallbackParams::WriteOp_t writeOp;
|
||||||
|
@ -1025,23 +1056,7 @@ uint8_t GattServer::atts_write_cb(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GattCharacteristic* auth_char = getInstance().get_auth_char(handle);
|
if (write_happened) {
|
||||||
if (auth_char && auth_char->isWriteAuthorizationEnabled()) {
|
|
||||||
GattWriteAuthCallbackParams write_auth_params = {
|
|
||||||
connId,
|
|
||||||
handle,
|
|
||||||
offset,
|
|
||||||
len,
|
|
||||||
pValue,
|
|
||||||
AUTH_CALLBACK_REPLY_SUCCESS
|
|
||||||
};
|
|
||||||
|
|
||||||
GattAuthCallbackReply_t ret = auth_char->authorizeWrite(&write_auth_params);
|
|
||||||
if (ret!= AUTH_CALLBACK_REPLY_SUCCESS) {
|
|
||||||
return ret & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GattWriteCallbackParams write_params = {
|
GattWriteCallbackParams write_params = {
|
||||||
connId,
|
connId,
|
||||||
handle,
|
handle,
|
||||||
|
@ -1050,7 +1065,9 @@ uint8_t GattServer::atts_write_cb(
|
||||||
len,
|
len,
|
||||||
pValue
|
pValue
|
||||||
};
|
};
|
||||||
|
|
||||||
getInstance().handleDataWrittenEvent(&write_params);
|
getInstance().handleDataWrittenEvent(&write_params);
|
||||||
|
}
|
||||||
|
|
||||||
return ATT_SUCCESS;
|
return ATT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue