Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / Tizen / 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/CHIPMem.h>
58 #include <support/CHIPMemString.h>
59
60 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
61 #include <cassert>
62 #include <errno.h>
63 #include <gio/gunixfdlist.h>
64 #include <limits>
65 #include <stdarg.h>
66 #include <strings.h>
67 #include <unistd.h>
68 #include <utility>
69
70 #include <platform/Linux/BLEManagerImpl.h>
71 #include <support/CodeUtils.h>
72 #include <system/TLVPacketBufferBackingStore.h>
73
74 #include "BluezObjectIterator.h"
75 #include "BluezObjectList.h"
76 #include "Helper.h"
77 #include "MainLoop.h"
78
79 using namespace ::nl;
80 using namespace chip::Protocols;
81 using chip::Platform::CopyString;
82
83 namespace chip {
84 namespace DeviceLayer {
85 namespace Internal {
86
87 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
88
89 namespace {
90
91 class BluezEndpointObjectList : public BluezObjectList
92 {
93 public:
94     explicit BluezEndpointObjectList(BluezEndpoint * apEndpoint)
95     {
96         VerifyOrReturn(apEndpoint != nullptr, ChipLogError(DeviceLayer, "apEndpoint is NULL in %s", __func__));
97         Initialize(apEndpoint->mpObjMgr);
98     }
99 };
100
101 } // namespace
102
103 static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
104 {
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__);
110
111     g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
112     endpoint->mIsAdvertising = false;
113     isSuccess                = true;
114 exit:
115
116     return isSuccess ? TRUE : FALSE;
117 }
118
119 static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
120 {
121     BluezLEAdvertisement1 * adv = nullptr;
122     BluezObjectSkeleton * object;
123     GVariant * serviceData;
124     GVariant * serviceUUID;
125     gchar * localName;
126     GVariantBuilder serviceDataBuilder;
127     GVariantBuilder serviceUUIDsBuilder;
128     char * debugStr;
129
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);
133
134     ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
135     object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
136
137     adv = bluez_leadvertisement1_skeleton_new();
138
139     g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
140     g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
141
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);
146
147     if (apEndpoint->mpAdapterName != nullptr)
148         localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
149     else
150         localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
151
152     serviceData = g_variant_builder_end(&serviceDataBuilder);
153     serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
154
155     debugStr = g_variant_print(serviceData, TRUE);
156     ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
157     g_free(debugStr);
158
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);
163     // empty data
164
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);
171
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);
175
176     // 0xffff means no appearance
177     bluez_leadvertisement1_set_appearance(adv, 0xffff);
178
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
183
184     bluez_object_skeleton_set_leadvertisement1(object, adv);
185     g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
186
187     g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
188     g_object_unref(object);
189
190     BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
191
192 exit:
193     return adv;
194 }
195
196 static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
197 {
198     BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
199     GError * error                      = nullptr;
200     BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
201     gboolean success                    = FALSE;
202
203     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
204
205     success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
206     if (success == FALSE)
207     {
208         g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
209     }
210     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
211
212     endpoint->mIsAdvertising = true;
213
214     ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
215
216 exit:
217     BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
218     if (error != nullptr)
219         g_error_free(error);
220 }
221
222 static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
223 {
224     BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
225     BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
226     GError * error                      = nullptr;
227     gboolean success                    = FALSE;
228
229     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
230
231     success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
232
233     if (success == FALSE)
234     {
235         g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
236     }
237     else
238     {
239         endpoint->mIsAdvertising = false;
240     }
241
242     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
243
244     ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
245
246 exit:
247     BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
248     if (error != nullptr)
249         g_error_free(error);
250 }
251
252 static gboolean BluezAdvSetup(BluezEndpoint * endpoint)
253 {
254     BluezLEAdvertisement1 * adv;
255
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__));
259
260     adv = BluezAdvertisingCreate(endpoint);
261     VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
262
263 exit:
264     return G_SOURCE_REMOVE;
265 }
266
267 static gboolean BluezAdvStart(BluezEndpoint * endpoint)
268 {
269     GDBusObject * adapter;
270     BluezLEAdvertisingManager1 * advMgr = nullptr;
271     GVariantBuilder optionsBuilder;
272     GVariant * options;
273
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__));
278
279     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
280     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
281
282     advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
283     VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
284
285     g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
286     options = g_variant_builder_end(&optionsBuilder);
287
288     bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
289                                                              endpoint);
290
291 exit:
292     return G_SOURCE_REMOVE;
293 }
294
295 static gboolean BluezAdvStop(BluezEndpoint * endpoint)
296 {
297     GDBusObject * adapter;
298     BluezLEAdvertisingManager1 * advMgr = nullptr;
299
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__));
304
305     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
306     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
307
308     advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
309     VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
310
311     bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, endpoint);
312
313 exit:
314     return G_SOURCE_REMOVE;
315 }
316
317 static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
318                                              GVariant * aOptions)
319 {
320     GVariant * val;
321     ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
322     val = bluez_gatt_characteristic1_get_value(aChar);
323     bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
324     return TRUE;
325 }
326
327 #if CHIP_BLUEZ_CHAR_WRITE_VALUE
328 static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
329                                               GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
330 {
331     const uint8_t * tmpBuf;
332     uint8_t * buf;
333     size_t len;
334     bool isSuccess         = false;
335     BluezConnection * conn = NULL;
336
337     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
338     VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
339
340     VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
341
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"));
345
346     bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
347
348     tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
349     buf    = (uint8_t *) (g_memdup(tmpBuf, len));
350
351     BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
352     bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
353     isSuccess = true;
354
355 exit:
356     return isSuccess ? TRUE : FALSE;
357 }
358 #endif
359
360 static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
361                                                    GVariant * aValue, GVariant * aOptions, gpointer apClosure)
362 {
363     ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
364     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
365                                                "Write for characteristic is unsupported");
366     return TRUE;
367 }
368
369 static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
370 {
371     GVariant * newVal;
372     gchar * buf;
373     ssize_t len;
374     int fd;
375     bool isSuccess = false;
376
377     BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
378
379     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
380
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__));
384
385     ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
386
387     buf = static_cast<gchar *>(g_malloc(conn->mMtu));
388     fd  = g_io_channel_unix_get_fd(aChannel);
389
390     len = read(fd, buf, conn->mMtu);
391
392     VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
393
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));
396
397     bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
398     BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
399     isSuccess = true;
400
401 exit:
402     return isSuccess ? TRUE : FALSE;
403 }
404
405 static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
406 {
407     GUnixFDList * fd_list = g_unix_fd_list_new();
408     int index;
409
410     index = g_unix_fd_list_append(fd_list, fd, nullptr);
411
412     g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
413                                                             fd_list);
414 }
415
416 static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
417 {
418     return G_SOURCE_REMOVE;
419 }
420
421 static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
422                                                 GVariant * aOptions, gpointer apEndpoint)
423 {
424     int fds[2] = { -1, -1 };
425     GIOChannel * channel;
426     char * errStr;
427     GVariantDict options;
428     bool isSuccess         = false;
429     BluezConnection * conn = nullptr;
430
431     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
432     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
433
434     conn = GetBluezConnectionViaDevice(endpoint);
435     VerifyOrExit(conn != nullptr,
436                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
437
438     ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
439
440     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
441     {
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);
446     }
447
448     g_variant_dict_init(&options, aOptions);
449     if (g_variant_dict_contains(&options, "mtu") == TRUE)
450     {
451         GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
452         conn->mMtu   = g_variant_get_uint16(v);
453     }
454     else
455     {
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);
459     }
460
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);
465
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);
469
470     bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
471
472     Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
473     close(fds[1]);
474     isSuccess = true;
475
476 exit:
477     return isSuccess ? TRUE : FALSE;
478 }
479
480 static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
481                                                      GVariant * aOptions)
482 {
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");
486     return TRUE;
487 }
488
489 static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
490                                                  GVariant * aOptions, gpointer apEndpoint)
491 {
492     int fds[2] = { -1, -1 };
493     GIOChannel * channel;
494     char * errStr;
495     GVariantDict options;
496     BluezConnection * conn = nullptr;
497     bool isSuccess         = false;
498
499     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
500     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
501
502     conn = GetBluezConnectionViaDevice(endpoint);
503     VerifyOrExit(conn != nullptr,
504                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
505
506     g_variant_dict_init(&options, aOptions);
507     if ((g_variant_dict_contains(&options, "mtu") == TRUE))
508     {
509         GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
510         conn->mMtu   = g_variant_get_uint16(v);
511     }
512
513     if (bluez_gatt_characteristic1_get_notifying(aChar))
514     {
515         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
516     }
517     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
518     {
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);
523     }
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);
532
533     bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
534
535     // same reply as for AcquireWrite
536     Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
537     close(fds[1]);
538
539     conn->mIsNotify = true;
540     BLEManagerImpl::HandleTXCharCCCDWrite(conn);
541     isSuccess = true;
542
543 exit:
544     return isSuccess ? TRUE : FALSE;
545 }
546
547 static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
548                                                       GVariant * aOptions)
549 {
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");
553     return TRUE;
554 }
555
556 static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
557                                                gpointer apEndpoint)
558 {
559     bool isSuccess         = false;
560     BluezConnection * conn = nullptr;
561
562     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
563     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
564
565     conn = GetBluezConnectionViaDevice(endpoint);
566     VerifyOrExit(conn != nullptr,
567                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
568
569     if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
570     {
571         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
572     }
573     else
574     {
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);
579     }
580     isSuccess = true;
581
582 exit:
583     return isSuccess ? TRUE : FALSE;
584 }
585
586 static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
587 {
588     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
589                                                "Subscribing to characteristic is unsupported");
590     return TRUE;
591 }
592
593 static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
594                                               gpointer apEndpoint)
595 {
596     bool isSuccess         = false;
597     BluezConnection * conn = nullptr;
598
599     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
600     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
601
602     conn = GetBluezConnectionViaDevice(endpoint);
603     VerifyOrExit(conn != nullptr,
604                  g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
605
606     if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
607     {
608         g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
609     }
610     else
611     {
612         bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
613         bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
614     }
615     conn->mIsNotify = false;
616
617     isSuccess = true;
618
619 exit:
620     return isSuccess ? TRUE : FALSE;
621 }
622
623 static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
624                                            gpointer apClosure)
625 {
626     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
627     BluezConnection * conn   = GetBluezConnectionViaDevice(endpoint);
628
629     ChipLogDetail(Ble, "Indication confirmation, %p", conn);
630     BLEManagerImpl::HandleTXComplete(conn);
631
632     return TRUE;
633 }
634
635 static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
636 {
637     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
638                                                "Unsubscribing from characteristic is unsupported");
639     return TRUE;
640 }
641
642 static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
643 {
644     g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
645     return TRUE;
646 }
647
648 static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
649 {
650     return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
651 }
652
653 static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
654 {
655     return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
656                                                                                                                       : FALSE;
657 }
658
659 static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
660 {
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
664                                                                                                                             : FALSE;
665 }
666
667 static void BluezConnectionInit(BluezConnection * apConn)
668 {
669     // populate the service and the characteristics
670     GList * objects = nullptr;
671     GList * l;
672     BluezEndpoint * endpoint = nullptr;
673
674     VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
675
676     endpoint = apConn->mpEndpoint;
677     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
678
679     if (!endpoint->mIsCentral)
680     {
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));
684     }
685     else
686     {
687         objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
688
689         for (l = objects; l != nullptr; l = l->next)
690         {
691             BluezObject * object        = BLUEZ_OBJECT(l->data);
692             BluezGattService1 * service = bluez_object_get_gatt_service1(object);
693
694             if (service != nullptr)
695             {
696                 if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
697                     (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
698                 {
699                     apConn->mpService = service;
700                     break;
701                 }
702                 g_object_unref(service);
703             }
704         }
705
706         VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
707
708         for (l = objects; l != nullptr; l = l->next)
709         {
710             BluezObject * object             = BLUEZ_OBJECT(l->data);
711             BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
712
713             if (char1 != nullptr)
714             {
715                 if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
716                     (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
717                 {
718                     apConn->mpC1 = char1;
719                 }
720                 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
721                          (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
722                 {
723                     apConn->mpC2 = char1;
724                 }
725                 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
726                          (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0))
727                 {
728                     apConn->mpC3 = char1;
729                 }
730                 else
731                 {
732                     g_object_unref(char1);
733                 }
734                 if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
735                 {
736                     break;
737                 }
738             }
739         }
740
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__));
743     }
744
745 exit:
746     if (objects != nullptr)
747         g_list_free_full(objects, g_object_unref);
748 }
749
750 static void BluezOTConnectionDestroy(BluezConnection * aConn)
751 {
752     if (aConn)
753     {
754         if (aConn->mpDevice)
755             g_object_unref(aConn->mpDevice);
756         if (aConn->mpService)
757             g_object_unref(aConn->mpService);
758         if (aConn->mpC1)
759             g_object_unref(aConn->mpC1);
760         if (aConn->mpC2)
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);
772
773         g_free(aConn);
774     }
775 }
776
777 static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
778                                                             const char * aUUID, GDBusObjectManagerServer * aRoot)
779 {
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;
784
785     ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
786     object = bluez_object_skeleton_new(charPath);
787
788     characteristic = bluez_gatt_characteristic1_skeleton_new();
789     bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
790     bluez_gatt_characteristic1_set_service(characteristic, servicePath);
791
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);
795
796     return characteristic;
797 }
798
799 static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
800 {
801     GError * error              = nullptr;
802     BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
803
804     gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
805
806     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
807
808     BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
809     ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
810
811 exit:
812     if (error != nullptr)
813     {
814         BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
815         g_error_free(error);
816     }
817 }
818
819 gboolean BluezPeripheralRegisterApp(BluezEndpoint * endpoint)
820 {
821     GDBusObject * adapter;
822     BluezGattManager1 * gattMgr;
823     GVariantBuilder optionsBuilder;
824     GVariant * options;
825
826     VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
827
828     adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
829     VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
830
831     gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
832     VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
833
834     g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
835     options = g_variant_builder_end(&optionsBuilder);
836
837     bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
838                                                   nullptr);
839
840 exit:
841     return G_SOURCE_REMOVE;
842 }
843
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)
846 {
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));
849
850     if (connection != nullptr && !bluez_device1_get_connected(apDevice))
851     {
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);
858         return;
859     }
860
861     if (connection == nullptr && !bluez_device1_get_connected(apDevice) && aEndpoint.mIsCentral)
862     {
863         return;
864     }
865
866     if (connection == nullptr && bluez_device1_get_connected(apDevice) &&
867         (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice)))
868     {
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);
876
877         ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
878                       aEndpoint.mpPeerDevicePath);
879
880         BLEManagerImpl::HandleNewConnection(connection);
881     }
882 }
883
884 static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
885                                                   GDBusProxy * aInterface, GVariant * aChangedProperties,
886                                                   const gchar * const * aInvalidatedProps, gpointer apClosure)
887 {
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, );
892
893     BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
894     VerifyOrReturn(BluezIsDeviceOnAdapter(device, endpoint->mpAdapter));
895
896     UpdateConnectionTable(device, *endpoint);
897 }
898
899 static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
900 {
901     VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
902     if (apEndpoint->mIsCentral)
903     {
904         return;
905     }
906
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"));
913
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))));
919
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);
928
929 exit:
930     return;
931 }
932
933 static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, BluezEndpoint * endpoint)
934 {
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)
939     {
940         return;
941     }
942
943     if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
944     {
945         BluezHandleNewDevice(device, endpoint);
946     }
947
948     g_object_unref(device);
949 }
950
951 static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
952 {
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.
956 }
957
958 static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
959 {
960     BluezObjectSkeleton * object;
961     BluezGattService1 * service;
962     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
963
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);
967
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);
972
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);
977
978     return service;
979 }
980
981 static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
982 {
983     GList * objects = nullptr;
984     GList * l;
985     char * expectedPath = nullptr;
986
987     VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
988
989     expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mAdapterId);
990     objects      = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
991
992     for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
993     {
994         BluezObject * object = BLUEZ_OBJECT(l->data);
995         GList * interfaces;
996         GList * ll;
997         interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
998
999         for (ll = interfaces; ll != nullptr; ll = ll->next)
1000         {
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
1006                 {
1007                     if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
1008                     {
1009                         apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1010                     }
1011                 }
1012                 else
1013                 {
1014                     if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
1015                     {
1016                         apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1017                     }
1018                 }
1019             }
1020         }
1021         g_list_free_full(interfaces, g_object_unref);
1022     }
1023     VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
1024     bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
1025
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);
1030
1031 exit:
1032     g_list_free_full(objects, g_object_unref);
1033     g_free(expectedPath);
1034 }
1035
1036 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
1037 {
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__);
1041     return retval;
1042 }
1043
1044 #if CHIP_BLUEZ_CENTRAL_SUPPORT
1045 static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
1046                                                                BluezEndpoint * apEndpoint)
1047 {
1048     BluezConnection * retval = NULL;
1049     const gchar * path       = NULL;
1050     GVariantDict options;
1051     GVariant * v;
1052
1053     VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1054     VerifyOrExit(apEndpoint->mIsCentral, );
1055
1056     /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
1057      * peer device in call params so we need look this up ourselves.
1058      */
1059     if (aOptions == NULL)
1060     {
1061         GList * objects;
1062         GList * l;
1063         GList * ll;
1064
1065         objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1066         for (l = objects; l != NULL; l = l->next)
1067         {
1068             BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
1069             if (device != NULL)
1070             {
1071                 if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
1072                 {
1073                     for (ll = objects; ll != NULL; ll = ll->next)
1074                     {
1075                         BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
1076                         if (service != NULL)
1077                         {
1078                             if (BluezIsServiceOnDevice(service, device))
1079                             {
1080                                 if (BluezIsCharOnService(aChar, service))
1081                                 {
1082                                     retval = (BluezConnection *) g_hash_table_lookup(
1083                                         apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1084                                 }
1085                             }
1086                             g_object_unref(service);
1087                             if (retval != NULL)
1088                                 break;
1089                         }
1090                     }
1091                 }
1092                 g_object_unref(device);
1093                 if (retval != NULL)
1094                     break;
1095             }
1096         }
1097
1098         g_list_free_full(objects, g_object_unref);
1099     }
1100     else
1101     {
1102         g_variant_dict_init(&options, aOptions);
1103
1104         v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
1105
1106         VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
1107
1108         path = g_variant_get_string(v, NULL);
1109
1110         retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
1111     }
1112
1113 exit:
1114     return retval;
1115 }
1116 #endif // CHIP_BLUEZ_CENTRAL_SUPPORT
1117
1118 void EndpointCleanup(BluezEndpoint * apEndpoint)
1119 {
1120     if (apEndpoint != nullptr)
1121     {
1122         if (apEndpoint->mpOwningName != nullptr)
1123         {
1124             g_free(apEndpoint->mpOwningName);
1125             apEndpoint->mpOwningName = nullptr;
1126         }
1127         if (apEndpoint->mpAdapterName != nullptr)
1128         {
1129             g_free(apEndpoint->mpAdapterName);
1130             apEndpoint->mpAdapterName = nullptr;
1131         }
1132         if (apEndpoint->mpAdapterAddr != nullptr)
1133         {
1134             g_free(apEndpoint->mpAdapterAddr);
1135             apEndpoint->mpAdapterAddr = nullptr;
1136         }
1137         if (apEndpoint->mpRootPath != nullptr)
1138         {
1139             g_free(apEndpoint->mpRootPath);
1140             apEndpoint->mpRootPath = nullptr;
1141         }
1142         if (apEndpoint->mpAdvPath != nullptr)
1143         {
1144             g_free(apEndpoint->mpAdvPath);
1145             apEndpoint->mpAdvPath = nullptr;
1146         }
1147         if (apEndpoint->mpServicePath != nullptr)
1148         {
1149             g_free(apEndpoint->mpServicePath);
1150             apEndpoint->mpServicePath = nullptr;
1151         }
1152         if (apEndpoint->mpConnMap != nullptr)
1153         {
1154             g_hash_table_destroy(apEndpoint->mpConnMap);
1155             apEndpoint->mpConnMap = nullptr;
1156         }
1157         if (apEndpoint->mpAdvertisingUUID != nullptr)
1158         {
1159             g_free(apEndpoint->mpAdvertisingUUID);
1160             apEndpoint->mpAdvertisingUUID = nullptr;
1161         }
1162         if (apEndpoint->mpPeerDevicePath != nullptr)
1163         {
1164             g_free(apEndpoint->mpPeerDevicePath);
1165             apEndpoint->mpPeerDevicePath = nullptr;
1166         }
1167         g_free(apEndpoint->mpConnectCancellable);
1168         g_free(apEndpoint);
1169     }
1170 }
1171
1172 int BluezObjectsCleanup(BluezEndpoint * apEndpoint)
1173 {
1174     g_object_unref(apEndpoint->mpAdapter);
1175     EndpointCleanup(apEndpoint);
1176     return 0;
1177 }
1178
1179 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1180 static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic)
1181 {
1182     if (characteristic == nullptr)
1183     {
1184         return;
1185     }
1186
1187     // Construct the TLV for the additional data
1188     GVariant * cValue = nullptr;
1189     gpointer data;
1190     CHIP_ERROR err = CHIP_NO_ERROR;
1191     chip::System::PacketBufferHandle bufferHandle;
1192
1193     char serialNumber[ConfigurationManager::kMaxSerialNumberLength + 1];
1194     size_t serialNumberSize  = 0;
1195     uint16_t lifetimeCounter = 0;
1196     BitFlags<AdditionalDataFields> additionalDataFields;
1197
1198 #if CHIP_ENABLE_ROTATING_DEVICE_ID
1199     err = ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize);
1200     SuccessOrExit(err);
1201     err = ConfigurationMgr().GetLifetimeCounter(lifetimeCounter);
1202     SuccessOrExit(err);
1203
1204     additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
1205 #endif
1206
1207     err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(lifetimeCounter, serialNumber, serialNumberSize,
1208                                                                          bufferHandle, additionalDataFields);
1209     SuccessOrExit(err);
1210
1211     data = g_memdup(bufferHandle->Start(), bufferHandle->DataLength());
1212
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);
1215
1216     return;
1217
1218 exit:
1219     if (err != CHIP_NO_ERROR)
1220     {
1221         ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__);
1222     }
1223     return;
1224 }
1225 #endif
1226
1227 static void BluezPeripheralObjectsSetup(gpointer apClosure)
1228 {
1229
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 };
1233
1234     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1235     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1236
1237     endpoint->mpService = BluezServiceCreate(apClosure);
1238     // C1 characteristic
1239     endpoint->mpC1 =
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);
1242
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);
1250
1251     endpoint->mpC2 =
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);
1261
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));
1264
1265 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1266     ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
1267     // Additional data characteristics
1268     endpoint->mpC3 =
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));
1281 #else
1282     ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is FALSE");
1283     (void) c3_flags;
1284 #endif
1285
1286 exit:
1287     return;
1288 }
1289
1290 static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1291 {
1292     BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1293     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1294
1295     ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
1296
1297     if (!endpoint->mIsCentral)
1298     {
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);
1302
1303         BluezPeripheralObjectsSetup(apClosure);
1304     }
1305
1306 exit:
1307     return;
1308 }
1309
1310 #if CHIP_BLUEZ_NAME_MONITOR
1311 static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1312 {
1313     ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
1314 }
1315
1316 static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1317 {
1318     ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
1319 }
1320 #endif
1321
1322 static int StartupEndpointBindings(BluezEndpoint * endpoint)
1323 {
1324     GDBusObjectManager * manager;
1325     GError * error         = nullptr;
1326     GDBusConnection * conn = nullptr;
1327     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1328
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));
1331
1332     if (endpoint->mpAdapterName != nullptr)
1333         endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
1334     else
1335         endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
1336
1337     BluezOnBusAcquired(conn, endpoint->mpOwningName, endpoint);
1338
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);
1342
1343     VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
1344
1345     endpoint->mpObjMgr = manager;
1346
1347     bluezObjectsSetup(endpoint);
1348
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);
1352
1353     if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint))
1354     {
1355         ChipLogError(DeviceLayer, "Failed to schedule cleanup function");
1356     }
1357
1358 exit:
1359     if (error != nullptr)
1360         g_error_free(error);
1361
1362     return 0;
1363 }
1364
1365 static gboolean BluezC2Indicate(ConnectionDataBundle * closure)
1366 {
1367     BluezConnection * conn = nullptr;
1368     GError * error         = nullptr;
1369     GIOStatus status;
1370     const char * buf;
1371     size_t len, written;
1372
1373     VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1374
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"));
1378
1379     if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
1380     {
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;
1387
1388         VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
1389     }
1390     else
1391     {
1392         bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
1393         closure->mpVal = nullptr;
1394     }
1395
1396 exit:
1397     if (closure != nullptr)
1398     {
1399         if (closure->mpVal)
1400         {
1401             g_variant_unref(closure->mpVal);
1402         }
1403         g_free(closure);
1404     }
1405
1406     if (error != nullptr)
1407         g_error_free(error);
1408     return G_SOURCE_REMOVE;
1409 }
1410
1411 static ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, const chip::System::PacketBufferHandle & apBuf)
1412 {
1413     ConnectionDataBundle * bundle = g_new(ConnectionDataBundle, 1);
1414     bundle->mpConn                = static_cast<BluezConnection *>(apConn);
1415     bundle->mpVal =
1416         g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
1417     return bundle;
1418 }
1419
1420 bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1421 {
1422     bool success = false;
1423
1424     VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1425
1426     success = MainLoop::Instance().Schedule(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
1427
1428 exit:
1429     return success;
1430 }
1431
1432 static gboolean BluezDisconnect(void * apClosure)
1433 {
1434     BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
1435     GError * error         = nullptr;
1436     gboolean success;
1437
1438     VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
1439     VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
1440
1441     ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
1442
1443     success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
1444     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
1445
1446 exit:
1447     if (error != nullptr)
1448         g_error_free(error);
1449     return G_SOURCE_REMOVE;
1450 }
1451
1452 static int CloseBleconnectionCB(void * apAppState)
1453 {
1454     BluezDisconnect(apAppState);
1455     return G_SOURCE_REMOVE;
1456 }
1457
1458 bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
1459 {
1460     return MainLoop::Instance().RunOnBluezThread(CloseBleconnectionCB, apConn);
1461 }
1462
1463 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
1464 {
1465     CHIP_ERROR err = CHIP_NO_ERROR;
1466     if (!MainLoop::Instance().Schedule(BluezAdvStart, apEndpoint))
1467     {
1468         err = CHIP_ERROR_INCORRECT_STATE;
1469         ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
1470     }
1471     return err;
1472 }
1473
1474 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
1475 {
1476     CHIP_ERROR err = CHIP_NO_ERROR;
1477     if (!MainLoop::Instance().Schedule(BluezAdvStop, apEndpoint))
1478     {
1479         err = CHIP_ERROR_INCORRECT_STATE;
1480         ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
1481     }
1482     return err;
1483 }
1484
1485 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
1486 {
1487     CHIP_ERROR err = CHIP_NO_ERROR;
1488     if (!MainLoop::Instance().Schedule(BluezAdvSetup, apEndpoint))
1489     {
1490         err = CHIP_ERROR_INCORRECT_STATE;
1491         ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
1492     }
1493     return err;
1494 }
1495
1496 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
1497 {
1498     CHIP_ERROR err = CHIP_NO_ERROR;
1499     if (!MainLoop::Instance().Schedule(BluezPeripheralRegisterApp, apEndpoint))
1500     {
1501         err = CHIP_ERROR_INCORRECT_STATE;
1502         ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
1503     }
1504     return err;
1505 }
1506
1507 CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
1508 {
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");
1513
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;
1520
1521     err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
1522     SuccessOrExit(err);
1523
1524 exit:
1525     if (nullptr != msg)
1526     {
1527         ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1528         err = CHIP_ERROR_INCORRECT_STATE;
1529     }
1530     return err;
1531 }
1532
1533 CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint)
1534 {
1535     CHIP_ERROR err           = CHIP_NO_ERROR;
1536     bool retval              = false;
1537     BluezEndpoint * endpoint = nullptr;
1538
1539     // initialize server endpoint
1540     endpoint = g_new0(BluezEndpoint, 1);
1541     VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
1542
1543     if (apBleAddr != nullptr)
1544         endpoint->mpAdapterAddr = g_strdup(apBleAddr);
1545     else
1546         endpoint->mpAdapterAddr = nullptr;
1547
1548     endpoint->mpConnMap  = g_hash_table_new(g_str_hash, g_str_equal);
1549     endpoint->mIsCentral = aIsCentral;
1550
1551     if (!aIsCentral)
1552     {
1553         err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
1554         SuccessOrExit(err);
1555     }
1556     else
1557     {
1558         endpoint->mAdapterId           = aBleAdvConfig.mAdapterId;
1559         endpoint->mpConnectCancellable = g_cancellable_new();
1560     }
1561
1562     err = MainLoop::Instance().EnsureStarted();
1563     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start BLE main loop"));
1564
1565     if (!MainLoop::Instance().ScheduleAndWait(StartupEndpointBindings, endpoint))
1566     {
1567         ChipLogError(DeviceLayer, "Failed to schedule endpoint initialization");
1568         ExitNow();
1569     }
1570
1571     retval = TRUE;
1572
1573 exit:
1574     if (retval)
1575     {
1576         apEndpoint = endpoint;
1577         ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
1578     }
1579     else
1580     {
1581         EndpointCleanup(endpoint);
1582     }
1583
1584     return err;
1585 }
1586
1587 // BluezSendWriteRequest callbacks
1588
1589 static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1590 {
1591     BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1592     GError * error                = nullptr;
1593     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error);
1594
1595     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
1596     BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
1597
1598 exit:
1599     if (error != nullptr)
1600         g_error_free(error);
1601 }
1602
1603 static gboolean SendWriteRequestImpl(void * apConnectionData)
1604 {
1605     ConnectionDataBundle * data = static_cast<ConnectionDataBundle *>(apConnectionData);
1606     GVariant * options          = nullptr;
1607     GVariantBuilder optionsBuilder;
1608
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__));
1612
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);
1616
1617     bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
1618                                                 data->mpConn);
1619
1620 exit:
1621     g_free(data);
1622     return G_SOURCE_REMOVE;
1623 }
1624
1625 bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1626 {
1627     bool success = false;
1628
1629     VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1630
1631     success = MainLoop::Instance().RunOnBluezThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
1632
1633 exit:
1634     return success;
1635 }
1636
1637 // BluezSubscribeCharacteristic callbacks
1638
1639 static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
1640                                     gpointer apConnection)
1641 {
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);
1645
1646     size_t bufferLen;
1647     auto buffer = g_variant_get_fixed_array(value, &bufferLen, sizeof(uint8_t));
1648     VerifyOrReturn(value != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));
1649
1650     BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
1651 }
1652
1653 static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1654 {
1655     BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1656     GError * error                = nullptr;
1657     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1658
1659     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));
1660
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);
1664
1665 exit:
1666     if (error != nullptr)
1667         g_error_free(error);
1668 }
1669
1670 static gboolean SubscribeCharacteristicImpl(BluezConnection * connection)
1671 {
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__));
1674
1675     bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);
1676
1677 exit:
1678     return G_SOURCE_REMOVE;
1679 }
1680
1681 bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1682 {
1683     return MainLoop::Instance().Schedule(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1684 }
1685
1686 // BluezUnsubscribeCharacteristic callbacks
1687
1688 static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1689 {
1690     BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1691     GError * error                = nullptr;
1692     gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1693
1694     VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));
1695
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);
1699
1700 exit:
1701     if (error != nullptr)
1702         g_error_free(error);
1703 }
1704
1705 static gboolean UnsubscribeCharacteristicImpl(BluezConnection * connection)
1706 {
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__));
1709
1710     bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);
1711
1712 exit:
1713     return G_SOURCE_REMOVE;
1714 }
1715
1716 bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1717 {
1718     return MainLoop::Instance().Schedule(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1719 }
1720
1721 // ConnectDevice callbacks
1722
1723 struct ConnectParams
1724 {
1725     ConnectParams(BluezDevice1 * device, BluezEndpoint * endpoint) : mDevice(device), mEndpoint(endpoint) {}
1726     BluezDevice1 * mDevice;
1727     BluezEndpoint * mEndpoint;
1728 };
1729
1730 static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
1731 {
1732     BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
1733     GError * error        = nullptr;
1734     gboolean success      = bluez_device1_call_connect_finish(device, aResult, &error);
1735
1736     if (!success)
1737     {
1738         ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message);
1739         BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_INTERNAL);
1740         ExitNow();
1741     }
1742
1743     ChipLogDetail(DeviceLayer, "ConnectDevice complete");
1744
1745 exit:
1746     if (error != nullptr)
1747         g_error_free(error);
1748 }
1749
1750 static gboolean ConnectDeviceImpl(ConnectParams * apParams)
1751 {
1752     BluezDevice1 * device    = apParams->mDevice;
1753     BluezEndpoint * endpoint = apParams->mEndpoint;
1754
1755     assert(device != nullptr);
1756     assert(endpoint != nullptr);
1757
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);
1762
1763     return G_SOURCE_REMOVE;
1764 }
1765
1766 CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice, BluezEndpoint * apEndpoint)
1767 {
1768     auto params = chip::Platform::New<ConnectParams>(apDevice, apEndpoint);
1769     g_object_ref(apDevice);
1770
1771     if (!MainLoop::Instance().Schedule(ConnectDeviceImpl, params))
1772     {
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;
1777     }
1778
1779     return CHIP_NO_ERROR;
1780 }
1781
1782 void CancelConnect(BluezEndpoint * apEndpoint)
1783 {
1784     assert(apEndpoint->mpConnectCancellable != nullptr);
1785     g_cancellable_cancel(apEndpoint->mpConnectCancellable);
1786 }
1787
1788 } // namespace Internal
1789 } // namespace DeviceLayer
1790 } // namespace chip
1791 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE