701feea6c6b61f28f01cac8f51771f89ec1ba502
[platform/upstream/connectedhomeip.git] / src / platform / Linux / bluez / Helper.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 /*
19  *  Copyright (c) 2016-2019, The OpenThread Authors.
20  *  All rights reserved.
21  *
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.
32  *
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.
44  */
45
46 /**
47  *    @file
48  *          Provides Bluez dbus implementatioon for BLE
49  */
50
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/CHIPMemString.h>
58
59 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
60 #include <errno.h>
61 #include <gio/gunixfdlist.h>
62 #include <limits>
63 #include <stdarg.h>
64 #include <strings.h>
65 #include <unistd.h>
66 #include <utility>
67
68 #include <platform/Linux/BLEManagerImpl.h>
69 #include <support/CodeUtils.h>
70 #include <support/ReturnMacros.h>
71 #include <system/TLVPacketBufferBackingStore.h>
72
73 #include "BluezObjectIterator.h"
74 #include "BluezObjectList.h"
75 #include "Helper.h"
76 #include "MainLoop.h"
77
78 using namespace ::nl;
79 using namespace chip::Protocols;
80 using chip::Platform::CopyString;
81
82 namespace chip {
83 namespace DeviceLayer {
84 namespace Internal {
85
86 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
87
88 namespace {
89
90 class BluezEndpointObjectList : public BluezObjectList
91 {
92 public:
93     explicit BluezEndpointObjectList(BluezEndpoint * apEndpoint)
94     {
95         VerifyOrReturn(apEndpoint != nullptr, ChipLogError(DeviceLayer, "apEndpoint is NULL in %s", __func__));
96         Initialize(apEndpoint->mpObjMgr);
97     }
98 };
99
100 } // namespace
101
102 static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
103 {
104     bool isSuccess           = false;
105     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
106     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
107     VerifyOrExit(aAdv != nullptr, ChipLogError(DeviceLayer, "BluezLEAdvertisement1 is NULL in %s", __func__));
108     ChipLogDetail(DeviceLayer, "Release adv object in %s", __func__);
109
110     g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
111     endpoint->mIsAdvertising = false;
112     isSuccess                = true;
113 exit:
114
115     return isSuccess ? TRUE : FALSE;
116 }
117
118 static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
119 {
120     BluezLEAdvertisement1 * adv = nullptr;
121     BluezObjectSkeleton * object;
122     GVariant * serviceData;
123     GVariant * serviceUUID;
124     gchar * localName;
125     GVariantBuilder serviceDataBuilder;
126     GVariantBuilder serviceUUIDsBuilder;
127     char * debugStr;
128
129     VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
130     if (apEndpoint->mpAdvPath == nullptr)
131         apEndpoint->mpAdvPath = g_strdup_printf("%s/advertising", apEndpoint->mpRootPath);
132
133     ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
134     object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
135
136     adv = bluez_leadvertisement1_skeleton_new();
137
138     g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
139     g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
140
141     g_variant_builder_add(&serviceDataBuilder, "{sv}", apEndpoint->mpAdvertisingUUID,
142                           g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &apEndpoint->mDeviceIdInfo,
143                                                     sizeof(apEndpoint->mDeviceIdInfo), sizeof(uint8_t)));
144     g_variant_builder_add(&serviceUUIDsBuilder, "s", apEndpoint->mpAdvertisingUUID);
145
146     if (apEndpoint->mpAdapterName != nullptr)
147         localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
148     else
149         localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
150
151     serviceData = g_variant_builder_end(&serviceDataBuilder);
152     serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
153
154     debugStr = g_variant_print(serviceData, TRUE);
155     ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
156     g_free(debugStr);
157
158     bluez_leadvertisement1_set_type_(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_CONNECTABLE) ? "peripheral" : "broadcast");
159     // empty manufacturer data
160     // empty solicit UUIDs
161     bluez_leadvertisement1_set_service_data(adv, serviceData);
162     // empty data
163
164     // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
165     // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
166     // and the flag is necessary to force using LE transport.
167     bluez_leadvertisement1_set_discoverable(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE) ? TRUE : FALSE);
168     if (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE)
169         bluez_leadvertisement1_set_discoverable_timeout(adv, UINT16_MAX);
170
171     // advertising name corresponding to the PID and object path, for debug purposes
172     bluez_leadvertisement1_set_local_name(adv, localName);
173     bluez_leadvertisement1_set_service_uuids(adv, serviceUUID);
174
175     // 0xffff means no appearance
176     bluez_leadvertisement1_set_appearance(adv, 0xffff);
177
178     bluez_leadvertisement1_set_duration(adv, apEndpoint->mDuration);
179     // empty duration, we don't have a clear notion what it would mean to timeslice between toble and anyone else
180     bluez_leadvertisement1_set_timeout(adv, 0);
181     // empty secondary channel for now
182
183     bluez_object_skeleton_set_leadvertisement1(object, adv);
184     g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
185
186     g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
187     g_object_unref(object);
188
189     BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
190
191 exit:
192     return adv;
193 }
194
195 static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
196 {
197     BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
198     GError * error                      = nullptr;
199     BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
200     gboolean success                    = FALSE;
201
202     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
203
204     success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
205     if (success == FALSE)
206     {
207         g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
208     }
209     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
210
211     endpoint->mIsAdvertising = true;
212
213     ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
214
215 exit:
216     BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
217     if (error != nullptr)
218         g_error_free(error);
219 }
220
221 static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
222 {
223     BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
224     BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
225     GError * error                      = nullptr;
226     gboolean success                    = FALSE;
227
228     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
229
230     success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
231
232     if (success == FALSE)
233     {
234         g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
235     }
236     else
237     {
238         endpoint->mIsAdvertising = false;
239     }
240
241     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
242
243     ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
244
245 exit:
246     BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
247     if (error != nullptr)
248         g_error_free(error);
249 }
250
251 static gboolean BluezAdvSetup(BluezEndpoint * endpoint)
252 {
253     BluezLEAdvertisement1 * adv;
254
255     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
256     VerifyOrExit(endpoint->mIsAdvertising == FALSE, ChipLogError(DeviceLayer, "FAIL: Advertising already enabled in %s", __func__));
257     VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
258
259     adv = BluezAdvertisingCreate(endpoint);
260     VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
261
262 exit:
263     return G_SOURCE_REMOVE;
264 }
265
266 static gboolean BluezAdvStart(BluezEndpoint * endpoint)
267 {
268     GDBusObject * adapter;
269     BluezLEAdvertisingManager1 * advMgr = nullptr;
270     GVariantBuilder optionsBuilder;
271     GVariant * options;
272
273     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
274     VerifyOrExit(!endpoint->mIsAdvertising,
275                  ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled in %s", __func__));
276     VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
277
278     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
279     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
280
281     advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
282     VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
283
284     g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
285     options = g_variant_builder_end(&optionsBuilder);
286
287     bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
288                                                              endpoint);
289
290 exit:
291     return G_SOURCE_REMOVE;
292 }
293
294 static gboolean BluezAdvStop(BluezEndpoint * endpoint)
295 {
296     GDBusObject * adapter;
297     BluezLEAdvertisingManager1 * advMgr = nullptr;
298
299     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
300     VerifyOrExit(endpoint->mIsAdvertising,
301                  ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
302     VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
303
304     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
305     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
306
307     advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
308     VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
309
310     bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, endpoint);
311
312 exit:
313     return G_SOURCE_REMOVE;
314 }
315
316 static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
317                                              GVariant * aOptions)
318 {
319     GVariant * val;
320     ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
321     val = bluez_gatt_characteristic1_get_value(aChar);
322     bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
323     return TRUE;
324 }
325
326 #if CHIP_BLUEZ_CHAR_WRITE_VALUE
327 static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
328                                               GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
329 {
330     const uint8_t * tmpBuf;
331     uint8_t * buf;
332     size_t len;
333     bool isSuccess         = false;
334     BluezConnection * conn = NULL;
335
336     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
337     VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
338
339     VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
340
341     conn = GetBluezConnectionViaDevice(endpoint);
342     VerifyOrExit(conn != NULL,
343                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
344
345     bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
346
347     tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
348     buf    = (uint8_t *) (g_memdup(tmpBuf, len));
349
350     BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
351     bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
352     isSuccess = true;
353
354 exit:
355     return isSuccess ? TRUE : FALSE;
356 }
357 #endif
358
359 static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
360                                                    GVariant * aValue, GVariant * aOptions, gpointer apClosure)
361 {
362     ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
363     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
364                                                "Write for characteristic is unsupported");
365     return TRUE;
366 }
367
368 static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
369 {
370     GVariant * newVal;
371     gchar * buf;
372     ssize_t len;
373     int fd;
374     bool isSuccess = false;
375
376     BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
377
378     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
379
380     VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__));
381     VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__));
382     VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__));
383
384     ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
385
386     buf = static_cast<gchar *>(g_malloc(conn->mMtu));
387     fd  = g_io_channel_unix_get_fd(aChannel);
388
389     len = read(fd, buf, conn->mMtu);
390
391     VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
392
393     // Casting len to size_t is safe, since we ensured that it's not negative.
394     newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
395
396     bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
397     BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
398     isSuccess = true;
399
400 exit:
401     return isSuccess ? TRUE : FALSE;
402 }
403
404 static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
405 {
406     GUnixFDList * fd_list = g_unix_fd_list_new();
407     int index;
408
409     index = g_unix_fd_list_append(fd_list, fd, nullptr);
410
411     g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
412                                                             fd_list);
413 }
414
415 static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
416 {
417     return G_SOURCE_REMOVE;
418 }
419
420 static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
421                                                 GVariant * aOptions, gpointer apEndpoint)
422 {
423     int fds[2] = { -1, -1 };
424     GIOChannel * channel;
425     char * errStr;
426     GVariantDict options;
427     bool isSuccess         = false;
428     BluezConnection * conn = nullptr;
429
430     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
431     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
432
433     conn = GetBluezConnectionViaDevice(endpoint);
434     VerifyOrExit(conn != nullptr,
435                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
436
437     ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
438
439     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
440     {
441         errStr = strerror(errno);
442         ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
443         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
444         SuccessOrExit(false);
445     }
446
447     g_variant_dict_init(&options, aOptions);
448     if (g_variant_dict_contains(&options, "mtu") == TRUE)
449     {
450         GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
451         conn->mMtu   = g_variant_get_uint16(v);
452     }
453     else
454     {
455         ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
456         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
457         SuccessOrExit(false);
458     }
459
460     channel = g_io_channel_unix_new(fds[0]);
461     g_io_channel_set_encoding(channel, nullptr, nullptr);
462     g_io_channel_set_close_on_unref(channel, TRUE);
463     g_io_channel_set_buffered(channel, FALSE);
464
465     conn->mC1Channel.mpChannel = channel;
466     conn->mC1Channel.mWatch    = g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL),
467                                              BluezCharacteristicWriteFD, conn);
468
469     bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
470
471     Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
472     close(fds[1]);
473     isSuccess = true;
474
475 exit:
476     return isSuccess ? TRUE : FALSE;
477 }
478
479 static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
480                                                      GVariant * aOptions)
481 {
482     ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWriteError is called");
483     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
484                                                "AcquireWrite for characteristic is unsupported");
485     return TRUE;
486 }
487
488 static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
489                                                  GVariant * aOptions, gpointer apEndpoint)
490 {
491     int fds[2] = { -1, -1 };
492     GIOChannel * channel;
493     char * errStr;
494     GVariantDict options;
495     BluezConnection * conn = nullptr;
496     bool isSuccess         = false;
497
498     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
499     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
500
501     conn = GetBluezConnectionViaDevice(endpoint);
502     VerifyOrExit(conn != nullptr,
503                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
504
505     g_variant_dict_init(&options, aOptions);
506     if ((g_variant_dict_contains(&options, "mtu") == TRUE))
507     {
508         GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
509         conn->mMtu   = g_variant_get_uint16(v);
510     }
511
512     if (bluez_gatt_characteristic1_get_notifying(aChar))
513     {
514         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
515     }
516     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
517     {
518         errStr = strerror(errno);
519         ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
520         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
521         SuccessOrExit(false);
522     }
523     channel = g_io_channel_unix_new(fds[0]);
524     g_io_channel_set_encoding(channel, nullptr, nullptr);
525     g_io_channel_set_close_on_unref(channel, TRUE);
526     g_io_channel_set_buffered(channel, FALSE);
527     conn->mC2Channel.mpChannel = channel;
528     conn->mC2Channel.mWatch =
529         g_io_add_watch_full(channel, G_PRIORITY_DEFAULT_IDLE, static_cast<GIOCondition>(G_IO_HUP | G_IO_ERR | G_IO_NVAL),
530                             bluezCharacteristicDestroyFD, conn, nullptr);
531
532     bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
533
534     // same reply as for AcquireWrite
535     Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
536     close(fds[1]);
537
538     conn->mIsNotify = true;
539     BLEManagerImpl::HandleTXCharCCCDWrite(conn);
540     isSuccess = true;
541
542 exit:
543     return isSuccess ? TRUE : FALSE;
544 }
545
546 static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
547                                                       GVariant * aOptions)
548 {
549     ChipLogDetail(DeviceLayer, "TRACE: AcquireNotify is called");
550     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
551                                                "AcquireNotify for characteristic is unsupported");
552     return TRUE;
553 }
554
555 static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
556                                                gpointer apEndpoint)
557 {
558     bool isSuccess         = false;
559     BluezConnection * conn = nullptr;
560
561     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
562     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
563
564     conn = GetBluezConnectionViaDevice(endpoint);
565     VerifyOrExit(conn != nullptr,
566                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
567
568     if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
569     {
570         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
571     }
572     else
573     {
574         bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
575         bluez_gatt_characteristic1_set_notifying(aChar, TRUE);
576         conn->mIsNotify = true;
577         BLEManagerImpl::HandleTXCharCCCDWrite(conn);
578     }
579     isSuccess = true;
580
581 exit:
582     return isSuccess ? TRUE : FALSE;
583 }
584
585 static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
586 {
587     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
588                                                "Subscribing to characteristic is unsupported");
589     return TRUE;
590 }
591
592 static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
593                                               gpointer apEndpoint)
594 {
595     bool isSuccess         = false;
596     BluezConnection * conn = nullptr;
597
598     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
599     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
600
601     conn = GetBluezConnectionViaDevice(endpoint);
602     VerifyOrExit(conn != nullptr,
603                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
604
605     if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
606     {
607         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
608     }
609     else
610     {
611         bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
612         bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
613     }
614     conn->mIsNotify = false;
615
616     isSuccess = true;
617
618 exit:
619     return isSuccess ? TRUE : FALSE;
620 }
621
622 static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
623                                            gpointer apClosure)
624 {
625     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
626     BluezConnection * conn   = GetBluezConnectionViaDevice(endpoint);
627
628     ChipLogDetail(Ble, "Indication confirmation, %p", conn);
629     BLEManagerImpl::HandleTXComplete(conn);
630
631     return TRUE;
632 }
633
634 static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
635 {
636     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
637                                                "Unsubscribing from characteristic is unsupported");
638     return TRUE;
639 }
640
641 static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
642 {
643     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
644     return TRUE;
645 }
646
647 static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
648 {
649     return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
650 }
651
652 static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
653 {
654     return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
655                                                                                                                       : FALSE;
656 }
657
658 static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
659 {
660     ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar));
661     ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)));
662     return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE
663                                                                                                                             : FALSE;
664 }
665
666 static void BluezConnectionInit(BluezConnection * apConn)
667 {
668     // populate the service and the characteristics
669     GList * objects = nullptr;
670     GList * l;
671     BluezEndpoint * endpoint = nullptr;
672
673     VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
674
675     endpoint = apConn->mpEndpoint;
676     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
677
678     if (!endpoint->mIsCentral)
679     {
680         apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService));
681         apConn->mpC1      = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1));
682         apConn->mpC2      = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2));
683     }
684     else
685     {
686         objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
687
688         for (l = objects; l != nullptr; l = l->next)
689         {
690             BluezObject * object        = BLUEZ_OBJECT(l->data);
691             BluezGattService1 * service = bluez_object_get_gatt_service1(object);
692
693             if (service != nullptr)
694             {
695                 if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
696                     (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
697                 {
698                     apConn->mpService = service;
699                     break;
700                 }
701                 g_object_unref(service);
702             }
703         }
704
705         VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
706
707         for (l = objects; l != nullptr; l = l->next)
708         {
709             BluezObject * object             = BLUEZ_OBJECT(l->data);
710             BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
711
712             if (char1 != nullptr)
713             {
714                 if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
715                     (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
716                 {
717                     apConn->mpC1 = char1;
718                 }
719                 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
720                          (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
721                 {
722                     apConn->mpC2 = char1;
723                 }
724                 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
725                          (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0))
726                 {
727                     apConn->mpC3 = char1;
728                 }
729                 else
730                 {
731                     g_object_unref(char1);
732                 }
733                 if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
734                 {
735                     break;
736                 }
737             }
738         }
739
740         VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
741         VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
742     }
743
744 exit:
745     if (objects != nullptr)
746         g_list_free_full(objects, g_object_unref);
747 }
748
749 static void BluezOTConnectionDestroy(BluezConnection * aConn)
750 {
751     if (aConn)
752     {
753         if (aConn->mpDevice)
754             g_object_unref(aConn->mpDevice);
755         if (aConn->mpService)
756             g_object_unref(aConn->mpService);
757         if (aConn->mpC1)
758             g_object_unref(aConn->mpC1);
759         if (aConn->mpC2)
760             g_object_unref(aConn->mpC2);
761         if (aConn->mpPeerAddress)
762             g_free(aConn->mpPeerAddress);
763         if (aConn->mC1Channel.mWatch > 0)
764             g_source_remove(aConn->mC1Channel.mWatch);
765         if (aConn->mC1Channel.mpChannel)
766             g_io_channel_unref(aConn->mC1Channel.mpChannel);
767         if (aConn->mC2Channel.mWatch > 0)
768             g_source_remove(aConn->mC2Channel.mWatch);
769         if (aConn->mC2Channel.mpChannel)
770             g_io_channel_unref(aConn->mC2Channel.mpChannel);
771
772         g_free(aConn);
773     }
774 }
775
776 static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
777                                                             const char * aUUID, GDBusObjectManagerServer * aRoot)
778 {
779     char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
780     char * charPath    = g_strdup_printf("%s/%s", servicePath, aCharName);
781     BluezObjectSkeleton * object;
782     BluezGattCharacteristic1 * characteristic;
783
784     ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
785     object = bluez_object_skeleton_new(charPath);
786
787     characteristic = bluez_gatt_characteristic1_skeleton_new();
788     bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
789     bluez_gatt_characteristic1_set_service(characteristic, servicePath);
790
791     bluez_object_skeleton_set_gatt_characteristic1(object, characteristic);
792     g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
793     g_object_unref(object);
794
795     return characteristic;
796 }
797
798 static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
799 {
800     GError * error              = nullptr;
801     BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
802
803     gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
804
805     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
806
807     BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
808     ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
809
810 exit:
811     if (error != nullptr)
812     {
813         BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
814         g_error_free(error);
815     }
816 }
817
818 gboolean BluezPeripheralRegisterApp(BluezEndpoint * endpoint)
819 {
820     GDBusObject * adapter;
821     BluezGattManager1 * gattMgr;
822     GVariantBuilder optionsBuilder;
823     GVariant * options;
824
825     VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
826
827     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
828     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
829
830     gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
831     VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
832
833     g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
834     options = g_variant_builder_end(&optionsBuilder);
835
836     bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
837                                                   nullptr);
838
839 exit:
840     return G_SOURCE_REMOVE;
841 }
842
843 /// Update the table of open BLE connections whevener a new device is spotted or its attributes have changed.
844 static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndpoint)
845 {
846     const gchar * objectPath     = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
847     BluezConnection * connection = static_cast<BluezConnection *>(g_hash_table_lookup(aEndpoint.mpConnMap, objectPath));
848
849     if (connection != nullptr && !bluez_device1_get_connected(apDevice))
850     {
851         ChipLogDetail(DeviceLayer, "Bluez disconnected");
852         BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection);
853         // TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources
854         // after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone.
855         BluezOTConnectionDestroy(connection);
856         g_hash_table_remove(aEndpoint.mpConnMap, objectPath);
857         return;
858     }
859
860     if (connection == nullptr && !bluez_device1_get_connected(apDevice) && aEndpoint.mIsCentral)
861     {
862         return;
863     }
864
865     if (connection == nullptr && bluez_device1_get_connected(apDevice) &&
866         (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice)))
867     {
868         connection                = g_new0(BluezConnection, 1);
869         connection->mpPeerAddress = g_strdup(bluez_device1_get_address(apDevice));
870         connection->mpDevice      = static_cast<BluezDevice1 *>(g_object_ref(apDevice));
871         connection->mpEndpoint    = &aEndpoint;
872         BluezConnectionInit(connection);
873         aEndpoint.mpPeerDevicePath = g_strdup(objectPath);
874         g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection);
875
876         ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
877                       aEndpoint.mpPeerDevicePath);
878
879         BLEManagerImpl::HandleNewConnection(connection);
880     }
881 }
882
883 static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
884                                                   GDBusProxy * aInterface, GVariant * aChangedProperties,
885                                                   const gchar * const * aInvalidatedProps, gpointer apClosure)
886 {
887     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
888     VerifyOrReturn(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
889     VerifyOrReturn(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
890     VerifyOrReturn(strcmp(g_dbus_proxy_get_interface_name(aInterface), DEVICE_INTERFACE) == 0, );
891
892     BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
893     VerifyOrReturn(BluezIsDeviceOnAdapter(device, endpoint->mpAdapter));
894
895     UpdateConnectionTable(device, *endpoint);
896 }
897
898 static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
899 {
900     VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
901     if (apEndpoint->mIsCentral)
902     {
903         return;
904     }
905
906     // We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
907     // When a device is connected for first time, this function will be triggerred.
908     // The future connections for the same device will trigger ``Connect'' property change.
909     // TODO: Factor common code in the two function.
910     BluezConnection * conn;
911     VerifyOrExit(bluez_device1_get_connected(device), ChipLogError(DeviceLayer, "FAIL: device is not connected"));
912
913     conn = static_cast<BluezConnection *>(
914         g_hash_table_lookup(apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
915     VerifyOrExit(conn == nullptr,
916                  ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x new device: %s", conn,
917                               g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
918
919     conn                = g_new0(BluezConnection, 1);
920     conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
921     conn->mpDevice      = static_cast<BluezDevice1 *>(g_object_ref(device));
922     conn->mpEndpoint    = apEndpoint;
923     BluezConnectionInit(conn);
924     apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
925     ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
926     g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
927
928 exit:
929     return;
930 }
931
932 static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, BluezEndpoint * endpoint)
933 {
934     // TODO: right now we do not handle addition/removal of adapters
935     // Primary focus here is to handle addition of a device
936     BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(aObject));
937     if (device == nullptr)
938     {
939         return;
940     }
941
942     if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
943     {
944         BluezHandleNewDevice(device, endpoint);
945     }
946
947     g_object_unref(device);
948 }
949
950 static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
951 {
952     // TODO: for Device1, lookup connection, and call otPlatTobleHandleDisconnected
953     // for Adapter1: unclear, crash if this pertains to our adapter? at least null out the endpoint->mpAdapter.
954     // for Characteristic1, or GattService -- handle here via calling otPlatTobleHandleDisconnected, or ignore.
955 }
956
957 static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
958 {
959     BluezObjectSkeleton * object;
960     BluezGattService1 * service;
961     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
962
963     endpoint->mpServicePath = g_strdup_printf("%s/service", endpoint->mpRootPath);
964     ChipLogDetail(DeviceLayer, "CREATE service object at %s", endpoint->mpServicePath);
965     object = bluez_object_skeleton_new(endpoint->mpServicePath);
966
967     service = bluez_gatt_service1_skeleton_new();
968     bluez_gatt_service1_set_uuid(service, "0xFEAF");
969     // device is only valid for remote services
970     bluez_gatt_service1_set_primary(service, TRUE);
971
972     // includes -- unclear whether required.  Might be filled in later
973     bluez_object_skeleton_set_gatt_service1(object, service);
974     g_dbus_object_manager_server_export(endpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
975     g_object_unref(object);
976
977     return service;
978 }
979
980 static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
981 {
982     GList * objects = nullptr;
983     GList * l;
984     char * expectedPath = nullptr;
985
986     VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
987
988     expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mAdapterId);
989     objects      = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
990
991     for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
992     {
993         BluezObject * object = BLUEZ_OBJECT(l->data);
994         GList * interfaces;
995         GList * ll;
996         interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
997
998         for (ll = interfaces; ll != nullptr; ll = ll->next)
999         {
1000             if (BLUEZ_IS_ADAPTER1(ll->data))
1001             { // we found the adapter
1002                 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(ll->data);
1003                 char * addr             = const_cast<char *>(bluez_adapter1_get_address(adapter));
1004                 if (apEndpoint->mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid
1005                 {
1006                     if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
1007                     {
1008                         apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1009                     }
1010                 }
1011                 else
1012                 {
1013                     if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
1014                     {
1015                         apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1016                     }
1017                 }
1018             }
1019         }
1020         g_list_free_full(interfaces, g_object_unref);
1021     }
1022     VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
1023     bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
1024
1025     // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
1026     // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
1027     // and the flag is necessary to force using LE transport.
1028     bluez_adapter1_set_discoverable(apEndpoint->mpAdapter, FALSE);
1029
1030 exit:
1031     g_list_free_full(objects, g_object_unref);
1032     g_free(expectedPath);
1033 }
1034
1035 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
1036 {
1037     BluezConnection * retval =
1038         static_cast<BluezConnection *>(g_hash_table_lookup(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath));
1039     // ChipLogError(DeviceLayer, "acquire connection object %p in (%s)", retval, __func__);
1040     return retval;
1041 }
1042
1043 #if CHIP_BLUEZ_CENTRAL_SUPPORT
1044 static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
1045                                                                BluezEndpoint * apEndpoint)
1046 {
1047     BluezConnection * retval = NULL;
1048     const gchar * path       = NULL;
1049     GVariantDict options;
1050     GVariant * v;
1051
1052     VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1053     VerifyOrExit(apEndpoint->mIsCentral, );
1054
1055     /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
1056      * peer device in call params so we need look this up ourselves.
1057      */
1058     if (aOptions == NULL)
1059     {
1060         GList * objects;
1061         GList * l;
1062         GList * ll;
1063
1064         objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1065         for (l = objects; l != NULL; l = l->next)
1066         {
1067             BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
1068             if (device != NULL)
1069             {
1070                 if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
1071                 {
1072                     for (ll = objects; ll != NULL; ll = ll->next)
1073                     {
1074                         BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
1075                         if (service != NULL)
1076                         {
1077                             if (BluezIsServiceOnDevice(service, device))
1078                             {
1079                                 if (BluezIsCharOnService(aChar, service))
1080                                 {
1081                                     retval = (BluezConnection *) g_hash_table_lookup(
1082                                         apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1083                                 }
1084                             }
1085                             g_object_unref(service);
1086                             if (retval != NULL)
1087                                 break;
1088                         }
1089                     }
1090                 }
1091                 g_object_unref(device);
1092                 if (retval != NULL)
1093                     break;
1094             }
1095         }
1096
1097         g_list_free_full(objects, g_object_unref);
1098     }
1099     else
1100     {
1101         g_variant_dict_init(&options, aOptions);
1102
1103         v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
1104
1105         VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
1106
1107         path = g_variant_get_string(v, NULL);
1108
1109         retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
1110     }
1111
1112 exit:
1113     return retval;
1114 }
1115 #endif // CHIP_BLUEZ_CENTRAL_SUPPORT
1116
1117 void EndpointCleanup(BluezEndpoint * apEndpoint)
1118 {
1119     if (apEndpoint != nullptr)
1120     {
1121         if (apEndpoint->mpOwningName != nullptr)
1122         {
1123             g_free(apEndpoint->mpOwningName);
1124             apEndpoint->mpOwningName = nullptr;
1125         }
1126         if (apEndpoint->mpAdapterName != nullptr)
1127         {
1128             g_free(apEndpoint->mpAdapterName);
1129             apEndpoint->mpAdapterName = nullptr;
1130         }
1131         if (apEndpoint->mpAdapterAddr != nullptr)
1132         {
1133             g_free(apEndpoint->mpAdapterAddr);
1134             apEndpoint->mpAdapterAddr = nullptr;
1135         }
1136         if (apEndpoint->mpRootPath != nullptr)
1137         {
1138             g_free(apEndpoint->mpRootPath);
1139             apEndpoint->mpRootPath = nullptr;
1140         }
1141         if (apEndpoint->mpAdvPath != nullptr)
1142         {
1143             g_free(apEndpoint->mpAdvPath);
1144             apEndpoint->mpAdvPath = nullptr;
1145         }
1146         if (apEndpoint->mpServicePath != nullptr)
1147         {
1148             g_free(apEndpoint->mpServicePath);
1149             apEndpoint->mpServicePath = nullptr;
1150         }
1151         if (apEndpoint->mpConnMap != nullptr)
1152         {
1153             g_hash_table_destroy(apEndpoint->mpConnMap);
1154             apEndpoint->mpConnMap = nullptr;
1155         }
1156         if (apEndpoint->mpAdvertisingUUID != nullptr)
1157         {
1158             g_free(apEndpoint->mpAdvertisingUUID);
1159             apEndpoint->mpAdvertisingUUID = nullptr;
1160         }
1161         if (apEndpoint->mpPeerDevicePath != nullptr)
1162         {
1163             g_free(apEndpoint->mpPeerDevicePath);
1164             apEndpoint->mpPeerDevicePath = nullptr;
1165         }
1166
1167         g_free(apEndpoint);
1168     }
1169 }
1170
1171 int BluezObjectsCleanup(BluezEndpoint * apEndpoint)
1172 {
1173     g_object_unref(apEndpoint->mpAdapter);
1174     EndpointCleanup(apEndpoint);
1175     return 0;
1176 }
1177
1178 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1179 static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic)
1180 {
1181     if (characteristic == nullptr)
1182     {
1183         return;
1184     }
1185
1186     // Construct the TLV for the additional data
1187     GVariant * cValue = nullptr;
1188     gpointer data;
1189     CHIP_ERROR err = CHIP_NO_ERROR;
1190     chip::System::PacketBufferHandle bufferHandle;
1191
1192     char serialNumber[ConfigurationManager::kMaxSerialNumberLength + 1];
1193     size_t serialNumberSize  = 0;
1194     uint16_t lifetimeCounter = 0;
1195     BitFlags<uint8_t, AdditionalDataFields> additionalDataFields;
1196
1197 #if CHIP_ENABLE_ROTATING_DEVICE_ID
1198     err = ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize);
1199     SuccessOrExit(err);
1200     err = ConfigurationMgr().GetLifetimeCounter(lifetimeCounter);
1201     SuccessOrExit(err);
1202
1203     additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
1204 #endif
1205
1206     err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(lifetimeCounter, serialNumber, serialNumberSize,
1207                                                                          bufferHandle, additionalDataFields);
1208     SuccessOrExit(err);
1209
1210     data = g_memdup(bufferHandle->Start(), bufferHandle->DataLength());
1211
1212     cValue = g_variant_new_from_data(G_VARIANT_TYPE("ay"), data, bufferHandle->DataLength(), TRUE, g_free, data);
1213     bluez_gatt_characteristic1_set_value(characteristic, cValue);
1214
1215     return;
1216
1217 exit:
1218     if (err != CHIP_NO_ERROR)
1219     {
1220         ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__);
1221     }
1222     return;
1223 }
1224 #endif
1225
1226 static void BluezPeripheralObjectsSetup(gpointer apClosure)
1227 {
1228
1229     static const char * const c1_flags[] = { "write", nullptr };
1230     static const char * const c2_flags[] = { "read", "indicate", nullptr };
1231     static const char * const c3_flags[] = { "read", nullptr };
1232
1233     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1234     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1235
1236     endpoint->mpService = BluezServiceCreate(apClosure);
1237     // C1 characteristic
1238     endpoint->mpC1 =
1239         BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
1240     bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
1241
1242     g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1243     g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1244     g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
1245     g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
1246     g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
1247     g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
1248     g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
1249
1250     endpoint->mpC2 =
1251         BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
1252     bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
1253     g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1254     g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1255     g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1256     g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1257     g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1258     g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1259     g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1260
1261     ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1));
1262     ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2));
1263
1264 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1265     ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
1266     // Additional data characteristics
1267     endpoint->mpC3 =
1268         BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot);
1269     bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags);
1270     g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1271     g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1272     g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1273     g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1274     g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1275     g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1276     g_signal_connect(endpoint->mpC3, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1277     // update the characteristic value
1278     UpdateAdditionalDataCharacteristic(endpoint->mpC3);
1279     ChipLogDetail(DeviceLayer, "CHIP BTP C3 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC3));
1280 #else
1281     ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is FALSE");
1282     (void) c3_flags;
1283 #endif
1284
1285 exit:
1286     return;
1287 }
1288
1289 static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1290 {
1291     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1292     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1293
1294     ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
1295
1296     if (!endpoint->mIsCentral)
1297     {
1298         endpoint->mpRootPath = g_strdup_printf("/chipoble/%04x", getpid() & 0xffff);
1299         endpoint->mpRoot     = g_dbus_object_manager_server_new(endpoint->mpRootPath);
1300         g_dbus_object_manager_server_set_connection(endpoint->mpRoot, aConn);
1301
1302         BluezPeripheralObjectsSetup(apClosure);
1303     }
1304
1305 exit:
1306     return;
1307 }
1308
1309 #if CHIP_BLUEZ_NAME_MONITOR
1310 static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1311 {
1312     ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
1313 }
1314
1315 static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1316 {
1317     ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
1318 }
1319 #endif
1320
1321 static int StartupEndpointBindings(BluezEndpoint * endpoint)
1322 {
1323     GDBusObjectManager * manager;
1324     GError * error         = nullptr;
1325     GDBusConnection * conn = nullptr;
1326     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1327
1328     conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
1329     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "FAIL: get bus sync in %s, error: %s", __func__, error->message));
1330
1331     if (endpoint->mpAdapterName != nullptr)
1332         endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
1333     else
1334         endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
1335
1336     BluezOnBusAcquired(conn, endpoint->mpOwningName, endpoint);
1337
1338     manager = g_dbus_object_manager_client_new_sync(
1339         conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
1340         nullptr /* unused user data in the Proxy Type Func */, nullptr /*destroy notify */, nullptr /* cancellable */, &error);
1341
1342     VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
1343
1344     endpoint->mpObjMgr = manager;
1345
1346     bluezObjectsSetup(endpoint);
1347
1348     g_signal_connect(manager, "object-added", G_CALLBACK(BluezSignalOnObjectAdded), endpoint);
1349     g_signal_connect(manager, "object-removed", G_CALLBACK(BluezSignalOnObjectRemoved), endpoint);
1350     g_signal_connect(manager, "interface-proxy-properties-changed", G_CALLBACK(BluezSignalInterfacePropertiesChanged), endpoint);
1351
1352     if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint))
1353     {
1354         ChipLogError(DeviceLayer, "Failed to schedule cleanup function");
1355     }
1356
1357 exit:
1358     if (error != nullptr)
1359         g_error_free(error);
1360
1361     return 0;
1362 }
1363
1364 static gboolean BluezC2Indicate(ConnectionDataBundle * closure)
1365 {
1366     BluezConnection * conn = nullptr;
1367     GError * error         = nullptr;
1368     GIOStatus status;
1369     const char * buf;
1370     size_t len, written;
1371
1372     VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1373
1374     conn = closure->mpConn;
1375     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1376     VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));
1377
1378     if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
1379     {
1380         buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
1381         VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
1382                      ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
1383         status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written, &error);
1384         g_variant_unref(closure->mpVal);
1385         closure->mpVal = nullptr;
1386
1387         VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
1388     }
1389     else
1390     {
1391         bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
1392         closure->mpVal = nullptr;
1393     }
1394
1395 exit:
1396     if (closure != nullptr)
1397     {
1398         if (closure->mpVal)
1399         {
1400             g_variant_unref(closure->mpVal);
1401         }
1402         g_free(closure);
1403     }
1404
1405     if (error != nullptr)
1406         g_error_free(error);
1407     return G_SOURCE_REMOVE;
1408 }
1409
1410 static ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, const chip::System::PacketBufferHandle & apBuf)
1411 {
1412     ConnectionDataBundle * bundle = g_new(ConnectionDataBundle, 1);
1413     bundle->mpConn                = static_cast<BluezConnection *>(apConn);
1414     bundle->mpVal =
1415         g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
1416     return bundle;
1417 }
1418
1419 bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1420 {
1421     bool success = false;
1422
1423     VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1424
1425     success = MainLoop::Instance().Schedule(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
1426
1427 exit:
1428     return success;
1429 }
1430
1431 static gboolean BluezDisconnect(void * apClosure)
1432 {
1433     BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
1434     GError * error         = nullptr;
1435     gboolean success;
1436
1437     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
1438     VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
1439
1440     ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
1441
1442     success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
1443     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
1444
1445 exit:
1446     if (error != nullptr)
1447         g_error_free(error);
1448     return G_SOURCE_REMOVE;
1449 }
1450
1451 static int CloseBleconnectionCB(void * apAppState)
1452 {
1453     BluezDisconnect(apAppState);
1454     return G_SOURCE_REMOVE;
1455 }
1456
1457 bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
1458 {
1459     return MainLoop::Instance().RunOnBluezThread(CloseBleconnectionCB, apConn);
1460 }
1461
1462 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
1463 {
1464     CHIP_ERROR err = CHIP_NO_ERROR;
1465     if (!MainLoop::Instance().Schedule(BluezAdvStart, apEndpoint))
1466     {
1467         err = CHIP_ERROR_INCORRECT_STATE;
1468         ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
1469     }
1470     return err;
1471 }
1472
1473 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
1474 {
1475     CHIP_ERROR err = CHIP_NO_ERROR;
1476     if (!MainLoop::Instance().Schedule(BluezAdvStop, apEndpoint))
1477     {
1478         err = CHIP_ERROR_INCORRECT_STATE;
1479         ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
1480     }
1481     return err;
1482 }
1483
1484 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
1485 {
1486     CHIP_ERROR err = CHIP_NO_ERROR;
1487     if (!MainLoop::Instance().Schedule(BluezAdvSetup, apEndpoint))
1488     {
1489         err = CHIP_ERROR_INCORRECT_STATE;
1490         ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
1491     }
1492     return err;
1493 }
1494
1495 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
1496 {
1497     CHIP_ERROR err = CHIP_NO_ERROR;
1498     if (!MainLoop::Instance().Schedule(BluezPeripheralRegisterApp, apEndpoint))
1499     {
1500         err = CHIP_ERROR_INCORRECT_STATE;
1501         ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
1502     }
1503     return err;
1504 }
1505
1506 CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
1507 {
1508     const char * msg = nullptr;
1509     CHIP_ERROR err   = CHIP_NO_ERROR;
1510     VerifyOrExit(aBleAdvConfig.mpBleName != nullptr, msg = "FAIL: BLE name is NULL");
1511     VerifyOrExit(aBleAdvConfig.mpAdvertisingUUID != nullptr, msg = "FAIL: BLE mpAdvertisingUUID is NULL in %s");
1512
1513     apEndpoint->mpAdapterName     = g_strdup(aBleAdvConfig.mpBleName);
1514     apEndpoint->mpAdvertisingUUID = g_strdup(aBleAdvConfig.mpAdvertisingUUID);
1515     apEndpoint->mAdapterId        = aBleAdvConfig.mAdapterId;
1516     apEndpoint->mType             = aBleAdvConfig.mType;
1517     apEndpoint->mDuration         = aBleAdvConfig.mDuration;
1518     apEndpoint->mDuration         = aBleAdvConfig.mDuration;
1519
1520     err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
1521     SuccessOrExit(err);
1522
1523 exit:
1524     if (nullptr != msg)
1525     {
1526         ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1527         err = CHIP_ERROR_INCORRECT_STATE;
1528     }
1529     return err;
1530 }
1531
1532 CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint)
1533 {
1534     CHIP_ERROR err           = CHIP_NO_ERROR;
1535     bool retval              = false;
1536     BluezEndpoint * endpoint = nullptr;
1537
1538     // initialize server endpoint
1539     endpoint = g_new0(BluezEndpoint, 1);
1540     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
1541
1542     if (apBleAddr != nullptr)
1543         endpoint->mpAdapterAddr = g_strdup(apBleAddr);
1544     else
1545         endpoint->mpAdapterAddr = nullptr;
1546
1547     endpoint->mpConnMap  = g_hash_table_new(g_str_hash, g_str_equal);
1548     endpoint->mIsCentral = aIsCentral;
1549
1550     if (!aIsCentral)
1551     {
1552         err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
1553         SuccessOrExit(err);
1554     }
1555     else
1556     {
1557         endpoint->mAdapterId = aBleAdvConfig.mAdapterId;
1558     }
1559
1560     err = MainLoop::Instance().EnsureStarted();
1561     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start BLE main loop"));
1562
1563     if (!MainLoop::Instance().ScheduleAndWait(StartupEndpointBindings, endpoint))
1564     {
1565         ChipLogError(DeviceLayer, "Failed to schedule endpoint initialization");
1566         ExitNow();
1567     }
1568
1569     retval = TRUE;
1570
1571 exit:
1572     if (retval)
1573     {
1574         apEndpoint = endpoint;
1575         ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
1576     }
1577     else
1578     {
1579         EndpointCleanup(endpoint);
1580     }
1581
1582     return err;
1583 }
1584
1585 // BluezSendWriteRequest callbacks
1586
1587 static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1588 {
1589     BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1590     GError * error                = nullptr;
1591     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error);
1592
1593     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
1594     BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
1595
1596 exit:
1597     if (error != nullptr)
1598         g_error_free(error);
1599 }
1600
1601 static gboolean SendWriteRequestImpl(void * apConnectionData)
1602 {
1603     ConnectionDataBundle * data = static_cast<ConnectionDataBundle *>(apConnectionData);
1604     GVariant * options          = nullptr;
1605     GVariantBuilder optionsBuilder;
1606
1607     VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1608     VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1609     VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__));
1610
1611     g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY);
1612     g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request"));
1613     options = g_variant_builder_end(&optionsBuilder);
1614
1615     bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
1616                                                 data->mpConn);
1617
1618 exit:
1619     g_free(data);
1620     return G_SOURCE_REMOVE;
1621 }
1622
1623 bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1624 {
1625     bool success = false;
1626
1627     VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1628
1629     success = MainLoop::Instance().RunOnBluezThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
1630
1631 exit:
1632     return success;
1633 }
1634
1635 // BluezSubscribeCharacteristic callbacks
1636
1637 static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
1638                                     gpointer apConnection)
1639 {
1640     BLE_CONNECTION_OBJECT connection = static_cast<BLE_CONNECTION_OBJECT>(apConnection);
1641     GVariant * value                 = g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING);
1642     VerifyOrReturn(value != nullptr);
1643
1644     size_t bufferLen;
1645     auto buffer = g_variant_get_fixed_array(value, &bufferLen, sizeof(uint8_t));
1646     VerifyOrReturn(value != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));
1647
1648     BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
1649 }
1650
1651 static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1652 {
1653     BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1654     GError * error                = nullptr;
1655     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1656
1657     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));
1658
1659     // Get notifications on the TX characteristic change (e.g. indication is received)
1660     g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), apConnection);
1661     BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), true);
1662
1663 exit:
1664     if (error != nullptr)
1665         g_error_free(error);
1666 }
1667
1668 static gboolean SubscribeCharacteristicImpl(BluezConnection * connection)
1669 {
1670     VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1671     VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1672
1673     bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);
1674
1675 exit:
1676     return G_SOURCE_REMOVE;
1677 }
1678
1679 bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1680 {
1681     return MainLoop::Instance().Schedule(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1682 }
1683
1684 // BluezUnsubscribeCharacteristic callbacks
1685
1686 static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1687 {
1688     BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1689     GError * error                = nullptr;
1690     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1691
1692     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));
1693
1694     // Stop listening to the TX characteristic changes
1695     g_signal_handlers_disconnect_by_data(c2, apConnection);
1696     BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), false);
1697
1698 exit:
1699     if (error != nullptr)
1700         g_error_free(error);
1701 }
1702
1703 static gboolean UnsubscribeCharacteristicImpl(BluezConnection * connection)
1704 {
1705     VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1706     VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1707
1708     bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);
1709
1710 exit:
1711     return G_SOURCE_REMOVE;
1712 }
1713
1714 bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1715 {
1716     return MainLoop::Instance().Schedule(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1717 }
1718
1719 // ConnectDevice callbacks
1720
1721 static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
1722 {
1723     BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
1724     GError * error        = nullptr;
1725     gboolean success      = bluez_device1_call_connect_finish(device, aResult, &error);
1726
1727     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message));
1728     ChipLogDetail(DeviceLayer, "ConnectDevice complete");
1729
1730 exit:
1731     if (error != nullptr)
1732         g_error_free(error);
1733 }
1734
1735 static gboolean ConnectDeviceImpl(BluezDevice1 * device)
1736 {
1737     VerifyOrExit(device != nullptr, ChipLogError(DeviceLayer, "device is NULL in %s", __func__));
1738
1739     bluez_device1_call_connect(device, nullptr, ConnectDeviceDone, nullptr);
1740     g_object_unref(device);
1741
1742 exit:
1743     return G_SOURCE_REMOVE;
1744 }
1745
1746 CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice)
1747 {
1748     CHIP_ERROR error = CHIP_NO_ERROR;
1749     g_object_ref(apDevice);
1750
1751     if (!MainLoop::Instance().Schedule(ConnectDeviceImpl, apDevice))
1752     {
1753         ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");
1754         g_object_unref(apDevice);
1755         error = CHIP_ERROR_INCORRECT_STATE;
1756     }
1757
1758     return error;
1759 }
1760
1761 } // namespace Internal
1762 } // namespace DeviceLayer
1763 } // namespace chip
1764 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE