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