Skip to content

Commit ba640aa

Browse files
[Linux] Verify BLE service before reporting new connection (#33893)
* Simplify logic in event posting helpers * [Linux] Fix discovery of C3 characteristic * [Linux] Check for spec-compliant CHIPoBLE service * Update name convention * Use C++ boolean type * Simplify memory management * Verify characteristic flags * C2 should have indication property set only * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent f91c661 commit ba640aa

File tree

6 files changed

+100
-114
lines changed

6 files changed

+100
-114
lines changed

src/app/tests/suites/certification/Test_TC_CNET_4_2.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ tests:
5656
[1698660637.937911][6429:6431] CHIP:IN: Clearing BLE pending packets.
5757
[1698660637.938582][6429:6431] CHIP:BLE: Auto-closing end point's BLE connection.
5858
[1698660637.938645][6429:6431] CHIP:DL: Closing BLE GATT connection (con 0xffff9c034bb0)
59-
[1698660637.938805][6429:6430] CHIP:DL: BluezDisconnect peer=F7:D4:24:D2:4A:1F
59+
[1698660637.938805][6429:6430] CHIP:DL: Close BLE connection: peer=F7:D4:24:D2:4A:1F
6060
[1698660638.365208][6429:6431] CHIP:IN: SecureSession[0xffff9400f900]: MarkForEviction Type:1 LSID:62220
6161
[1698660638.365311][6429:6431] CHIP:SC: SecureSession[0xffff9400f900, LSID:62220]: State change 'kActive' --> 'kPendingEviction'
6262
[1698660638.365440][6429:6431] CHIP:IN: SecureSession[0xffff9400f900]: Released - Type:1 LSID:62220

src/platform/Linux/BLEManagerImpl.cpp

+17-39
Original file line numberDiff line numberDiff line change
@@ -476,74 +476,52 @@ void BLEManagerImpl::HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool
476476

477477
void BLEManagerImpl::HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
478478
{
479-
CHIP_ERROR err = CHIP_NO_ERROR;
480-
System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(value, len);
479+
System::PacketBufferHandle buf(System::PacketBufferHandle::NewWithData(value, len));
480+
VerifyOrReturn(!buf.IsNull(), ChipLogError(DeviceLayer, "Failed to allocate packet buffer in %s", __func__));
481481

482482
ChipLogDetail(DeviceLayer, "Indication received, conn = %p", conId);
483483

484484
ChipDeviceEvent event{ .Type = DeviceEventType::kPlatformLinuxBLEIndicationReceived,
485-
.Platform = { .BLEIndicationReceived = { .mConnection = conId } } };
486-
487-
VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
488-
489-
event.Platform.BLEIndicationReceived.mData = std::move(buf).UnsafeRelease();
485+
.Platform = {
486+
.BLEIndicationReceived = { .mConnection = conId, .mData = std::move(buf).UnsafeRelease() } } };
490487
PlatformMgr().PostEventOrDie(&event);
491-
492-
exit:
493-
if (err != CHIP_NO_ERROR)
494-
ChipLogError(DeviceLayer, "HandleTXCharChanged() failed: %s", ErrorStr(err));
495488
}
496489

497490
void BLEManagerImpl::HandleRXCharWrite(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
498491
{
499-
CHIP_ERROR err = CHIP_NO_ERROR;
500-
System::PacketBufferHandle buf;
501-
502492
// Copy the data to a packet buffer.
503-
buf = System::PacketBufferHandle::NewWithData(value, len);
504-
VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
493+
System::PacketBufferHandle buf(System::PacketBufferHandle::NewWithData(value, len));
494+
VerifyOrReturn(!buf.IsNull(), ChipLogError(DeviceLayer, "Failed to allocate packet buffer in %s", __func__));
505495

506-
// Post an event to the Chip queue to deliver the data into the Chip stack.
507-
{
508-
ChipLogProgress(Ble, "Write request received debug %p", conId);
509-
ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoBLEWriteReceived,
510-
.CHIPoBLEWriteReceived = { .ConId = conId, .Data = std::move(buf).UnsafeRelease() } };
511-
PlatformMgr().PostEventOrDie(&event);
512-
}
496+
ChipLogProgress(Ble, "Write request received, conn = %p", conId);
513497

514-
exit:
515-
if (err != CHIP_NO_ERROR)
516-
{
517-
ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
518-
}
498+
// Post an event to the Chip queue to deliver the data into the Chip stack.
499+
ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoBLEWriteReceived,
500+
.CHIPoBLEWriteReceived = { .ConId = conId, .Data = std::move(buf).UnsafeRelease() } };
501+
PlatformMgr().PostEventOrDie(&event);
519502
}
520503

521-
void BLEManagerImpl::CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT conId)
504+
void BLEManagerImpl::HandleConnectionClosed(BLE_CONNECTION_OBJECT conId)
522505
{
523-
ChipLogProgress(DeviceLayer, "Bluez notify CHIPoBluez connection disconnected");
524-
525506
// If this was a CHIPoBLE connection, post an event to deliver a connection error to the CHIPoBLE layer.
526-
{
527-
ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoBLEConnectionError,
528-
.CHIPoBLEConnectionError = { .ConId = conId, .Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED } };
529-
PlatformMgr().PostEventOrDie(&event);
530-
}
507+
ChipDeviceEvent event{ .Type = DeviceEventType::kCHIPoBLEConnectionError,
508+
.CHIPoBLEConnectionError = { .ConId = conId, .Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED } };
509+
PlatformMgr().PostEventOrDie(&event);
531510
}
532511

533512
void BLEManagerImpl::HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT conId)
534513
{
535514
VerifyOrReturn(conId != BLE_CONNECTION_UNINITIALIZED,
536515
ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
537516

517+
ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", conId->IsNotifyAcquired() ? "subscribe" : "unsubscribe");
518+
538519
// Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on
539520
// whether the client is enabling or disabling indications.
540521
ChipDeviceEvent event{ .Type = conId->IsNotifyAcquired() ? static_cast<uint16_t>(DeviceEventType::kCHIPoBLESubscribe)
541522
: static_cast<uint16_t>(DeviceEventType::kCHIPoBLEUnsubscribe),
542523
.CHIPoBLESubscribe = { .ConId = conId } };
543524
PlatformMgr().PostEventOrDie(&event);
544-
545-
ChipLogProgress(DeviceLayer, "CHIPoBLE %s received",
546-
(event.Type == DeviceEventType::kCHIPoBLESubscribe) ? "subscribe" : "unsubscribe");
547525
}
548526

549527
void BLEManagerImpl::HandleTXComplete(BLE_CONNECTION_OBJECT conId)

src/platform/Linux/BLEManagerImpl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class BLEManagerImpl final : public BLEManager,
8787
static void HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool subscribed);
8888
static void HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len);
8989
static void HandleRXCharWrite(BLE_CONNECTION_OBJECT user_data, const uint8_t * value, size_t len);
90-
static void CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT user_data);
90+
static void HandleConnectionClosed(BLE_CONNECTION_OBJECT user_data);
9191
static void HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT user_data);
9292
static void HandleTXComplete(BLE_CONNECTION_OBJECT user_data);
9393

src/platform/Linux/bluez/BluezConnection.cpp

+59-60
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <gio/gio.h>
2525
#include <glib.h>
2626

27+
#include <ble/Ble.h>
2728
#include <lib/support/CHIPMem.h>
2829
#include <lib/support/CodeUtils.h>
2930
#include <platform/ConnectivityManager.h>
@@ -42,29 +43,31 @@ namespace Internal {
4243

4344
namespace {
4445

45-
gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
46+
bool BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
4647
{
47-
const auto * servicePath = bluez_gatt_service1_get_device(aService);
48-
const auto * devicePath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(aDevice));
49-
return strcmp(servicePath, devicePath) == 0 ? TRUE : FALSE;
48+
auto servicePath = bluez_gatt_service1_get_device(aService);
49+
auto devicePath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(aDevice));
50+
return strcmp(servicePath, devicePath) == 0;
5051
}
5152

52-
gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
53+
bool BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
5354
{
54-
const auto * charPath = bluez_gatt_characteristic1_get_service(aChar);
55-
const auto * servicePath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(aService));
56-
ChipLogDetail(DeviceLayer, "Char %s on service %s", charPath, servicePath);
57-
return strcmp(charPath, servicePath) == 0 ? TRUE : FALSE;
55+
auto charPath = bluez_gatt_characteristic1_get_service(aChar);
56+
auto servicePath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(aService));
57+
return strcmp(charPath, servicePath) == 0;
5858
}
5959

60-
} // namespace
61-
62-
BluezConnection::BluezConnection(const BluezEndpoint & aEndpoint, BluezDevice1 & aDevice) :
63-
mDevice(reinterpret_cast<BluezDevice1 *>(g_object_ref(&aDevice)))
60+
bool BluezIsFlagOnChar(BluezGattCharacteristic1 * aChar, const char * flag)
6461
{
65-
Init(aEndpoint);
62+
auto charFlags = bluez_gatt_characteristic1_get_flags(aChar);
63+
for (size_t i = 0; charFlags[i] != nullptr; i++)
64+
if (strcmp(charFlags[i], flag) == 0)
65+
return true;
66+
return false;
6667
}
6768

69+
} // namespace
70+
6871
BluezConnection::IOChannel::~IOChannel()
6972
{
7073
if (mWatchSource != nullptr)
@@ -85,73 +88,69 @@ CHIP_ERROR BluezConnection::Init(const BluezEndpoint & aEndpoint)
8588
mService.reset(reinterpret_cast<BluezGattService1 *>(g_object_ref(aEndpoint.mService.get())));
8689
mC1.reset(reinterpret_cast<BluezGattCharacteristic1 *>(g_object_ref(aEndpoint.mC1.get())));
8790
mC2.reset(reinterpret_cast<BluezGattCharacteristic1 *>(g_object_ref(aEndpoint.mC2.get())));
91+
return CHIP_NO_ERROR;
8892
}
89-
else
93+
94+
for (BluezObject & object : aEndpoint.mObjectManager.GetObjects())
9095
{
91-
for (BluezObject & object : aEndpoint.mObjectManager.GetObjects())
96+
GAutoPtr<BluezGattService1> service(bluez_object_get_gatt_service1(&object));
97+
if (service && BluezIsServiceOnDevice(service.get(), mDevice.get()))
9298
{
93-
BluezGattService1 * service = bluez_object_get_gatt_service1(&object);
94-
if (service != nullptr)
99+
if (strcmp(bluez_gatt_service1_get_uuid(service.get()), Ble::CHIP_BLE_SERVICE_LONG_UUID_STR) == 0)
95100
{
96-
if ((BluezIsServiceOnDevice(service, mDevice.get())) == TRUE &&
97-
(strcmp(bluez_gatt_service1_get_uuid(service), Ble::CHIP_BLE_SERVICE_LONG_UUID_STR) == 0))
98-
{
99-
mService.reset(service);
100-
break;
101-
}
102-
g_object_unref(service);
101+
ChipLogDetail(DeviceLayer, "CHIP service found");
102+
mService.reset(service.release());
103+
break;
103104
}
104105
}
106+
}
105107

106-
VerifyOrExit(mService, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
108+
VerifyOrReturnError(
109+
mService, BLE_ERROR_NOT_CHIP_DEVICE,
110+
ChipLogError(DeviceLayer, "CHIP service (%s) not found on %s", Ble::CHIP_BLE_SERVICE_LONG_UUID_STR, GetPeerAddress()));
107111

108-
for (BluezObject & object : aEndpoint.mObjectManager.GetObjects())
112+
for (BluezObject & object : aEndpoint.mObjectManager.GetObjects())
113+
{
114+
GAutoPtr<BluezGattCharacteristic1> chr(bluez_object_get_gatt_characteristic1(&object));
115+
if (chr && BluezIsCharOnService(chr.get(), mService.get()))
109116
{
110-
BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(&object);
111-
if (char1 != nullptr)
117+
if (strcmp(bluez_gatt_characteristic1_get_uuid(chr.get()), Ble::CHIP_BLE_CHAR_1_UUID_STR) == 0 &&
118+
BluezIsFlagOnChar(chr.get(), "write"))
112119
{
113-
if ((BluezIsCharOnService(char1, mService.get()) == TRUE) &&
114-
(strcmp(bluez_gatt_characteristic1_get_uuid(char1), Ble::CHIP_BLE_CHAR_1_UUID_STR) == 0))
115-
{
116-
mC1.reset(char1);
117-
}
118-
else if ((BluezIsCharOnService(char1, mService.get()) == TRUE) &&
119-
(strcmp(bluez_gatt_characteristic1_get_uuid(char1), Ble::CHIP_BLE_CHAR_2_UUID_STR) == 0))
120-
{
121-
mC2.reset(char1);
122-
}
120+
ChipLogDetail(DeviceLayer, "Valid C1 characteristic found");
121+
mC1.reset(chr.release());
122+
}
123+
else if (strcmp(bluez_gatt_characteristic1_get_uuid(chr.get()), Ble::CHIP_BLE_CHAR_2_UUID_STR) == 0 &&
124+
BluezIsFlagOnChar(chr.get(), "indicate"))
125+
{
126+
ChipLogDetail(DeviceLayer, "Valid C2 characteristic found");
127+
mC2.reset(chr.release());
128+
}
123129
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
124-
else if ((BluezIsCharOnService(char1, mService.get()) == TRUE) &&
125-
(strcmp(bluez_gatt_characteristic1_get_uuid(char1), Ble::CHIP_BLE_CHAR_3_UUID_STR) == 0))
126-
{
127-
mC3.reset(char1);
128-
}
129-
#endif
130-
else
131-
{
132-
g_object_unref(char1);
133-
}
134-
if (mC1 && mC2)
135-
{
136-
break;
137-
}
130+
else if (strcmp(bluez_gatt_characteristic1_get_uuid(chr.get()), Ble::CHIP_BLE_CHAR_3_UUID_STR) == 0 &&
131+
BluezIsFlagOnChar(chr.get(), "read"))
132+
{
133+
ChipLogDetail(DeviceLayer, "Valid C3 characteristic found");
134+
mC3.reset(chr.release());
138135
}
136+
#endif
139137
}
140-
141-
VerifyOrExit(mC1, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
142-
VerifyOrExit(mC2, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
143138
}
144139

145-
exit:
140+
VerifyOrReturnError(mC1, BLE_ERROR_NOT_CHIP_DEVICE,
141+
ChipLogError(DeviceLayer, "No valid C1 (%s) on %s", Ble::CHIP_BLE_CHAR_1_UUID_STR, GetPeerAddress()));
142+
VerifyOrReturnError(mC2, BLE_ERROR_NOT_CHIP_DEVICE,
143+
ChipLogError(DeviceLayer, "No valid C2 (%s) on %s", Ble::CHIP_BLE_CHAR_2_UUID_STR, GetPeerAddress()));
144+
146145
return CHIP_NO_ERROR;
147146
}
148147

149-
CHIP_ERROR BluezConnection::BluezDisconnect(BluezConnection * conn)
148+
CHIP_ERROR BluezConnection::CloseConnectionImpl(BluezConnection * conn)
150149
{
151150
GAutoPtr<GError> error;
152151
gboolean success;
153152

154-
ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, conn->GetPeerAddress());
153+
ChipLogDetail(DeviceLayer, "Close BLE connection: peer=%s", conn->GetPeerAddress());
155154

156155
success = bluez_device1_call_disconnect_sync(conn->mDevice.get(), nullptr, &error.GetReceiver());
157156
VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
@@ -162,7 +161,7 @@ CHIP_ERROR BluezConnection::BluezDisconnect(BluezConnection * conn)
162161

163162
CHIP_ERROR BluezConnection::CloseConnection()
164163
{
165-
return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezDisconnect, this);
164+
return PlatformMgrImpl().GLibMatterContextInvokeSync(CloseConnectionImpl, this);
166165
}
167166

168167
const char * BluezConnection::GetPeerAddress() const

src/platform/Linux/bluez/BluezConnection.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ class BluezEndpoint;
3939
class BluezConnection
4040
{
4141
public:
42-
BluezConnection(const BluezEndpoint & aEndpoint, BluezDevice1 & aDevice);
42+
BluezConnection(BluezDevice1 & aDevice) : mDevice(reinterpret_cast<BluezDevice1 *>(g_object_ref(&aDevice))) {}
4343
~BluezConnection() = default;
4444

45+
CHIP_ERROR Init(const BluezEndpoint & aEndpoint);
46+
4547
const char * GetPeerAddress() const;
4648

4749
uint16_t GetMTU() const { return mMtu; }
@@ -97,9 +99,7 @@ class BluezConnection
9799
GAutoPtr<GVariant> mData;
98100
};
99101

100-
CHIP_ERROR Init(const BluezEndpoint & aEndpoint);
101-
102-
static CHIP_ERROR BluezDisconnect(BluezConnection * apConn);
102+
static CHIP_ERROR CloseConnectionImpl(BluezConnection * apConn);
103103

104104
static gboolean WriteHandlerCallback(GIOChannel * aChannel, GIOCondition aCond, BluezConnection * apConn);
105105
static gboolean NotifyHandlerCallback(GIOChannel * aChannel, GIOCondition aCond, BluezConnection * apConn);

src/platform/Linux/bluez/BluezEndpoint.cpp

+18-9
Original file line numberDiff line numberDiff line change
@@ -299,21 +299,21 @@ CHIP_ERROR BluezEndpoint::RegisterGattApplicationImpl()
299299
/// Update the table of open BLE connections whenever a new device is spotted or its attributes have changed.
300300
void BluezEndpoint::UpdateConnectionTable(BluezDevice1 & aDevice)
301301
{
302-
const char * objectPath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(&aDevice));
303-
BluezConnection * connection = GetBluezConnection(objectPath);
302+
const char * objectPath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(&aDevice));
303+
BluezConnection * conn = GetBluezConnection(objectPath);
304304

305-
if (connection != nullptr && !bluez_device1_get_connected(&aDevice))
305+
if (conn != nullptr && !bluez_device1_get_connected(&aDevice))
306306
{
307-
ChipLogDetail(DeviceLayer, "Bluez disconnected");
308-
BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection);
307+
ChipLogDetail(DeviceLayer, "BLE connection closed: conn=%p", conn);
308+
BLEManagerImpl::HandleConnectionClosed(conn);
309309
mConnMap.erase(objectPath);
310310
// TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources
311311
// after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone.
312-
chip::Platform::Delete(connection);
312+
chip::Platform::Delete(conn);
313313
return;
314314
}
315315

316-
if (connection == nullptr)
316+
if (conn == nullptr)
317317
{
318318
HandleNewDevice(aDevice);
319319
}
@@ -323,20 +323,29 @@ void BluezEndpoint::HandleNewDevice(BluezDevice1 & aDevice)
323323
{
324324
VerifyOrReturn(bluez_device1_get_connected(&aDevice));
325325
VerifyOrReturn(!mIsCentral || bluez_device1_get_services_resolved(&aDevice));
326+
CHIP_ERROR err;
326327

327328
const char * objectPath = g_dbus_proxy_get_object_path(reinterpret_cast<GDBusProxy *>(&aDevice));
328329
BluezConnection * conn = GetBluezConnection(objectPath);
329330
VerifyOrReturn(conn == nullptr,
330331
ChipLogError(DeviceLayer, "FAIL: Connection already tracked: conn=%p device=%s path=%s", conn,
331332
conn->GetPeerAddress(), objectPath));
332333

333-
conn = chip::Platform::New<BluezConnection>(*this, aDevice);
334+
conn = chip::Platform::New<BluezConnection>(aDevice);
335+
VerifyOrExit(conn != nullptr, err = CHIP_ERROR_NO_MEMORY);
336+
SuccessOrExit(err = conn->Init(*this));
337+
334338
mpPeerDevicePath = g_strdup(objectPath);
335339
mConnMap[mpPeerDevicePath] = conn;
336340

337341
ChipLogDetail(DeviceLayer, "New BLE connection: conn=%p device=%s path=%s", conn, conn->GetPeerAddress(), objectPath);
338342

339343
BLEManagerImpl::HandleNewConnection(conn);
344+
return;
345+
346+
exit:
347+
chip::Platform::Delete(conn);
348+
BLEManagerImpl::HandleConnectFailed(err);
340349
}
341350

342351
void BluezEndpoint::OnDeviceAdded(BluezDevice1 & device)
@@ -437,7 +446,7 @@ void BluezEndpoint::SetupGattService()
437446
{
438447

439448
static const char * const c1_flags[] = { "write", nullptr };
440-
static const char * const c2_flags[] = { "read", "indicate", nullptr };
449+
static const char * const c2_flags[] = { "indicate", nullptr };
441450
#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
442451
static const char * const c3_flags[] = { "read", nullptr };
443452
#endif

0 commit comments

Comments
 (0)