3 * Copyright (c) 2020-2021 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * Copyright (c) 2016-2019, The OpenThread Authors.
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. Neither the name of the copyright holder nor the
30 * names of its contributors may be used to endorse or promote products
31 * derived from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 * POSSIBILITY OF SUCH DAMAGE.
48 * Provides Bluez dbus implementatioon for BLE
51 #include <ble/BleUUID.h>
52 #include <ble/CHIPBleServiceData.h>
53 #include <platform/CHIPDeviceLayer.h>
54 #include <protocols/Protocols.h>
55 #include <setup_payload/AdditionalDataPayloadGenerator.h>
56 #include <support/BitFlags.h>
57 #include <support/CHIPMem.h>
58 #include <support/CHIPMemString.h>
60 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
63 #include <gio/gunixfdlist.h>
70 #include <platform/Linux/BLEManagerImpl.h>
71 #include <support/CodeUtils.h>
72 #include <system/TLVPacketBufferBackingStore.h>
74 #include "BluezObjectIterator.h"
75 #include "BluezObjectList.h"
80 using namespace chip::Protocols;
81 using chip::Platform::CopyString;
84 namespace DeviceLayer {
87 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
91 class BluezEndpointObjectList : public BluezObjectList
94 explicit BluezEndpointObjectList(BluezEndpoint * apEndpoint)
96 VerifyOrReturn(apEndpoint != nullptr, ChipLogError(DeviceLayer, "apEndpoint is NULL in %s", __func__));
97 Initialize(apEndpoint->mpObjMgr);
103 static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
105 bool isSuccess = false;
106 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
107 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
108 VerifyOrExit(aAdv != nullptr, ChipLogError(DeviceLayer, "BluezLEAdvertisement1 is NULL in %s", __func__));
109 ChipLogDetail(DeviceLayer, "Release adv object in %s", __func__);
111 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
112 endpoint->mIsAdvertising = false;
116 return isSuccess ? TRUE : FALSE;
119 static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
121 BluezLEAdvertisement1 * adv = nullptr;
122 BluezObjectSkeleton * object;
123 GVariant * serviceData;
124 GVariant * serviceUUID;
126 GVariantBuilder serviceDataBuilder;
127 GVariantBuilder serviceUUIDsBuilder;
130 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
131 if (apEndpoint->mpAdvPath == nullptr)
132 apEndpoint->mpAdvPath = g_strdup_printf("%s/advertising", apEndpoint->mpRootPath);
134 ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
135 object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
137 adv = bluez_leadvertisement1_skeleton_new();
139 g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
140 g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
142 g_variant_builder_add(&serviceDataBuilder, "{sv}", apEndpoint->mpAdvertisingUUID,
143 g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &apEndpoint->mDeviceIdInfo,
144 sizeof(apEndpoint->mDeviceIdInfo), sizeof(uint8_t)));
145 g_variant_builder_add(&serviceUUIDsBuilder, "s", apEndpoint->mpAdvertisingUUID);
147 if (apEndpoint->mpAdapterName != nullptr)
148 localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
150 localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
152 serviceData = g_variant_builder_end(&serviceDataBuilder);
153 serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
155 debugStr = g_variant_print(serviceData, TRUE);
156 ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
159 bluez_leadvertisement1_set_type_(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_CONNECTABLE) ? "peripheral" : "broadcast");
160 // empty manufacturer data
161 // empty solicit UUIDs
162 bluez_leadvertisement1_set_service_data(adv, serviceData);
165 // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
166 // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
167 // and the flag is necessary to force using LE transport.
168 bluez_leadvertisement1_set_discoverable(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE) ? TRUE : FALSE);
169 if (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE)
170 bluez_leadvertisement1_set_discoverable_timeout(adv, UINT16_MAX);
172 // advertising name corresponding to the PID and object path, for debug purposes
173 bluez_leadvertisement1_set_local_name(adv, localName);
174 bluez_leadvertisement1_set_service_uuids(adv, serviceUUID);
176 // 0xffff means no appearance
177 bluez_leadvertisement1_set_appearance(adv, 0xffff);
179 bluez_leadvertisement1_set_duration(adv, apEndpoint->mDuration);
180 // empty duration, we don't have a clear notion what it would mean to timeslice between toble and anyone else
181 bluez_leadvertisement1_set_timeout(adv, 0);
182 // empty secondary channel for now
184 bluez_object_skeleton_set_leadvertisement1(object, adv);
185 g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
187 g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
188 g_object_unref(object);
190 BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
196 static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
198 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
199 GError * error = nullptr;
200 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
201 gboolean success = FALSE;
203 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
205 success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
206 if (success == FALSE)
208 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
210 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
212 endpoint->mIsAdvertising = true;
214 ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
217 BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
218 if (error != nullptr)
222 static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
224 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
225 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
226 GError * error = nullptr;
227 gboolean success = FALSE;
229 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
231 success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
233 if (success == FALSE)
235 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
239 endpoint->mIsAdvertising = false;
242 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
244 ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
247 BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
248 if (error != nullptr)
252 static gboolean BluezAdvSetup(BluezEndpoint * endpoint)
254 BluezLEAdvertisement1 * adv;
256 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
257 VerifyOrExit(endpoint->mIsAdvertising == FALSE, ChipLogError(DeviceLayer, "FAIL: Advertising already enabled in %s", __func__));
258 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
260 adv = BluezAdvertisingCreate(endpoint);
261 VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
264 return G_SOURCE_REMOVE;
267 static gboolean BluezAdvStart(BluezEndpoint * endpoint)
269 GDBusObject * adapter;
270 BluezLEAdvertisingManager1 * advMgr = nullptr;
271 GVariantBuilder optionsBuilder;
274 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
275 VerifyOrExit(!endpoint->mIsAdvertising,
276 ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled in %s", __func__));
277 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
279 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
280 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
282 advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
283 VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
285 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
286 options = g_variant_builder_end(&optionsBuilder);
288 bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
292 return G_SOURCE_REMOVE;
295 static gboolean BluezAdvStop(BluezEndpoint * endpoint)
297 GDBusObject * adapter;
298 BluezLEAdvertisingManager1 * advMgr = nullptr;
300 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
301 VerifyOrExit(endpoint->mIsAdvertising,
302 ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
303 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
305 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
306 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
308 advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
309 VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
311 bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, endpoint);
314 return G_SOURCE_REMOVE;
317 static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
321 ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
322 val = bluez_gatt_characteristic1_get_value(aChar);
323 bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
327 #if CHIP_BLUEZ_CHAR_WRITE_VALUE
328 static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
329 GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
331 const uint8_t * tmpBuf;
334 bool isSuccess = false;
335 BluezConnection * conn = NULL;
337 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
338 VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
340 VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
342 conn = GetBluezConnectionViaDevice(endpoint);
343 VerifyOrExit(conn != NULL,
344 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
346 bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
348 tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
349 buf = (uint8_t *) (g_memdup(tmpBuf, len));
351 BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
352 bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
356 return isSuccess ? TRUE : FALSE;
360 static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
361 GVariant * aValue, GVariant * aOptions, gpointer apClosure)
363 ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
364 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
365 "Write for characteristic is unsupported");
369 static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
375 bool isSuccess = false;
377 BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
379 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
381 VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__));
382 VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__));
383 VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__));
385 ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
387 buf = static_cast<gchar *>(g_malloc(conn->mMtu));
388 fd = g_io_channel_unix_get_fd(aChannel);
390 len = read(fd, buf, conn->mMtu);
392 VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
394 // Casting len to size_t is safe, since we ensured that it's not negative.
395 newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
397 bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
398 BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
402 return isSuccess ? TRUE : FALSE;
405 static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
407 GUnixFDList * fd_list = g_unix_fd_list_new();
410 index = g_unix_fd_list_append(fd_list, fd, nullptr);
412 g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
416 static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
418 return G_SOURCE_REMOVE;
421 static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
422 GVariant * aOptions, gpointer apEndpoint)
424 int fds[2] = { -1, -1 };
425 GIOChannel * channel;
427 GVariantDict options;
428 bool isSuccess = false;
429 BluezConnection * conn = nullptr;
431 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
432 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
434 conn = GetBluezConnectionViaDevice(endpoint);
435 VerifyOrExit(conn != nullptr,
436 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
438 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
440 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
442 errStr = strerror(errno);
443 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
444 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
445 SuccessOrExit(false);
448 g_variant_dict_init(&options, aOptions);
449 if (g_variant_dict_contains(&options, "mtu") == TRUE)
451 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
452 conn->mMtu = g_variant_get_uint16(v);
456 ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
457 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
458 SuccessOrExit(false);
461 channel = g_io_channel_unix_new(fds[0]);
462 g_io_channel_set_encoding(channel, nullptr, nullptr);
463 g_io_channel_set_close_on_unref(channel, TRUE);
464 g_io_channel_set_buffered(channel, FALSE);
466 conn->mC1Channel.mpChannel = channel;
467 conn->mC1Channel.mWatch = g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL),
468 BluezCharacteristicWriteFD, conn);
470 bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
472 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
477 return isSuccess ? TRUE : FALSE;
480 static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
483 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWriteError is called");
484 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
485 "AcquireWrite for characteristic is unsupported");
489 static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
490 GVariant * aOptions, gpointer apEndpoint)
492 int fds[2] = { -1, -1 };
493 GIOChannel * channel;
495 GVariantDict options;
496 BluezConnection * conn = nullptr;
497 bool isSuccess = false;
499 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
500 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
502 conn = GetBluezConnectionViaDevice(endpoint);
503 VerifyOrExit(conn != nullptr,
504 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
506 g_variant_dict_init(&options, aOptions);
507 if ((g_variant_dict_contains(&options, "mtu") == TRUE))
509 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
510 conn->mMtu = g_variant_get_uint16(v);
513 if (bluez_gatt_characteristic1_get_notifying(aChar))
515 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
517 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
519 errStr = strerror(errno);
520 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
521 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
522 SuccessOrExit(false);
524 channel = g_io_channel_unix_new(fds[0]);
525 g_io_channel_set_encoding(channel, nullptr, nullptr);
526 g_io_channel_set_close_on_unref(channel, TRUE);
527 g_io_channel_set_buffered(channel, FALSE);
528 conn->mC2Channel.mpChannel = channel;
529 conn->mC2Channel.mWatch =
530 g_io_add_watch_full(channel, G_PRIORITY_DEFAULT_IDLE, static_cast<GIOCondition>(G_IO_HUP | G_IO_ERR | G_IO_NVAL),
531 bluezCharacteristicDestroyFD, conn, nullptr);
533 bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
535 // same reply as for AcquireWrite
536 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
539 conn->mIsNotify = true;
540 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
544 return isSuccess ? TRUE : FALSE;
547 static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
550 ChipLogDetail(DeviceLayer, "TRACE: AcquireNotify is called");
551 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
552 "AcquireNotify for characteristic is unsupported");
556 static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
559 bool isSuccess = false;
560 BluezConnection * conn = nullptr;
562 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
563 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
565 conn = GetBluezConnectionViaDevice(endpoint);
566 VerifyOrExit(conn != nullptr,
567 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
569 if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
571 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
575 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
576 bluez_gatt_characteristic1_set_notifying(aChar, TRUE);
577 conn->mIsNotify = true;
578 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
583 return isSuccess ? TRUE : FALSE;
586 static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
588 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
589 "Subscribing to characteristic is unsupported");
593 static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
596 bool isSuccess = false;
597 BluezConnection * conn = nullptr;
599 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
600 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
602 conn = GetBluezConnectionViaDevice(endpoint);
603 VerifyOrExit(conn != nullptr,
604 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
606 if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
608 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
612 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
613 bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
615 conn->mIsNotify = false;
620 return isSuccess ? TRUE : FALSE;
623 static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
626 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
627 BluezConnection * conn = GetBluezConnectionViaDevice(endpoint);
629 ChipLogDetail(Ble, "Indication confirmation, %p", conn);
630 BLEManagerImpl::HandleTXComplete(conn);
635 static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
637 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
638 "Unsubscribing from characteristic is unsupported");
642 static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
644 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
648 static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
650 return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
653 static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
655 return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
659 static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
661 ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar));
662 ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)));
663 return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE
667 static void BluezConnectionInit(BluezConnection * apConn)
669 // populate the service and the characteristics
670 GList * objects = nullptr;
672 BluezEndpoint * endpoint = nullptr;
674 VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
676 endpoint = apConn->mpEndpoint;
677 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
679 if (!endpoint->mIsCentral)
681 apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService));
682 apConn->mpC1 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1));
683 apConn->mpC2 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2));
687 objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
689 for (l = objects; l != nullptr; l = l->next)
691 BluezObject * object = BLUEZ_OBJECT(l->data);
692 BluezGattService1 * service = bluez_object_get_gatt_service1(object);
694 if (service != nullptr)
696 if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
697 (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
699 apConn->mpService = service;
702 g_object_unref(service);
706 VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
708 for (l = objects; l != nullptr; l = l->next)
710 BluezObject * object = BLUEZ_OBJECT(l->data);
711 BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
713 if (char1 != nullptr)
715 if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
716 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
718 apConn->mpC1 = char1;
720 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
721 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
723 apConn->mpC2 = char1;
725 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
726 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0))
728 apConn->mpC3 = char1;
732 g_object_unref(char1);
734 if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
741 VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
742 VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
746 if (objects != nullptr)
747 g_list_free_full(objects, g_object_unref);
750 static void BluezOTConnectionDestroy(BluezConnection * aConn)
755 g_object_unref(aConn->mpDevice);
756 if (aConn->mpService)
757 g_object_unref(aConn->mpService);
759 g_object_unref(aConn->mpC1);
761 g_object_unref(aConn->mpC2);
762 if (aConn->mpPeerAddress)
763 g_free(aConn->mpPeerAddress);
764 if (aConn->mC1Channel.mWatch > 0)
765 g_source_remove(aConn->mC1Channel.mWatch);
766 if (aConn->mC1Channel.mpChannel)
767 g_io_channel_unref(aConn->mC1Channel.mpChannel);
768 if (aConn->mC2Channel.mWatch > 0)
769 g_source_remove(aConn->mC2Channel.mWatch);
770 if (aConn->mC2Channel.mpChannel)
771 g_io_channel_unref(aConn->mC2Channel.mpChannel);
777 static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
778 const char * aUUID, GDBusObjectManagerServer * aRoot)
780 char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
781 char * charPath = g_strdup_printf("%s/%s", servicePath, aCharName);
782 BluezObjectSkeleton * object;
783 BluezGattCharacteristic1 * characteristic;
785 ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
786 object = bluez_object_skeleton_new(charPath);
788 characteristic = bluez_gatt_characteristic1_skeleton_new();
789 bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
790 bluez_gatt_characteristic1_set_service(characteristic, servicePath);
792 bluez_object_skeleton_set_gatt_characteristic1(object, characteristic);
793 g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
794 g_object_unref(object);
796 return characteristic;
799 static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
801 GError * error = nullptr;
802 BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
804 gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
806 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
808 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
809 ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
812 if (error != nullptr)
814 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
819 gboolean BluezPeripheralRegisterApp(BluezEndpoint * endpoint)
821 GDBusObject * adapter;
822 BluezGattManager1 * gattMgr;
823 GVariantBuilder optionsBuilder;
826 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
828 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
829 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
831 gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
832 VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
834 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
835 options = g_variant_builder_end(&optionsBuilder);
837 bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
841 return G_SOURCE_REMOVE;
844 /// Update the table of open BLE connections whevener a new device is spotted or its attributes have changed.
845 static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndpoint)
847 const gchar * objectPath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
848 BluezConnection * connection = static_cast<BluezConnection *>(g_hash_table_lookup(aEndpoint.mpConnMap, objectPath));
850 if (connection != nullptr && !bluez_device1_get_connected(apDevice))
852 ChipLogDetail(DeviceLayer, "Bluez disconnected");
853 BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection);
854 // TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources
855 // after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone.
856 BluezOTConnectionDestroy(connection);
857 g_hash_table_remove(aEndpoint.mpConnMap, objectPath);
861 if (connection == nullptr && !bluez_device1_get_connected(apDevice) && aEndpoint.mIsCentral)
866 if (connection == nullptr && bluez_device1_get_connected(apDevice) &&
867 (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice)))
869 connection = g_new0(BluezConnection, 1);
870 connection->mpPeerAddress = g_strdup(bluez_device1_get_address(apDevice));
871 connection->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(apDevice));
872 connection->mpEndpoint = &aEndpoint;
873 BluezConnectionInit(connection);
874 aEndpoint.mpPeerDevicePath = g_strdup(objectPath);
875 g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection);
877 ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
878 aEndpoint.mpPeerDevicePath);
880 BLEManagerImpl::HandleNewConnection(connection);
884 static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
885 GDBusProxy * aInterface, GVariant * aChangedProperties,
886 const gchar * const * aInvalidatedProps, gpointer apClosure)
888 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
889 VerifyOrReturn(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
890 VerifyOrReturn(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
891 VerifyOrReturn(strcmp(g_dbus_proxy_get_interface_name(aInterface), DEVICE_INTERFACE) == 0, );
893 BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
894 VerifyOrReturn(BluezIsDeviceOnAdapter(device, endpoint->mpAdapter));
896 UpdateConnectionTable(device, *endpoint);
899 static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
901 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
902 if (apEndpoint->mIsCentral)
907 // We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
908 // When a device is connected for first time, this function will be triggerred.
909 // The future connections for the same device will trigger ``Connect'' property change.
910 // TODO: Factor common code in the two function.
911 BluezConnection * conn;
912 VerifyOrExit(bluez_device1_get_connected(device), ChipLogError(DeviceLayer, "FAIL: device is not connected"));
914 conn = static_cast<BluezConnection *>(
915 g_hash_table_lookup(apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
916 VerifyOrExit(conn == nullptr,
917 ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x new device: %s", conn,
918 g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
920 conn = g_new0(BluezConnection, 1);
921 conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
922 conn->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(device));
923 conn->mpEndpoint = apEndpoint;
924 BluezConnectionInit(conn);
925 apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
926 ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
927 g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
933 static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, BluezEndpoint * endpoint)
935 // TODO: right now we do not handle addition/removal of adapters
936 // Primary focus here is to handle addition of a device
937 BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(aObject));
938 if (device == nullptr)
943 if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
945 BluezHandleNewDevice(device, endpoint);
948 g_object_unref(device);
951 static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
953 // TODO: for Device1, lookup connection, and call otPlatTobleHandleDisconnected
954 // for Adapter1: unclear, crash if this pertains to our adapter? at least null out the endpoint->mpAdapter.
955 // for Characteristic1, or GattService -- handle here via calling otPlatTobleHandleDisconnected, or ignore.
958 static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
960 BluezObjectSkeleton * object;
961 BluezGattService1 * service;
962 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
964 endpoint->mpServicePath = g_strdup_printf("%s/service", endpoint->mpRootPath);
965 ChipLogDetail(DeviceLayer, "CREATE service object at %s", endpoint->mpServicePath);
966 object = bluez_object_skeleton_new(endpoint->mpServicePath);
968 service = bluez_gatt_service1_skeleton_new();
969 bluez_gatt_service1_set_uuid(service, "0xFEAF");
970 // device is only valid for remote services
971 bluez_gatt_service1_set_primary(service, TRUE);
973 // includes -- unclear whether required. Might be filled in later
974 bluez_object_skeleton_set_gatt_service1(object, service);
975 g_dbus_object_manager_server_export(endpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
976 g_object_unref(object);
981 static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
983 GList * objects = nullptr;
985 char * expectedPath = nullptr;
987 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
989 expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mAdapterId);
990 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
992 for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
994 BluezObject * object = BLUEZ_OBJECT(l->data);
997 interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
999 for (ll = interfaces; ll != nullptr; ll = ll->next)
1001 if (BLUEZ_IS_ADAPTER1(ll->data))
1002 { // we found the adapter
1003 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(ll->data);
1004 char * addr = const_cast<char *>(bluez_adapter1_get_address(adapter));
1005 if (apEndpoint->mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid
1007 if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
1009 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1014 if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
1016 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1021 g_list_free_full(interfaces, g_object_unref);
1023 VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
1024 bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
1026 // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
1027 // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
1028 // and the flag is necessary to force using LE transport.
1029 bluez_adapter1_set_discoverable(apEndpoint->mpAdapter, FALSE);
1032 g_list_free_full(objects, g_object_unref);
1033 g_free(expectedPath);
1036 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
1038 BluezConnection * retval =
1039 static_cast<BluezConnection *>(g_hash_table_lookup(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath));
1040 // ChipLogError(DeviceLayer, "acquire connection object %p in (%s)", retval, __func__);
1044 #if CHIP_BLUEZ_CENTRAL_SUPPORT
1045 static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
1046 BluezEndpoint * apEndpoint)
1048 BluezConnection * retval = NULL;
1049 const gchar * path = NULL;
1050 GVariantDict options;
1053 VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1054 VerifyOrExit(apEndpoint->mIsCentral, );
1056 /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
1057 * peer device in call params so we need look this up ourselves.
1059 if (aOptions == NULL)
1065 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1066 for (l = objects; l != NULL; l = l->next)
1068 BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
1071 if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
1073 for (ll = objects; ll != NULL; ll = ll->next)
1075 BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
1076 if (service != NULL)
1078 if (BluezIsServiceOnDevice(service, device))
1080 if (BluezIsCharOnService(aChar, service))
1082 retval = (BluezConnection *) g_hash_table_lookup(
1083 apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1086 g_object_unref(service);
1092 g_object_unref(device);
1098 g_list_free_full(objects, g_object_unref);
1102 g_variant_dict_init(&options, aOptions);
1104 v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
1106 VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
1108 path = g_variant_get_string(v, NULL);
1110 retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
1116 #endif // CHIP_BLUEZ_CENTRAL_SUPPORT
1118 void EndpointCleanup(BluezEndpoint * apEndpoint)
1120 if (apEndpoint != nullptr)
1122 if (apEndpoint->mpOwningName != nullptr)
1124 g_free(apEndpoint->mpOwningName);
1125 apEndpoint->mpOwningName = nullptr;
1127 if (apEndpoint->mpAdapterName != nullptr)
1129 g_free(apEndpoint->mpAdapterName);
1130 apEndpoint->mpAdapterName = nullptr;
1132 if (apEndpoint->mpAdapterAddr != nullptr)
1134 g_free(apEndpoint->mpAdapterAddr);
1135 apEndpoint->mpAdapterAddr = nullptr;
1137 if (apEndpoint->mpRootPath != nullptr)
1139 g_free(apEndpoint->mpRootPath);
1140 apEndpoint->mpRootPath = nullptr;
1142 if (apEndpoint->mpAdvPath != nullptr)
1144 g_free(apEndpoint->mpAdvPath);
1145 apEndpoint->mpAdvPath = nullptr;
1147 if (apEndpoint->mpServicePath != nullptr)
1149 g_free(apEndpoint->mpServicePath);
1150 apEndpoint->mpServicePath = nullptr;
1152 if (apEndpoint->mpConnMap != nullptr)
1154 g_hash_table_destroy(apEndpoint->mpConnMap);
1155 apEndpoint->mpConnMap = nullptr;
1157 if (apEndpoint->mpAdvertisingUUID != nullptr)
1159 g_free(apEndpoint->mpAdvertisingUUID);
1160 apEndpoint->mpAdvertisingUUID = nullptr;
1162 if (apEndpoint->mpPeerDevicePath != nullptr)
1164 g_free(apEndpoint->mpPeerDevicePath);
1165 apEndpoint->mpPeerDevicePath = nullptr;
1167 g_free(apEndpoint->mpConnectCancellable);
1172 int BluezObjectsCleanup(BluezEndpoint * apEndpoint)
1174 g_object_unref(apEndpoint->mpAdapter);
1175 EndpointCleanup(apEndpoint);
1179 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1180 static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic)
1182 if (characteristic == nullptr)
1187 // Construct the TLV for the additional data
1188 GVariant * cValue = nullptr;
1190 CHIP_ERROR err = CHIP_NO_ERROR;
1191 chip::System::PacketBufferHandle bufferHandle;
1193 char serialNumber[ConfigurationManager::kMaxSerialNumberLength + 1];
1194 size_t serialNumberSize = 0;
1195 uint16_t lifetimeCounter = 0;
1196 BitFlags<AdditionalDataFields> additionalDataFields;
1198 #if CHIP_ENABLE_ROTATING_DEVICE_ID
1199 err = ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize);
1201 err = ConfigurationMgr().GetLifetimeCounter(lifetimeCounter);
1204 additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
1207 err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(lifetimeCounter, serialNumber, serialNumberSize,
1208 bufferHandle, additionalDataFields);
1211 data = g_memdup(bufferHandle->Start(), bufferHandle->DataLength());
1213 cValue = g_variant_new_from_data(G_VARIANT_TYPE("ay"), data, bufferHandle->DataLength(), TRUE, g_free, data);
1214 bluez_gatt_characteristic1_set_value(characteristic, cValue);
1219 if (err != CHIP_NO_ERROR)
1221 ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__);
1227 static void BluezPeripheralObjectsSetup(gpointer apClosure)
1230 static const char * const c1_flags[] = { "write", nullptr };
1231 static const char * const c2_flags[] = { "read", "indicate", nullptr };
1232 static const char * const c3_flags[] = { "read", nullptr };
1234 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1235 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1237 endpoint->mpService = BluezServiceCreate(apClosure);
1238 // C1 characteristic
1240 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
1241 bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
1243 g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1244 g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1245 g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
1246 g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
1247 g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
1248 g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
1249 g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
1252 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
1253 bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
1254 g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1255 g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1256 g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1257 g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1258 g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1259 g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1260 g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1262 ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1));
1263 ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2));
1265 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1266 ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
1267 // Additional data characteristics
1269 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot);
1270 bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags);
1271 g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1272 g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1273 g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1274 g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1275 g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1276 g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1277 g_signal_connect(endpoint->mpC3, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1278 // update the characteristic value
1279 UpdateAdditionalDataCharacteristic(endpoint->mpC3);
1280 ChipLogDetail(DeviceLayer, "CHIP BTP C3 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC3));
1282 ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is FALSE");
1290 static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1292 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1293 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1295 ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
1297 if (!endpoint->mIsCentral)
1299 endpoint->mpRootPath = g_strdup_printf("/chipoble/%04x", getpid() & 0xffff);
1300 endpoint->mpRoot = g_dbus_object_manager_server_new(endpoint->mpRootPath);
1301 g_dbus_object_manager_server_set_connection(endpoint->mpRoot, aConn);
1303 BluezPeripheralObjectsSetup(apClosure);
1310 #if CHIP_BLUEZ_NAME_MONITOR
1311 static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1313 ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
1316 static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1318 ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
1322 static int StartupEndpointBindings(BluezEndpoint * endpoint)
1324 GDBusObjectManager * manager;
1325 GError * error = nullptr;
1326 GDBusConnection * conn = nullptr;
1327 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1329 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
1330 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "FAIL: get bus sync in %s, error: %s", __func__, error->message));
1332 if (endpoint->mpAdapterName != nullptr)
1333 endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
1335 endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
1337 BluezOnBusAcquired(conn, endpoint->mpOwningName, endpoint);
1339 manager = g_dbus_object_manager_client_new_sync(
1340 conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
1341 nullptr /* unused user data in the Proxy Type Func */, nullptr /*destroy notify */, nullptr /* cancellable */, &error);
1343 VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
1345 endpoint->mpObjMgr = manager;
1347 bluezObjectsSetup(endpoint);
1349 g_signal_connect(manager, "object-added", G_CALLBACK(BluezSignalOnObjectAdded), endpoint);
1350 g_signal_connect(manager, "object-removed", G_CALLBACK(BluezSignalOnObjectRemoved), endpoint);
1351 g_signal_connect(manager, "interface-proxy-properties-changed", G_CALLBACK(BluezSignalInterfacePropertiesChanged), endpoint);
1353 if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint))
1355 ChipLogError(DeviceLayer, "Failed to schedule cleanup function");
1359 if (error != nullptr)
1360 g_error_free(error);
1365 static gboolean BluezC2Indicate(ConnectionDataBundle * closure)
1367 BluezConnection * conn = nullptr;
1368 GError * error = nullptr;
1371 size_t len, written;
1373 VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1375 conn = closure->mpConn;
1376 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1377 VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));
1379 if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
1381 buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
1382 VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
1383 ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
1384 status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written, &error);
1385 g_variant_unref(closure->mpVal);
1386 closure->mpVal = nullptr;
1388 VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
1392 bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
1393 closure->mpVal = nullptr;
1397 if (closure != nullptr)
1401 g_variant_unref(closure->mpVal);
1406 if (error != nullptr)
1407 g_error_free(error);
1408 return G_SOURCE_REMOVE;
1411 static ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, const chip::System::PacketBufferHandle & apBuf)
1413 ConnectionDataBundle * bundle = g_new(ConnectionDataBundle, 1);
1414 bundle->mpConn = static_cast<BluezConnection *>(apConn);
1416 g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
1420 bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1422 bool success = false;
1424 VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1426 success = MainLoop::Instance().Schedule(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
1432 static gboolean BluezDisconnect(void * apClosure)
1434 BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
1435 GError * error = nullptr;
1438 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
1439 VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
1441 ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
1443 success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
1444 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
1447 if (error != nullptr)
1448 g_error_free(error);
1449 return G_SOURCE_REMOVE;
1452 static int CloseBleconnectionCB(void * apAppState)
1454 BluezDisconnect(apAppState);
1455 return G_SOURCE_REMOVE;
1458 bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
1460 return MainLoop::Instance().RunOnBluezThread(CloseBleconnectionCB, apConn);
1463 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
1465 CHIP_ERROR err = CHIP_NO_ERROR;
1466 if (!MainLoop::Instance().Schedule(BluezAdvStart, apEndpoint))
1468 err = CHIP_ERROR_INCORRECT_STATE;
1469 ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
1474 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
1476 CHIP_ERROR err = CHIP_NO_ERROR;
1477 if (!MainLoop::Instance().Schedule(BluezAdvStop, apEndpoint))
1479 err = CHIP_ERROR_INCORRECT_STATE;
1480 ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
1485 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
1487 CHIP_ERROR err = CHIP_NO_ERROR;
1488 if (!MainLoop::Instance().Schedule(BluezAdvSetup, apEndpoint))
1490 err = CHIP_ERROR_INCORRECT_STATE;
1491 ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
1496 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
1498 CHIP_ERROR err = CHIP_NO_ERROR;
1499 if (!MainLoop::Instance().Schedule(BluezPeripheralRegisterApp, apEndpoint))
1501 err = CHIP_ERROR_INCORRECT_STATE;
1502 ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
1507 CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
1509 const char * msg = nullptr;
1510 CHIP_ERROR err = CHIP_NO_ERROR;
1511 VerifyOrExit(aBleAdvConfig.mpBleName != nullptr, msg = "FAIL: BLE name is NULL");
1512 VerifyOrExit(aBleAdvConfig.mpAdvertisingUUID != nullptr, msg = "FAIL: BLE mpAdvertisingUUID is NULL in %s");
1514 apEndpoint->mpAdapterName = g_strdup(aBleAdvConfig.mpBleName);
1515 apEndpoint->mpAdvertisingUUID = g_strdup(aBleAdvConfig.mpAdvertisingUUID);
1516 apEndpoint->mAdapterId = aBleAdvConfig.mAdapterId;
1517 apEndpoint->mType = aBleAdvConfig.mType;
1518 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1519 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1521 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
1527 ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1528 err = CHIP_ERROR_INCORRECT_STATE;
1533 CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint)
1535 CHIP_ERROR err = CHIP_NO_ERROR;
1536 bool retval = false;
1537 BluezEndpoint * endpoint = nullptr;
1539 // initialize server endpoint
1540 endpoint = g_new0(BluezEndpoint, 1);
1541 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
1543 if (apBleAddr != nullptr)
1544 endpoint->mpAdapterAddr = g_strdup(apBleAddr);
1546 endpoint->mpAdapterAddr = nullptr;
1548 endpoint->mpConnMap = g_hash_table_new(g_str_hash, g_str_equal);
1549 endpoint->mIsCentral = aIsCentral;
1553 err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
1558 endpoint->mAdapterId = aBleAdvConfig.mAdapterId;
1559 endpoint->mpConnectCancellable = g_cancellable_new();
1562 err = MainLoop::Instance().EnsureStarted();
1563 VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start BLE main loop"));
1565 if (!MainLoop::Instance().ScheduleAndWait(StartupEndpointBindings, endpoint))
1567 ChipLogError(DeviceLayer, "Failed to schedule endpoint initialization");
1576 apEndpoint = endpoint;
1577 ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
1581 EndpointCleanup(endpoint);
1587 // BluezSendWriteRequest callbacks
1589 static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1591 BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1592 GError * error = nullptr;
1593 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error);
1595 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
1596 BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
1599 if (error != nullptr)
1600 g_error_free(error);
1603 static gboolean SendWriteRequestImpl(void * apConnectionData)
1605 ConnectionDataBundle * data = static_cast<ConnectionDataBundle *>(apConnectionData);
1606 GVariant * options = nullptr;
1607 GVariantBuilder optionsBuilder;
1609 VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1610 VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1611 VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__));
1613 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY);
1614 g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request"));
1615 options = g_variant_builder_end(&optionsBuilder);
1617 bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
1622 return G_SOURCE_REMOVE;
1625 bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1627 bool success = false;
1629 VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1631 success = MainLoop::Instance().RunOnBluezThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
1637 // BluezSubscribeCharacteristic callbacks
1639 static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
1640 gpointer apConnection)
1642 BLE_CONNECTION_OBJECT connection = static_cast<BLE_CONNECTION_OBJECT>(apConnection);
1643 GVariant * value = g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING);
1644 VerifyOrReturn(value != nullptr);
1647 auto buffer = g_variant_get_fixed_array(value, &bufferLen, sizeof(uint8_t));
1648 VerifyOrReturn(value != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));
1650 BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
1653 static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1655 BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1656 GError * error = nullptr;
1657 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1659 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));
1661 // Get notifications on the TX characteristic change (e.g. indication is received)
1662 g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), apConnection);
1663 BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), true);
1666 if (error != nullptr)
1667 g_error_free(error);
1670 static gboolean SubscribeCharacteristicImpl(BluezConnection * connection)
1672 VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1673 VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1675 bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);
1678 return G_SOURCE_REMOVE;
1681 bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1683 return MainLoop::Instance().Schedule(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1686 // BluezUnsubscribeCharacteristic callbacks
1688 static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1690 BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1691 GError * error = nullptr;
1692 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1694 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));
1696 // Stop listening to the TX characteristic changes
1697 g_signal_handlers_disconnect_by_data(c2, apConnection);
1698 BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), false);
1701 if (error != nullptr)
1702 g_error_free(error);
1705 static gboolean UnsubscribeCharacteristicImpl(BluezConnection * connection)
1707 VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1708 VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1710 bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);
1713 return G_SOURCE_REMOVE;
1716 bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1718 return MainLoop::Instance().Schedule(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1721 // ConnectDevice callbacks
1723 struct ConnectParams
1725 ConnectParams(BluezDevice1 * device, BluezEndpoint * endpoint) : mDevice(device), mEndpoint(endpoint) {}
1726 BluezDevice1 * mDevice;
1727 BluezEndpoint * mEndpoint;
1730 static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
1732 BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
1733 GError * error = nullptr;
1734 gboolean success = bluez_device1_call_connect_finish(device, aResult, &error);
1738 ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message);
1739 BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_INTERNAL);
1743 ChipLogDetail(DeviceLayer, "ConnectDevice complete");
1746 if (error != nullptr)
1747 g_error_free(error);
1750 static gboolean ConnectDeviceImpl(ConnectParams * apParams)
1752 BluezDevice1 * device = apParams->mDevice;
1753 BluezEndpoint * endpoint = apParams->mEndpoint;
1755 assert(device != nullptr);
1756 assert(endpoint != nullptr);
1758 g_cancellable_reset(endpoint->mpConnectCancellable);
1759 bluez_device1_call_connect(device, endpoint->mpConnectCancellable, ConnectDeviceDone, nullptr);
1760 g_object_unref(device);
1761 chip::Platform::Delete(apParams);
1763 return G_SOURCE_REMOVE;
1766 CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice, BluezEndpoint * apEndpoint)
1768 auto params = chip::Platform::New<ConnectParams>(apDevice, apEndpoint);
1769 g_object_ref(apDevice);
1771 if (!MainLoop::Instance().Schedule(ConnectDeviceImpl, params))
1773 ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");
1774 g_object_unref(apDevice);
1775 chip::Platform::Delete(params);
1776 return CHIP_ERROR_INCORRECT_STATE;
1779 return CHIP_NO_ERROR;
1782 void CancelConnect(BluezEndpoint * apEndpoint)
1784 assert(apEndpoint->mpConnectCancellable != nullptr);
1785 g_cancellable_cancel(apEndpoint->mpConnectCancellable);
1788 } // namespace Internal
1789 } // namespace DeviceLayer
1791 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE