Skip to content

Commit

Permalink
Unit tests for BLE layer class (#33359)
Browse files Browse the repository at this point in the history
* Unit tests for BLE layer class

* Check for mBleTransport NULL before dereference

* Return false in case of handle error in BLE layer

* Check for NULL UUIDs match

* Test for exceeding max number of BLE connections

* Fix compilation on ESP32

* More compilation fixes

* Mark SetUp and TearDown as overrides

* Update includes
  • Loading branch information
arkq authored May 10, 2024
1 parent 2d6d403 commit f075b9b
Show file tree
Hide file tree
Showing 6 changed files with 484 additions and 191 deletions.
6 changes: 3 additions & 3 deletions src/ble/BLEEndPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ void BLEEndPoint::DoClose(uint8_t flags, CHIP_ERROR err)
DoCloseCallback(oldState, flags, err);
}

if ((flags & kBleCloseFlag_SuppressCallback) != 0)
if (mBleTransport != nullptr && (flags & kBleCloseFlag_SuppressCallback) != 0)
{
mBleTransport->OnEndPointConnectionClosed(this, err);
}
Expand All @@ -367,7 +367,7 @@ void BLEEndPoint::FinalizeClose(uint8_t oldState, uint8_t flags, CHIP_ERROR err)
DoCloseCallback(oldState, flags, err);
}

if ((flags & kBleCloseFlag_SuppressCallback) != 0)
if (mBleTransport != nullptr && (flags & kBleCloseFlag_SuppressCallback) != 0)
{
mBleTransport->OnEndPointConnectionClosed(this, err);
}
Expand Down Expand Up @@ -1290,7 +1290,7 @@ CHIP_ERROR BLEEndPoint::Receive(PacketBufferHandle && data)
// Take ownership of message buffer
System::PacketBufferHandle full_packet = mBtpEngine.TakeRxPacket();

ChipLogDebugBleEndPoint(Ble, "reassembled whole msg, len = %d", full_packet->DataLength());
ChipLogDebugBleEndPoint(Ble, "reassembled whole msg, len = %u", static_cast<unsigned>(full_packet->DataLength()));

// If we have a message received callback, and end point is not closing...
if (mBleTransport != nullptr && mState != kState_Closing)
Expand Down
256 changes: 70 additions & 186 deletions src/ble/BleLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* a platform's Bluetooth Low Energy (BLE) implementation and the CHIP
* stack.
*
* The BleLayer obect accepts BLE data and control input from the
* The BleLayer object accepts BLE data and control input from the
* application via a functional interface. It performs the fragmentation
* and reassembly required to transmit CHIP message via a BLE GATT
* characteristic interface, and drives incoming messages up the CHIP
Expand Down Expand Up @@ -485,43 +485,24 @@ CHIP_ERROR BleLayer::HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT
bool BleLayer::HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle && pBuf)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
ChipLogError(Ble, "ble write rcvd on unknown svc id");
return true;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Write received on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_1_ID, charId), false, ChipLogError(Ble, "Write received on unknown char"));
VerifyOrReturnError(!pBuf.IsNull(), false, ChipLogError(Ble, "Write received null buffer"));

if (UUIDsMatch(&CHIP_BLE_CHAR_1_ID, charId))
{
if (pBuf.IsNull())
{
ChipLogError(Ble, "rcvd null ble write");
return true;
}

// Find matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
// Find matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);

if (endPoint != nullptr)
{
CHIP_ERROR status = endPoint->Receive(std::move(pBuf));
if (status != CHIP_NO_ERROR)
{
ChipLogError(Ble, "BLEEndPoint rcv failed, err = %" CHIP_ERROR_FORMAT, status.Format());
}
}
else
{
CHIP_ERROR status = HandleBleTransportConnectionInitiated(connObj, std::move(pBuf));
if (status != CHIP_NO_ERROR)
{
ChipLogError(Ble, "failed handle new chip BLE connection, status = %" CHIP_ERROR_FORMAT, status.Format());
}
}
if (endPoint != nullptr)
{
CHIP_ERROR err = endPoint->Receive(std::move(pBuf));
VerifyOrReturnError(err == CHIP_NO_ERROR, false,
ChipLogError(Ble, "Receive failed, err = %" CHIP_ERROR_FORMAT, err.Format()));
}
else
{
ChipLogError(Ble, "ble write rcvd on unknown char");
CHIP_ERROR err = HandleBleTransportConnectionInitiated(connObj, std::move(pBuf));
VerifyOrReturnError(err == CHIP_NO_ERROR, false,
ChipLogError(Ble, "Handle new BLE connection failed, err = %" CHIP_ERROR_FORMAT, err.Format()));
}

return true;
Expand All @@ -530,217 +511,120 @@ bool BleLayer::HandleWriteReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleU
bool BleLayer::HandleIndicationReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId,
PacketBufferHandle && pBuf)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Indication received on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId), false, ChipLogError(Ble, "Indication received on unknown char"));
VerifyOrReturnError(!pBuf.IsNull(), false, ChipLogError(Ble, "Indication received null buffer"));

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId))
{
if (pBuf.IsNull())
{
ChipLogError(Ble, "rcvd null ble indication");
return true;
}

// find matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
// Find matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturnError(endPoint != nullptr, false, ChipLogDetail(Ble, "No endpoint for received indication"));

if (endPoint != nullptr)
{
CHIP_ERROR status = endPoint->Receive(std::move(pBuf));
if (status != CHIP_NO_ERROR)
{
ChipLogError(Ble, "BLEEndPoint rcv failed, err = %" CHIP_ERROR_FORMAT, status.Format());
}
}
else
{
ChipLogDetail(Ble, "no endpoint for rcvd indication");
}
}
else
{
ChipLogError(Ble, "ble ind rcvd on unknown char");
}
CHIP_ERROR err = endPoint->Receive(std::move(pBuf));
VerifyOrReturnError(err == CHIP_NO_ERROR, false, ChipLogError(Ble, "Receive failed, err = %" CHIP_ERROR_FORMAT, err.Format()));

return true;
}

bool BleLayer::HandleWriteConfirmation(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}

if (UUIDsMatch(&CHIP_BLE_CHAR_1_ID, charId))
{
HandleAckReceived(connObj);
}
else
{
ChipLogError(Ble, "ble write con rcvd on unknown char");
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Write confirmation on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_1_ID, charId), false, ChipLogError(Ble, "Write confirmation on unknown char"));

HandleAckReceived(connObj);
return true;
}

bool BleLayer::HandleIndicationConfirmation(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId))
{
HandleAckReceived(connObj);
}
else
{
ChipLogError(Ble, "ble ind con rcvd on unknown char");
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Indication confirmation on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId), false,
ChipLogError(Ble, "Indication confirmation on unknown char"));

HandleAckReceived(connObj);
return true;
}

void BleLayer::HandleAckReceived(BLE_CONNECTION_OBJECT connObj)
{
// find matching connection end point.
// Find matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturn(endPoint != nullptr, ChipLogDetail(Ble, "No endpoint for received ack"));

if (endPoint != nullptr)
{
CHIP_ERROR status = endPoint->HandleGattSendConfirmationReceived();

if (status != CHIP_NO_ERROR)
{
ChipLogError(Ble, "endpoint conf recvd failed, err = %" CHIP_ERROR_FORMAT, status.Format());
}
}
else
{
ChipLogError(Ble, "no endpoint for BLE sent data ack");
}
CHIP_ERROR err = endPoint->HandleGattSendConfirmationReceived();
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(Ble, "Send ack confirmation failed, err = %" CHIP_ERROR_FORMAT, err.Format()));
}

bool BleLayer::HandleSubscribeReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Subscribe received on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId), false,
ChipLogError(Ble, "Subscribe received on unknown char"));

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId))
{
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);

if (endPoint != nullptr)
{
endPoint->HandleSubscribeReceived();
}
else
{
ChipLogError(Ble, "no endpoint for sub recvd");
}
}
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturnError(endPoint != nullptr, false, ChipLogDetail(Ble, "No endpoint for received subscribe"));

endPoint->HandleSubscribeReceived();
return true;
}

bool BleLayer::HandleSubscribeComplete(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Subscribe complete on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId), false,
ChipLogError(Ble, "Subscribe complete on unknown char"));

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId))
{
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);

if (endPoint != nullptr)
{
endPoint->HandleSubscribeComplete();
}
else
{
ChipLogError(Ble, "no endpoint for sub complete");
}
}
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturnError(endPoint != nullptr, false, ChipLogDetail(Ble, "No endpoint for subscribe complete"));

endPoint->HandleSubscribeComplete();
return true;
}

bool BleLayer::HandleUnsubscribeReceived(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Unsubscribe received on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId), false,
ChipLogError(Ble, "Unsubscribe received on unknown char"));

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId))
{
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);

if (endPoint != nullptr)
{
endPoint->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_CENTRAL_UNSUBSCRIBED);
}
else
{
ChipLogError(Ble, "no endpoint for unsub recvd");
}
}
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturnError(endPoint != nullptr, false, ChipLogDetail(Ble, "No endpoint for unsubscribe received"));

endPoint->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_CENTRAL_UNSUBSCRIBED);
return true;
}

bool BleLayer::HandleUnsubscribeComplete(BLE_CONNECTION_OBJECT connObj, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
if (!UUIDsMatch(&CHIP_BLE_SVC_ID, svcId))
{
return false;
}
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_SVC_ID, svcId), false, ChipLogError(Ble, "Unsubscribe complete on unknown svc"));
VerifyOrReturnError(UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId), false,
ChipLogError(Ble, "Unsubscribe complete on unknown char"));

if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId))
{
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);

if (endPoint != nullptr)
{
endPoint->HandleUnsubscribeComplete();
}
else
{
ChipLogError(Ble, "no endpoint for unsub complete");
}
}
// Find end point already associated with BLE connection, if any.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturnError(endPoint != nullptr, false, ChipLogDetail(Ble, "No endpoint for unsubscribe complete"));

endPoint->HandleUnsubscribeComplete();
return true;
}

void BleLayer::HandleConnectionError(BLE_CONNECTION_OBJECT connObj, CHIP_ERROR err)
{
// BLE connection has failed somehow, we must find and abort matching connection end point.
BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj);
VerifyOrReturn(endPoint != nullptr, ChipLogDetail(Ble, "No endpoint for connection error"));

if (endPoint != nullptr)
if (err == BLE_ERROR_GATT_UNSUBSCRIBE_FAILED && endPoint->IsUnsubscribePending())
{
if (err == BLE_ERROR_GATT_UNSUBSCRIBE_FAILED && endPoint->IsUnsubscribePending())
{
// If end point was already closed and just waiting for unsubscribe to complete, free it. Call to Free()
// stops unsubscribe timer.
endPoint->Free();
}
else
{
endPoint->DoClose(kBleCloseFlag_AbortTransmission, err);
}
// If end point was already closed and just waiting for unsubscribe to complete, free it. Call to Free()
// stops unsubscribe timer.
endPoint->Free();
}
else
{
endPoint->DoClose(kBleCloseFlag_AbortTransmission, err);
}
}

Expand Down
1 change: 0 additions & 1 deletion src/ble/BleLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,6 @@ class DLL_EXPORT BleLayer

// Private functions:
void HandleAckReceived(BLE_CONNECTION_OBJECT connObj);
void DriveSending();
CHIP_ERROR HandleBleTransportConnectionInitiated(BLE_CONNECTION_OBJECT connObj, System::PacketBufferHandle && pBuf);

static BleTransportProtocolVersion GetHighestSupportedProtocolVersion(const BleTransportCapabilitiesRequestMessage & reqMsg);
Expand Down
6 changes: 5 additions & 1 deletion src/ble/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ chip_test_suite("tests") {

test_sources = [
"TestBleErrorStr.cpp",
"TestBleLayer.cpp",
"TestBleUUID.cpp",
"TestBtpEngine.cpp",
]

cflags = [ "-Wconversion" ]

public_deps = [ "${chip_root}/src/ble" ]
public_deps = [
"${chip_root}/src/ble",
"${chip_root}/src/platform",
]
}
Loading

0 comments on commit f075b9b

Please sign in to comment.