2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include<glib/gprintf.h>
25 #include "bt-common.h"
27 #define NUMBER_OF_FLAGS 10
29 GDBusConnection *g_conn;
32 static gboolean new_service = FALSE;
33 static gboolean new_char = FALSE;
34 static int serv_id = 1;
35 static int register_pending_cnt = 0;
37 /* Introspection data for the service we are exporting */
38 static const gchar service_introspection_xml[] =
40 " <interface name='org.freedesktop.DBus.Properties'>"
41 " <property type='s' name='UUID' access='read'>"
43 " <property type='b' name='primary' access='read'>"
45 " <property type='o' name='Device' access='read'>"
47 " <property type='ao' name='Characteristics' access='read'>"
49 " <property type='s' name='Includes' access='read'>"
54 /* Introspection data for the characteristics we are exporting */
55 static const gchar characteristics_introspection_xml[] =
57 " <interface name='org.bluez.GattCharacteristic1'>"
58 " <method name='ReadValue'>"
59 " <arg type='s' name='address' direction='in'/>"
60 " <arg type='y' name='id' direction='in'/>"
61 " <arg type='q' name='offset' direction='in'/>"
62 " <arg type='ay' name='Value' direction='out'/>"
64 " <method name='WriteValue'>"
65 " <arg type='s' name='address' direction='in'/>"
66 " <arg type='y' name='id' direction='in'/>"
67 " <arg type='q' name='offset' direction='in'/>"
68 " <arg type='ay' name='value' direction='in'/>"
70 " <method name='StartNotify'>"
72 " <method name='StopNotify'>"
74 " <method name='IndicateConfirm'>"
75 " <arg type='s' name='address' direction='in'/>"
76 " <arg type='b' name='complete' direction='in'/>"
79 " <interface name='org.freedesktop.DBus.Properties'>"
80 " <property type='s' name='UUID' access='read'>"
82 " <property type='o' name='Service' access='read'>"
84 " <property type='ay' name='Value' access='readwrite'>"
86 " <property type='b' name='Notifying' access='read'>"
88 " <property type='as' name='Flags' access='read'>"
90 " <property type='s' name='Unicast' access='read'>"
92 " <property type='ao' name='Descriptors' access='read'>"
97 /* Introspection data for the descriptor we are exporting */
98 static const gchar descriptor_introspection_xml[] =
100 " <interface name='org.bluez.GattDescriptor1'>"
101 " <method name='ReadValue'>"
102 " <arg type='s' name='address' direction='in'/>"
103 " <arg type='y' name='id' direction='in'/>"
104 " <arg type='q' name='offset' direction='in'/>"
105 " <arg type='ay' name='Value' direction='out'/>"
107 " <method name='WriteValue'>"
108 " <arg type='s' name='address' direction='in'/>"
109 " <arg type='y' name='id' direction='in'/>"
110 " <arg type='q' name='offset' direction='in'/>"
111 " <arg type='ay' name='value' direction='in'/>"
114 " <interface name='org.freedesktop.DBus.Properties'>"
115 " <property type='s' name='UUID' access='read'>"
117 " <property type='o' name='Characteristic' access='read'>"
119 " <property type='ay' name='Value' access='read'>"
121 " <property type='as' name='Flags' access='read'>"
126 static const gchar manager_introspection_xml[] =
128 " <interface name='org.freedesktop.DBus.ObjectManager'>"
129 " <method name='GetManagedObjects'>"
130 " <arg type='a{oa{sa{sv}}}' name='object_paths_interfaces_and_properties' direction='out'/>"
135 struct gatt_service_info {
142 gboolean is_svc_registered;
143 gboolean is_svc_primary;
146 struct gatt_char_info {
151 gchar *char_flags[NUMBER_OF_FLAGS];
157 struct gatt_desc_info {
162 gchar *desc_flags[NUMBER_OF_FLAGS];
167 struct gatt_req_info {
172 GDBusMethodInvocation *context;
175 static GSList *gatt_services = NULL;
176 static GSList *gatt_requests = NULL;
177 static gchar *app_path = NULL;
179 #define BT_GATT_SERVICE_NAME "org.frwk.gatt_service"
180 #define BT_GATT_SERVICE_PATH "/org/frwk/gatt_service"
182 #define GATT_SERV_OBJECT_PATH "/service"
184 #define GATT_MNGR_INTERFACE "org.bluez.GattManager1"
185 #define GATT_SERV_INTERFACE "org.bluez.GattService1"
186 #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
187 #define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1"
190 #define BT_HPS_OBJECT_PATH "/org/projectx/httpproxy"
191 #define BT_HPS_INTERFACE_NAME "org.projectx.httpproxy_service"
192 #define PROPERTIES_CHANGED "PropertiesChanged"
193 #define BT_HPS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
196 static GDBusProxy *manager_gproxy = NULL;
198 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
199 const char *service_path, const char *char_path);
200 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
201 const char *serv_path, const char *char_path,
202 const char *desc_path);
204 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id);
207 static int __bt_send_event_to_hps(int event, GVariant *var)
209 GError *error = NULL;
210 GVariant *parameters;
211 GDBusMessage *msg = NULL;
215 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
217 if (event == BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED) {
218 GVariantBuilder *inner_builder;
219 GVariantBuilder *invalidated_builder;
221 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
222 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
224 g_variant_builder_add(inner_builder, "{sv}", "WriteValue", var);
226 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
228 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
229 g_variant_builder_unref(invalidated_builder);
230 g_variant_builder_unref(inner_builder);
231 } else if (BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) {
232 GVariantBuilder *inner_builder;
233 GVariantBuilder *invalidated_builder;
235 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
236 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
238 g_variant_builder_add(inner_builder, "{sv}", "ReadValue", var);
240 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
242 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
243 g_variant_builder_unref(invalidated_builder);
244 g_variant_builder_unref(inner_builder);
247 msg = g_dbus_message_new_signal(BT_HPS_OBJECT_PATH, BT_HPS_INTERFACE_NAME, PROPERTIES_CHANGED);
248 g_dbus_message_set_body(msg, parameters);
249 if (!g_dbus_connection_send_message(g_conn, msg,G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) {
251 BT_ERR("D-Bus API failure: errCode[%x], \
253 error->code, error->message);
254 g_clear_error(&error);
256 return BLUETOOTH_ERROR_INTERNAL;
258 return BLUETOOTH_ERROR_NONE;
262 static void __bt_gatt_manager_method_call(GDBusConnection *connection,
264 const gchar *object_path,
265 const gchar *interface_name,
266 const gchar *method_name,
267 GVariant *parameters,
268 GDBusMethodInvocation *invocation,
275 if (g_strcmp0(method_name, "GetManagedObjects") == 0) {
276 BT_DBG("Getting values for service, chars and descriptors");
278 GVariantBuilder *builder;
279 GVariantBuilder *inner_builder1 = NULL;
280 GVariant *svc_char = NULL;
283 builder = g_variant_builder_new(
284 G_VARIANT_TYPE("a{oa{sa{sv}}}"));
286 /* Prepare inner builder for GattService1 interface */
288 len = g_slist_length(gatt_services);
290 for (i = 0; i <= len; i++) {
291 GVariantBuilder *svc_builder = NULL;
292 GVariantBuilder *inner_builder = NULL;
294 if (register_pending_cnt > 1) {
295 l1 = g_slist_nth(gatt_services, len - register_pending_cnt);
297 l1 = g_slist_last(gatt_services);
299 register_pending_cnt--;
301 struct gatt_service_info *serv_info = l1->data;
302 if (serv_info == NULL) {
303 BT_ERR("service info value is NULL");
304 g_dbus_method_invocation_return_value(invocation, NULL);
308 /* Prepare inner builder for GattService1 interface */
309 BT_DBG("Creating builder for service");
310 svc_builder = g_variant_builder_new(
311 G_VARIANT_TYPE("a{sa{sv}}"));
312 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
314 g_variant_builder_add(inner_builder, "{sv}", "UUID",
315 g_variant_new_string(serv_info->service_uuid));
317 g_variant_builder_add(inner_builder, "{sv}", "Primary",
318 g_variant_new_boolean(serv_info->is_svc_primary));
321 inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
322 BT_DBG("Adding Charatarisitcs list");
323 for (l4 = serv_info->char_data; l4 != NULL; l4 = l4->next) {
324 struct gatt_char_info *char_info = l4->data;
325 g_variant_builder_add(inner_builder1, "o",
326 char_info->char_path);
327 BT_DBG("%s", char_info->char_path);
330 svc_char = g_variant_new("ao", inner_builder1);
331 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
334 g_variant_builder_add(svc_builder, "{sa{sv}}",
338 g_variant_builder_add(builder, "{oa{sa{sv}}}",
339 serv_info->serv_path,
342 g_variant_builder_unref(inner_builder1);
344 /* Prepare inner builder for GattCharacteristic1 interface */
346 GSList *l2 = serv_info->char_data;
347 BT_DBG("Creating builder for characteristics \n");
350 BT_DBG("characteristic data is NULL");
352 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
354 GVariantBuilder *char_builder = NULL;
355 GVariantBuilder *inner_builder = NULL;
356 GVariantBuilder *builder1 = NULL;
357 GVariantBuilder *builder2 = NULL;
358 GVariantBuilder *builder3 = NULL;
359 GVariant *char_val = NULL;
360 GVariant *flags_val = NULL;
361 GVariant *char_desc = NULL;
362 char *unicast = NULL;
363 gboolean notify = FALSE;
366 char_builder = g_variant_builder_new(
369 inner_builder = g_variant_builder_new(
373 struct gatt_char_info *char_info = l2->data;
374 if (char_info == NULL) {
375 BT_ERR("char_info is NULL");
380 g_variant_builder_add(inner_builder, "{sv}", "UUID",
381 g_variant_new_string(char_info->char_uuid));
383 g_variant_builder_add(inner_builder, "{sv}", "Service",
384 g_variant_new("o", serv_info->serv_path));
386 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
388 if(char_info->char_value != NULL) {
389 for (i = 0; i < char_info->value_length; i++) {
390 g_variant_builder_add(builder1, "y",
391 char_info->char_value[i]);
393 char_val = g_variant_new("ay", builder1);
394 g_variant_builder_add(inner_builder, "{sv}",
398 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
400 for (i = 0; i < char_info->flags_length; i++) {
401 g_variant_builder_add(builder2, "s",
402 char_info->char_flags[i]);
405 flags_val = g_variant_new("as", builder2);
406 g_variant_builder_add(inner_builder, "{sv}", "Flags",
410 g_variant_builder_add(inner_builder, "{sv}", "Notifying",
411 g_variant_new("b", notify));
414 unicast = g_strdup("00:00:00:00:00:00");
415 g_variant_builder_add(inner_builder, "{sv}", "Unicast",
416 g_variant_new("s", unicast));
419 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
420 BT_DBG("Adding Descriptors list");
422 for (l4 = char_info->desc_data; l4 != NULL; l4 = l4->next) {
423 struct gatt_desc_info *desc_info = l4->data;
424 g_variant_builder_add(builder3, "o",
425 desc_info->desc_path);
426 BT_DBG("%s", desc_info->desc_path);
429 char_desc = g_variant_new("ao", builder3);
430 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
433 g_variant_builder_add(char_builder, "{sa{sv}}",
434 GATT_CHAR_INTERFACE , inner_builder);
435 g_variant_builder_add(builder, "{oa{sa{sv}}}",
436 char_info->char_path, char_builder);
438 /*Prepare inner builder for GattDescriptor1 interface*/
440 GSList *l3 = char_info->desc_data;
443 BT_DBG("descriptor data is NULL");
445 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
447 BT_DBG("Creating builder for descriptor \n");
449 GVariantBuilder *desc_builder = NULL;
450 GVariantBuilder *inner_builder = NULL;
451 GVariantBuilder *builder1 = NULL;
452 GVariantBuilder *builder2 = NULL;
453 GVariant *desc_val = NULL;
455 desc_builder = g_variant_builder_new(
458 inner_builder = g_variant_builder_new(
462 struct gatt_desc_info *desc_info = l3->data;
463 if (desc_info == NULL) {
464 BT_ERR("desc_info is NULL");
469 g_variant_builder_add(inner_builder,
471 g_variant_new_string(
472 desc_info->desc_uuid));
475 g_variant_builder_add(inner_builder, "{sv}",
478 char_info->char_path));
481 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
483 if(desc_info->desc_value != NULL) {
484 for (i = 0; i < desc_info->value_length; i++) {
485 g_variant_builder_add(builder1, "y",
486 desc_info->desc_value[i]);
488 desc_val = g_variant_new("ay", builder1);
489 g_variant_builder_add(inner_builder, "{sv}",
494 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
496 for (i = 0; i < desc_info->flags_length; i++) {
497 g_variant_builder_add(builder2, "s",
498 desc_info->desc_flags[i]);
501 flags_val = g_variant_new("as", builder2);
502 g_variant_builder_add(inner_builder, "{sv}", "Flags",
505 g_variant_builder_add(desc_builder, "{sa{sv}}",
509 g_variant_builder_add(builder, "{oa{sa{sv}}}",
510 desc_info->desc_path,
513 /*unref descriptor builder pointers*/
514 g_variant_builder_unref(builder1);
515 g_variant_builder_unref(builder2);
516 g_variant_builder_unref(inner_builder);
517 g_variant_builder_unref(desc_builder);
522 /*unref char builder pointers*/
523 g_variant_builder_unref(builder1);
524 g_variant_builder_unref(builder2);
525 g_variant_builder_unref(builder3);
526 g_variant_builder_unref(inner_builder);
527 g_variant_builder_unref(char_builder);
530 /*unref service builder pointers*/
531 g_variant_builder_unref(inner_builder);
532 g_variant_builder_unref(svc_builder);
535 /* Return builder as method reply */
536 BT_DBG("Sending gatt service builder values to Bluez");
537 g_dbus_method_invocation_return_value(invocation,
544 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const char *char_path)
548 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
549 struct gatt_service_info *serv_info = l1->data;
551 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
552 struct gatt_char_info *char_info = l2->data;
554 if (g_strcmp0(char_info->char_path, char_path)
559 BT_ERR("Gatt service not found");
563 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const char *desc_path)
565 GSList *l1, *l2, *l3;
567 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
568 struct gatt_service_info *serv_info = l1->data;
570 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
571 struct gatt_char_info *char_info = l2->data;
573 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
574 struct gatt_desc_info *desc_info = l3->data;
576 if (g_strcmp0(desc_info->desc_path, desc_path)
582 BT_ERR("Gatt service not found");
586 static void __bt_gatt_char_method_call(GDBusConnection *connection,
588 const gchar *object_path,
589 const gchar *interface_name,
590 const gchar *method_name,
591 GVariant *parameters,
592 GDBusMethodInvocation *invocation,
596 if (g_strcmp0(method_name, "ReadValue") == 0) {
600 bt_gatt_read_req_t read_req = {0, };
601 bt_user_info_t *user_info = NULL;
602 struct gatt_req_info *req_info = NULL;
603 struct gatt_service_info *svc_info = NULL;
607 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
609 BT_DBG("Application path = %s", object_path);
611 BT_DBG("Remote Device address number = %s", addr);
612 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
614 BT_DBG("Sender = %s", sender);
616 read_req.att_handle = g_strdup(object_path);
617 read_req.address = g_strdup(addr);
618 read_req.req_id = req_id;
619 read_req.offset = offset;
620 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
621 if (svc_info != NULL) {
622 read_req.service_handle = g_strdup(svc_info->serv_path);
623 user_info = _bt_get_user_data(BT_COMMON);
625 GVariant *param = NULL;
628 /* Store requets information */
629 req_info = g_new0(struct gatt_req_info, 1);
630 req_info->attr_path = g_strdup(object_path);
631 req_info->svc_path = g_strdup(read_req.service_handle);
632 req_info->request_id= req_id;
633 req_info->offset = offset;
634 req_info->context = invocation;
635 gatt_requests = g_slist_append(gatt_requests, req_info);
637 if (user_info != NULL) {
639 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
640 BLUETOOTH_ERROR_NONE, &read_req,
641 user_info->cb, user_info->user_data);
644 param = g_variant_new("(sssyq)",
646 read_req.service_handle,
650 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param);
654 if (read_req.att_handle)
655 g_free(read_req.att_handle);
656 if (read_req.address)
657 g_free(read_req.address);
658 if (read_req.service_handle)
659 g_free(read_req.service_handle);
661 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
662 GVariant *var = NULL;
666 bt_gatt_value_change_t value_change = {0, };
667 bt_user_info_t *user_info = NULL;
669 struct gatt_service_info *svc_info = NULL;
670 struct gatt_req_info *req_info = NULL;
672 GVariant *param = NULL;
675 BT_DBG("WriteValue");
676 BT_DBG("Application path = %s", object_path);
677 BT_DBG("Sender = %s", sender);
679 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
681 value_change.att_handle = g_strdup(object_path);
682 value_change.address = g_strdup(addr);
683 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
684 if (svc_info == NULL) {
685 g_variant_unref(var);
686 g_dbus_method_invocation_return_value(invocation, NULL);
690 value_change.service_handle = g_strdup(svc_info->serv_path);
691 value_change.offset = offset;
692 value_change.req_id = req_id;
694 len = g_variant_get_size(var);
698 value_change.att_value = (guint8 *)malloc(len);
699 if (!value_change.att_value) {
700 BT_ERR("att_value is NULL");
701 g_variant_unref(var);
702 g_dbus_method_invocation_return_value(invocation, NULL);
706 data = (char *)g_variant_get_data(var);
707 memcpy(value_change.att_value, data, len);
710 value_change.val_len = len;
712 /* Store requets information */
713 req_info = g_new0(struct gatt_req_info, 1);
714 req_info->attr_path = g_strdup(object_path);
715 req_info->svc_path = g_strdup(value_change.service_handle);
716 req_info->request_id= req_id;
717 req_info->offset = offset;
718 req_info->context = invocation;
719 gatt_requests = g_slist_append(gatt_requests, req_info);
721 user_info = _bt_get_user_data(BT_COMMON);
722 if (user_info != NULL) {
724 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
725 BLUETOOTH_ERROR_NONE, &value_change,
726 user_info->cb, user_info->user_data);
731 svc_path = g_strdup(svc_info->serv_path);
732 param = g_variant_new("(sssyq@ay)",
739 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, param);
744 g_variant_unref(var);
746 } else if (g_strcmp0(method_name, "StartNotify") == 0) {
747 bt_user_info_t *user_info = NULL;
748 bt_gatt_char_notify_change_t notify_change = {0, };
749 BT_DBG("StartNotify");
750 user_info = _bt_get_user_data(BT_COMMON);
751 if (user_info != NULL) {
752 struct gatt_service_info *svc_info = NULL;
753 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
755 notify_change.service_handle = g_strdup(svc_info->serv_path);
756 notify_change.att_handle = g_strdup(object_path);
757 notify_change.att_notify = TRUE;
759 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
760 BLUETOOTH_ERROR_NONE, ¬ify_change,
761 user_info->cb, user_info->user_data);
764 } else if (g_strcmp0(method_name, "StopNotify") == 0) {
765 bt_user_info_t *user_info = NULL;
766 bt_gatt_char_notify_change_t notify_change = {0, };
767 BT_DBG("StopNotify");
768 user_info = _bt_get_user_data(BT_COMMON);
769 if (user_info != NULL) {
770 struct gatt_service_info *svc_info = NULL;
771 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
773 notify_change.service_handle = g_strdup(svc_info->serv_path);
774 notify_change.att_handle = g_strdup(object_path);
775 notify_change.att_notify = FALSE;
777 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
778 BLUETOOTH_ERROR_NONE, ¬ify_change,
779 user_info->cb, user_info->user_data);
782 } else if (g_strcmp0(method_name, "IndicateConfirm") == 0) {
784 bt_gatt_indicate_confirm_t confirm = {0, };
785 bt_user_info_t *user_info = NULL;
786 gboolean complete = 0;
787 struct gatt_service_info *svc_info = NULL;
789 BT_DBG("IndicateConfirm");
790 BT_DBG("Application path = %s", object_path);
791 BT_DBG("Sender = %s", sender);
793 g_variant_get(parameters, "(&sb)", &addr, &complete);
795 BT_DBG("Remote Device address number = %s", addr);
796 confirm.att_handle = g_strdup(object_path);
797 confirm.address = g_strdup(addr);
798 confirm.complete = complete;
800 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
801 if (svc_info != NULL) {
802 confirm.service_handle = g_strdup(svc_info->serv_path);
803 user_info = _bt_get_user_data(BT_COMMON);
805 if (user_info != NULL) {
807 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_COMPLETED,
808 BLUETOOTH_ERROR_NONE, &confirm,
809 user_info->cb, user_info->user_data);
813 g_dbus_method_invocation_return_value(invocation, NULL);
816 static void __bt_gatt_desc_method_call(GDBusConnection *connection,
818 const gchar *object_path,
819 const gchar *interface_name,
820 const gchar *method_name,
821 GVariant *parameters,
822 GDBusMethodInvocation *invocation,
825 if (g_strcmp0(method_name, "ReadValue") == 0) {
829 bt_gatt_read_req_t read_req = {0, };
830 bt_user_info_t *user_info = NULL;
831 struct gatt_req_info *req_info = NULL;
832 struct gatt_service_info *svc_info = NULL;
835 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
837 BT_DBG("Application path = %s", object_path);
839 BT_DBG("Remote Device address number = %s", addr);
840 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
842 BT_DBG("Sender = %s", sender);
844 read_req.att_handle = g_strdup(object_path);
845 read_req.address = g_strdup(addr);
846 read_req.req_id = req_id;
847 read_req.offset = offset;
848 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
849 if (svc_info != NULL) {
850 read_req.service_handle = g_strdup(svc_info->serv_path);
851 user_info = _bt_get_user_data(BT_COMMON);
853 /* Store requets information */
854 req_info = g_new0(struct gatt_req_info, 1);
855 req_info->attr_path = g_strdup(object_path);
856 req_info->svc_path = g_strdup(read_req.service_handle);
857 req_info->request_id= req_id;
858 req_info->offset = offset;
859 req_info->context = invocation;
860 gatt_requests = g_slist_append(gatt_requests, req_info);
862 if (user_info != NULL) {
864 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
865 BLUETOOTH_ERROR_NONE, &read_req,
866 user_info->cb, user_info->user_data);
870 if (read_req.att_handle)
871 g_free(read_req.att_handle);
872 if (read_req.address)
873 g_free(read_req.address);
874 if (read_req.service_handle)
875 g_free(read_req.service_handle);
878 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
879 GVariant *var = NULL;
883 bt_gatt_value_change_t value_change = {0, };
884 bt_user_info_t *user_info = NULL;
886 struct gatt_service_info *svc_info = NULL;
887 struct gatt_req_info *req_info = NULL;
889 BT_DBG("WriteValue");
890 BT_DBG("Application path = %s", object_path);
891 BT_DBG("Sender = %s", sender);
893 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
895 value_change.att_handle = g_strdup(object_path);
896 value_change.address = g_strdup(addr);
897 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
898 if (svc_info == NULL) {
899 g_variant_unref(var);
900 g_dbus_method_invocation_return_value(invocation, NULL);
904 value_change.service_handle = g_strdup(svc_info->serv_path);
905 value_change.offset = offset;
906 value_change.req_id = req_id;
908 len = g_variant_get_size(var);
912 value_change.att_value = (guint8 *)malloc(len);
913 if (!value_change.att_value) {
914 BT_ERR("att_value is NULL");
915 g_variant_unref(var);
916 g_dbus_method_invocation_return_value(invocation, NULL);
919 data = (char *)g_variant_get_data(var);
920 memcpy(value_change.att_value, data, len);
922 g_variant_unref(var);
924 value_change.val_len = len;
926 /* Store requets information */
927 req_info = g_new0(struct gatt_req_info, 1);
928 req_info->attr_path = g_strdup(object_path);
929 req_info->svc_path = g_strdup(value_change.service_handle);
930 req_info->request_id= req_id;
931 req_info->offset = offset;
932 req_info->context = invocation;
933 gatt_requests = g_slist_append(gatt_requests, req_info);
935 user_info = _bt_get_user_data(BT_COMMON);
936 if (user_info != NULL) {
938 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
939 BLUETOOTH_ERROR_NONE, &value_change,
940 user_info->cb, user_info->user_data);
944 g_dbus_method_invocation_return_value(invocation, NULL);
947 gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface)
950 GError *error = NULL;
951 GVariantBuilder *array_builder;
953 array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
954 g_variant_builder_init(array_builder, G_VARIANT_TYPE ("as"));
955 g_variant_builder_add(array_builder, "s", interface);
957 ret = g_dbus_connection_emit_signal(g_conn, NULL, "/",
958 "org.freedesktop.Dbus.Objectmanager",
960 g_variant_new ("(oas)",
961 object_path, array_builder),
966 /* dbus gives error cause */
967 BT_ERR("d-bus api failure: errcode[%x], message[%s]",
968 error->code, error->message);
969 g_clear_error(&error);
972 g_variant_builder_unref(array_builder);
977 static const GDBusInterfaceVTable desc_interface_vtable = {
978 __bt_gatt_desc_method_call,
983 static const GDBusInterfaceVTable char_interface_vtable = {
984 __bt_gatt_char_method_call,
989 static const GDBusInterfaceVTable serv_interface_vtable = {
995 static const GDBusInterfaceVTable manager_interface_vtable = {
996 __bt_gatt_manager_method_call,
1001 static GDBusNodeInfo *__bt_gatt_create_method_node_info(
1002 const gchar *introspection_data)
1005 GDBusNodeInfo *node_info = NULL;
1007 if (introspection_data == NULL)
1010 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
1013 BT_ERR("Unable to create node: %s", err->message);
1014 g_clear_error(&err);
1019 static struct gatt_service_info *__bt_gatt_find_gatt_service_info(
1020 const char *service_path)
1024 for (l = gatt_services; l != NULL; l = l->next) {
1025 struct gatt_service_info *info = l->data;
1027 if (g_strcmp0(info->serv_path, service_path) == 0)
1030 BT_ERR("Gatt service not found");
1034 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
1035 const char *service_path, const char *char_path)
1039 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1040 struct gatt_service_info *serv_info = l1->data;
1042 if (g_strcmp0(serv_info->serv_path, service_path) == 0) {
1044 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1045 struct gatt_char_info *char_info = l2->data;
1047 if (g_strcmp0(char_info->char_path, char_path)
1051 BT_ERR("Gatt characteristic not found");
1055 BT_ERR("Gatt service not found");
1059 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
1060 const char *serv_path, const char *char_path,
1061 const char *desc_path)
1063 GSList *l1, *l2, *l3;
1065 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1066 struct gatt_service_info *serv_info = l1->data;
1068 if (g_strcmp0(serv_info->serv_path, serv_path) == 0) {
1069 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1070 struct gatt_char_info *char_info = l2->data;
1072 if (g_strcmp0(char_info->char_path, char_path)
1074 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
1075 struct gatt_desc_info *desc_info = l3->data;
1076 if (g_strcmp0(desc_info->desc_path,
1085 BT_ERR("Gatt descriptor not found");
1089 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id)
1093 for (l = gatt_requests; l != NULL; l = l->next) {
1094 struct gatt_req_info *req_info = l->data;
1096 if (req_info && req_info->request_id == request_id) {
1100 BT_ERR("Gatt Request not found");
1104 static GDBusProxy *__bt_gatt_gdbus_init_manager_proxy(const gchar *service,
1105 const gchar *path, const gchar *interface)
1111 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
1116 BT_ERR("Unable to connect to gdbus: %s", err->message);
1117 g_clear_error(&err);
1122 proxy = g_dbus_proxy_new_sync(g_conn,
1123 G_DBUS_PROXY_FLAGS_NONE, NULL,
1125 interface, NULL, &err);
1129 BT_ERR("Unable to create proxy: %s", err->message);
1130 g_clear_error(&err);
1134 manager_gproxy = proxy;
1139 static GDBusProxy *__bt_gatt_gdbus_get_manager_proxy(const gchar *service,
1140 const gchar *path, const gchar *interface)
1142 return (manager_gproxy) ? manager_gproxy :
1143 __bt_gatt_gdbus_init_manager_proxy(service,
1147 int bluetooth_gatt_convert_prop2string(
1148 bt_gatt_characteristic_property_t properties,
1149 char *char_properties[])
1153 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) {
1154 char_properties[flag_count] = g_strdup("broadcast");
1157 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) {
1158 char_properties[flag_count] = g_strdup("read");
1161 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) {
1162 char_properties[flag_count] = g_strdup("write-without-response");
1165 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) {
1166 char_properties[flag_count] = g_strdup("write");
1169 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) {
1170 char_properties[flag_count] = g_strdup("notify");
1173 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) {
1174 char_properties[flag_count] = g_strdup("indicate");
1177 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) {
1178 char_properties[flag_count] = g_strdup("authenticated-signed-writes");
1181 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE) {
1182 char_properties[flag_count] = g_strdup("reliable-write");
1185 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES) {
1186 char_properties[flag_count] = g_strdup("writable-auxiliaries");
1189 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ) {
1190 char_properties[flag_count] = g_strdup("encrypt-read");
1193 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE) {
1194 char_properties[flag_count] = g_strdup("encrypt-write");
1197 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ) {
1198 char_properties[flag_count] = g_strdup("encrypt-authenticated-read");
1201 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE) {
1202 char_properties[flag_count] = g_strdup("encrypt-authenticated-write");
1206 if (flag_count == 0) {
1207 char_properties[flag_count] = g_strdup("read");
1214 int bluetooth_gatt_convert_perm2string(
1215 bt_gatt_permission_t properties,
1216 char *char_properties[])
1220 if (properties & BLUETOOTH_GATT_PERMISSION_READ) {
1221 char_properties[flag_count] = g_strdup("read");
1224 if (properties & BLUETOOTH_GATT_PERMISSION_WRITE) {
1225 char_properties[flag_count] = g_strdup("write");
1228 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ) {
1229 char_properties[flag_count] = g_strdup("encrypt-read");
1232 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE) {
1233 char_properties[flag_count] = g_strdup("encrypt-write");
1236 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ) {
1237 char_properties[flag_count] = g_strdup("encrypt-authenticated-read");
1240 if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE) {
1241 char_properties[flag_count] = g_strdup("encrypt-authenticated-write");
1245 if (flag_count == 0) {
1246 char_properties[flag_count] = g_strdup("read");
1253 static void __bt_gatt_set_service_state(const char *service_path,
1256 struct gatt_service_info *svc_info = NULL;
1257 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1259 if (svc_info != NULL) {
1260 BT_DBG("Updating the gatt service register state %d", state);
1261 svc_info->is_svc_registered = state;
1265 BT_DBG("gatt service not found");
1268 static gboolean __bt_gatt_get_service_state(const char *service_path)
1270 struct gatt_service_info *svc_info = NULL;
1272 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1274 if (svc_info != NULL) {
1275 BT_DBG("Return the state of the gatt service %d",
1276 svc_info->is_svc_registered);
1277 return svc_info->is_svc_registered;
1280 BT_DBG("gatt service info is NULL");
1284 void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1286 GError *error = NULL;
1288 GVariantIter *iter = NULL;
1289 const gchar *key = NULL;
1290 GVariant *value = NULL;
1291 const gchar *service = NULL;
1292 const gchar *characteristic = NULL;
1293 const gchar *descriptor = NULL;
1297 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1299 if (result == NULL) {
1300 /* dBUS-RPC is failed */
1301 BT_ERR("Dbus-RPC is failed\n");
1303 if (error != NULL) {
1304 /* dBUS gives error cause */
1305 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1306 error->code, error->message);
1307 g_clear_error(&error);
1310 char *char_cmp = NULL;
1311 g_variant_get (result, "(a{sv})", &iter);
1312 char_cmp = g_strdup_printf("Characteristic%d", n_char);
1314 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
1315 if (g_strcmp0(key, "Service") == 0) {
1316 service = g_variant_get_string(value, NULL);
1317 BT_DBG("Service %s", service);
1318 } else if (g_strcmp0(key, char_cmp) == 0) {
1319 characteristic = g_variant_get_string(value, NULL);
1321 char_cmp = g_strdup_printf("Characteristic%d", ++n_char);
1322 BT_DBG("%s", characteristic);
1323 } else if (g_strcmp0(key, "Descriptor") == 0) {
1324 descriptor = g_variant_get_string(value, NULL);
1325 BT_DBG("Descriptor %s", descriptor);
1328 /* TODO: Store the service informationa and
1329 * Send respponse to CAPI layer. */
1331 g_variant_unref(result);
1336 void register_application_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1338 BT_INFO("RegisterApplication is completed");
1340 GError *error = NULL;
1343 register_pending_cnt = 0;
1345 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1347 if (result == NULL) {
1348 /* dBUS-RPC is failed */
1349 BT_ERR("Dbus-RPC is failed\n");
1351 if (error != NULL) {
1352 /* dBUS gives error cause */
1353 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1354 error->code, error->message);
1355 g_clear_error(&error);
1360 void unregister_application_cb(GObject *object, GAsyncResult *res,
1363 BT_INFO("UnregisterApplication is completed");
1365 GError *error = NULL;
1368 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1370 if (result == NULL) {
1371 /* dBUS-RPC is failed */
1372 BT_ERR("Dbus-RPC is failed\n");
1374 if (error != NULL) {
1375 /* dBUS gives error cause */
1376 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1377 error->code, error->message);
1378 g_clear_error(&error);
1383 static int __bt_gatt_unregister_service(const char *service_path)
1385 if (!__bt_gatt_get_service_state(service_path)) {
1386 BT_DBG("service not registered \n");
1387 return BLUETOOTH_ERROR_NOT_FOUND;
1390 return BLUETOOTH_ERROR_NONE;
1393 BT_EXPORT_API int bluetooth_gatt_unregister_application(void)
1395 GDBusProxy *proxy = NULL;
1397 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1398 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
1400 if (proxy == NULL || app_path == NULL)
1401 return BLUETOOTH_ERROR_INTERNAL;
1403 BT_INFO("UnregisterApplication");
1405 /* Async Call to Unregister Service */
1406 g_dbus_proxy_call(proxy,
1407 "UnregisterApplication",
1408 g_variant_new("(o)",
1410 G_DBUS_CALL_FLAGS_NONE, -1,
1412 (GAsyncReadyCallback) unregister_application_cb,
1415 return BLUETOOTH_ERROR_NONE;
1418 static GDBusConnection *__bt_gatt_get_gdbus_connection(void)
1420 GDBusConnection *local_system_gconn = NULL;
1423 if (g_conn == NULL) {
1424 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1427 BT_ERR("Unable to connect to dbus: %s", err->message);
1428 g_clear_error(&err);
1432 } else if (g_dbus_connection_is_closed(g_conn)) {
1433 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1435 if (!local_system_gconn) {
1436 BT_ERR("Unable to connect to dbus: %s", err->message);
1437 g_clear_error(&err);
1440 g_conn = local_system_gconn;
1446 BT_EXPORT_API int bluetooth_gatt_init(void)
1448 GDBusConnection *conn;
1449 GDBusNodeInfo *obj_info;
1450 GError *error = NULL;
1452 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
1453 BT_GATT_SERVICE_NAME,
1454 G_BUS_NAME_OWNER_FLAGS_NONE,
1455 NULL, NULL, NULL, NULL, NULL);
1457 BT_DBG("owner_id is [%d]", owner_id);
1458 app_path = g_strdup_printf("/com/%d", getpid());
1462 conn = __bt_gatt_get_gdbus_connection();
1464 BT_ERR("Unable to get connection");
1465 return BLUETOOTH_ERROR_INTERNAL;
1468 /* Register ObjectManager interface */
1469 obj_info = __bt_gatt_create_method_node_info(
1470 manager_introspection_xml);
1472 if (obj_info == NULL) {
1473 BT_ERR("failed to get node info");
1474 return BLUETOOTH_ERROR_INTERNAL;
1477 manager_id = g_dbus_connection_register_object(g_conn, app_path,
1478 obj_info->interfaces[0],
1479 &manager_interface_vtable,
1480 NULL, NULL, &error);
1482 if (manager_id == 0) {
1483 BT_ERR("failed to register: %s", error->message);
1484 g_error_free(error);
1485 return BLUETOOTH_ERROR_INTERNAL;
1488 return BLUETOOTH_ERROR_NONE;
1491 BT_EXPORT_API int bluetooth_gatt_deinit()
1493 int ret = BLUETOOTH_ERROR_NONE;
1494 /* Unown gdbus bus */
1497 /* remove/unregister all services */
1498 BT_DBG("removing all registered gatt service\n");
1499 bluetooth_gatt_delete_services();
1501 g_bus_unown_name(owner_id);
1503 /* unregister the exported interface for object manager */
1504 g_dbus_connection_unregister_object(g_conn,
1507 BT_DBG("Gatt service deinitialized \n");
1509 g_slist_free(gatt_services);
1510 gatt_services = NULL;
1512 ret = bluetooth_gatt_unregister_application();
1514 if (ret == BLUETOOTH_ERROR_NONE) {
1522 return BLUETOOTH_ERROR_NOT_FOUND;
1525 BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid,
1528 GError *error = NULL;
1530 GDBusNodeInfo *node_info;
1532 GVariantBuilder *builder = NULL;
1533 GVariantBuilder *builder1 = NULL;
1534 GVariantBuilder *inner_builder = NULL;
1535 gboolean svc_primary = TRUE;
1536 struct gatt_service_info *serv_info = NULL;
1538 node_info = __bt_gatt_create_method_node_info(
1539 service_introspection_xml);
1541 if (node_info == NULL)
1542 return BLUETOOTH_ERROR_INTERNAL;
1544 path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, serv_id++);
1545 BT_DBG("gatt service path is [%s]", path);
1547 object_id = g_dbus_connection_register_object(g_conn, path,
1548 node_info->interfaces[0],
1549 &serv_interface_vtable,
1550 NULL, NULL, &error);
1552 if (object_id == 0) {
1553 BT_ERR("failed to register: %s", error->message);
1554 g_error_free(error);
1557 return BLUETOOTH_ERROR_INTERNAL;
1560 /* Add object_id/gatt service information; it's required at the time of
1561 * service unregister and Getmanagedobjects
1563 serv_info = g_new0(struct gatt_service_info, 1);
1565 serv_info->serv_path = g_strdup(path);
1566 serv_info->serv_id = object_id;
1567 serv_info->service_uuid = g_strdup(svc_uuid);
1568 serv_info->is_svc_registered = FALSE;
1569 serv_info->is_svc_primary = svc_primary;
1571 gatt_services = g_slist_append(gatt_services, serv_info);
1573 /* emit interfacesadded signal here for service path */
1574 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1575 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1577 g_variant_builder_add(inner_builder, "{sv}",
1578 "UUID", g_variant_new_string(svc_uuid));
1580 g_variant_builder_add(inner_builder, "{sv}",
1581 "Primary", g_variant_new_boolean(svc_primary));
1583 builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1585 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
1586 g_variant_new("ao", builder1));
1588 g_variant_builder_add(builder, "{sa{sv}}",
1589 GATT_SERV_INTERFACE, inner_builder);
1591 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1592 "org.freedesktop.Dbus.ObjectManager",
1594 g_variant_new("(oa{sa{sv}})",
1600 *svc_path = g_strdup(path);
1603 g_variant_builder_unref(inner_builder);
1604 g_variant_builder_unref(builder);
1605 g_variant_builder_unref(builder1);
1607 return BLUETOOTH_ERROR_NONE;
1610 BT_EXPORT_API int bluetooth_gatt_add_new_characteristic(
1611 const char *svc_path, const char *char_uuid,
1612 bt_gatt_permission_t permissions,
1613 bt_gatt_characteristic_property_t properties,
1617 GError *error = NULL;
1619 GDBusNodeInfo *node_info;
1621 GVariantBuilder *builder = NULL;
1622 GVariantBuilder *inner_builder = NULL;
1623 struct gatt_service_info *serv_info = NULL;
1624 struct gatt_char_info *char_info = NULL;
1625 GVariantBuilder *builder2 = NULL;
1626 GVariantBuilder *builder3 = NULL;
1627 GVariant *flags_val = NULL;
1629 char *char_flags[NUMBER_OF_FLAGS];
1634 new_service = FALSE;
1637 BT_DBG("gatt svc_path path is [%s]", svc_path);
1638 serv_info = __bt_gatt_find_gatt_service_info(svc_path);
1639 if (serv_info == NULL)
1640 return BLUETOOTH_ERROR_INVALID_PARAM;
1642 node_info = __bt_gatt_create_method_node_info(
1643 characteristics_introspection_xml);
1645 if (node_info == NULL)
1646 return BLUETOOTH_ERROR_INTERNAL;
1648 path = g_strdup_printf("%s/characteristic%d", svc_path, char_id++);
1649 BT_DBG("gatt characteristic path is [%s]", path);
1651 object_id = g_dbus_connection_register_object(g_conn, path,
1652 node_info->interfaces[0],
1653 &char_interface_vtable,
1654 NULL, NULL, &error);
1656 if (object_id == 0) {
1657 BT_ERR("failed to register: %s", error->message);
1658 g_error_free(error);
1661 return BLUETOOTH_ERROR_INTERNAL;
1664 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ)
1665 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ;
1666 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ)
1667 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ;
1668 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE)
1669 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE;
1670 if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE)
1671 properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE;
1673 flag_count = bluetooth_gatt_convert_prop2string(properties, char_flags);
1675 char_info = g_new0(struct gatt_char_info, 1);
1677 char_info->char_path = g_strdup(path);
1678 char_info->char_id = object_id;
1679 char_info->char_uuid = g_strdup(char_uuid);
1681 for (i = 0; i < flag_count; i++) {
1682 char_info->char_flags[i] = char_flags[i];
1685 char_info->flags_length = flag_count;
1687 serv_info->char_data = g_slist_append(serv_info->char_data, char_info);
1689 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1690 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1692 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1693 g_variant_new("s", char_uuid));
1694 g_variant_builder_add(inner_builder, "{sv}", "Service",
1695 g_variant_new("o", svc_path));
1697 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1699 for (i = 0; i < flag_count; i++) {
1700 g_variant_builder_add(builder2, "s", char_flags[i]);
1703 flags_val = g_variant_new("as", builder2);
1704 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1707 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1709 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
1710 g_variant_new("ao", builder3));
1712 g_variant_builder_add(builder, "{sa{sv}}",
1713 GATT_CHAR_INTERFACE,
1716 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1717 "org.freedesktop.Dbus.ObjectManager",
1719 g_variant_new("(oa{sa{sv}})",
1723 *char_path = g_strdup(path);
1729 g_variant_builder_unref(inner_builder);
1730 g_variant_builder_unref(builder);
1731 g_variant_builder_unref(builder2);
1732 g_variant_builder_unref(builder3);
1734 return BLUETOOTH_ERROR_NONE;
1737 BT_EXPORT_API int bluetooth_gatt_set_characteristic_value(
1738 const char *characteristic, const char *char_value,
1741 gchar **line_argv = NULL;
1742 char *serv_path = NULL;
1743 struct gatt_char_info *char_info = NULL;
1744 GVariantBuilder *builder1 = NULL;
1745 GVariantBuilder *builder = NULL;
1746 GVariantBuilder *inner_builder = NULL;
1747 GVariant *char_val = NULL;
1748 GError *error = NULL;
1750 int res = BLUETOOTH_ERROR_NONE;
1752 line_argv = g_strsplit_set(characteristic, "/", 0);
1753 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1755 char_info = __bt_gatt_find_gatt_char_info(serv_path, characteristic);
1757 if (char_info == NULL) {
1758 /* Fix : RESOURCE_LEAK */
1759 res = BLUETOOTH_ERROR_INVALID_PARAM;
1763 char_info->value_length = value_length;
1765 char_info->char_value = (char *)malloc(value_length);
1766 /* Fix : NULL_RETURNS */
1767 if (char_info->char_value == NULL) {
1768 res = BLUETOOTH_ERROR_MEMORY_ALLOCATION;
1772 for (i = 0; i < value_length; i++)
1773 char_info->char_value[i] = char_value[i];
1775 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1776 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1778 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1780 for (i = 0; i < value_length; i++) {
1781 g_variant_builder_add(builder1, "y", char_value[i]);
1784 char_val = g_variant_new("ay", builder1);
1785 g_variant_builder_add(inner_builder, "{sv}", "Value", char_val);
1787 g_variant_builder_add(builder, "{sa{sv}}",
1788 GATT_CHAR_INTERFACE,
1791 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1792 "org.freedesktop.Dbus.ObjectManager",
1794 g_variant_new("(oa{sa{sv}})",
1795 char_info->char_path, builder),
1798 g_variant_builder_unref(inner_builder);
1799 g_variant_builder_unref(builder);
1800 g_variant_builder_unref(builder1);
1802 g_strfreev(line_argv);
1808 BT_EXPORT_API int bluetooth_gatt_add_descriptor(
1809 const char *char_path, const char *desc_uuid,
1810 bt_gatt_permission_t permissions,
1813 static int desc_id = 1;
1814 GError *error = NULL;
1816 GDBusNodeInfo *node_info;
1818 GVariantBuilder *builder = NULL;
1819 GVariantBuilder *inner_builder = NULL;
1820 struct gatt_char_info *char_info = NULL;
1821 struct gatt_desc_info *desc_info = NULL;
1822 gchar **line_argv = NULL;
1824 GVariantBuilder *builder2 = NULL;
1825 GVariant *flags_val = NULL;
1827 char *desc_flags[NUMBER_OF_FLAGS];
1835 line_argv = g_strsplit_set(char_path, "/", 0);
1836 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1838 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
1839 if (char_info == NULL) {
1840 g_strfreev(line_argv);
1841 return BLUETOOTH_ERROR_INVALID_PARAM;
1844 node_info = __bt_gatt_create_method_node_info(
1845 descriptor_introspection_xml);
1847 if (node_info == NULL) {
1848 g_strfreev(line_argv);
1849 return BLUETOOTH_ERROR_INTERNAL;
1852 path = g_strdup_printf("%s/descriptor%d", char_path, desc_id++);
1853 BT_DBG("gatt descriptor path is [%s]", path);
1855 object_id = g_dbus_connection_register_object(g_conn, path,
1856 node_info->interfaces[0],
1857 &desc_interface_vtable,
1858 NULL, NULL, &error);
1860 if (object_id == 0) {
1861 BT_ERR("failed to register: %s", error->message);
1862 g_error_free(error);
1864 g_strfreev(line_argv);
1866 return BLUETOOTH_ERROR_INTERNAL;
1869 flag_count = bluetooth_gatt_convert_perm2string(permissions, desc_flags);
1871 desc_info = g_new0(struct gatt_desc_info, 1);
1873 desc_info->desc_path = g_strdup(path);
1874 desc_info->desc_id = object_id;
1875 desc_info->desc_uuid = g_strdup(desc_uuid);
1877 for (i = 0; i < flag_count; i++) {
1878 desc_info->desc_flags[i] = desc_flags[i];
1881 desc_info->flags_length = flag_count;
1883 char_info->desc_data = g_slist_append(char_info->desc_data, desc_info);
1885 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1886 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1888 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1889 g_variant_new("s", desc_uuid));
1890 g_variant_builder_add(inner_builder, "{sv}", "Characteristic",
1891 g_variant_new("o", char_path));
1893 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1895 for (i = 0; i < flag_count; i++) {
1896 g_variant_builder_add(builder2, "s", desc_flags[i]);
1899 flags_val = g_variant_new("as", builder2);
1900 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1903 g_variant_builder_add(builder, "{sa{sv}}",
1904 GATT_DESC_INTERFACE,
1907 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1908 "org.freedesktop.Dbus.ObjectManager",
1910 g_variant_new("(oa{sa{sv}})",
1914 *desc_path = g_strdup(path);
1917 g_strfreev(line_argv);
1918 g_variant_builder_unref(inner_builder);
1919 g_variant_builder_unref(builder);
1921 return BLUETOOTH_ERROR_NONE;
1924 BT_EXPORT_API int bluetooth_gatt_set_descriptor_value(
1925 const char *desc_path, const char *desc_value,
1928 GError *error = NULL;
1929 GVariantBuilder *builder = NULL;
1930 GVariantBuilder *inner_builder = NULL;
1931 GVariantBuilder *builder1 = NULL;
1932 struct gatt_desc_info *desc_info = NULL;
1933 gchar **line_argv = NULL;
1935 GVariant *desc_val = NULL;
1936 char *serv_path = NULL;
1939 line_argv = g_strsplit_set(desc_path, "/", 0);
1940 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
1941 char_path = g_strdup_printf("%s/%s", serv_path, line_argv[4]);
1943 desc_info = __bt_gatt_find_gatt_desc_info(serv_path, char_path, desc_path);
1945 /* Free the allocated memory */
1946 g_strfreev(line_argv);
1950 /* Fix : NULL_RETURNS */
1951 retv_if(desc_info == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
1953 desc_info->desc_value = (char *)malloc(value_length);
1955 /* Fix : NULL_RETURNS */
1956 retv_if(desc_info->desc_value == NULL, BLUETOOTH_ERROR_MEMORY_ALLOCATION);
1958 for (i = 0; i < value_length; i++)
1959 desc_info->desc_value[i] = desc_value[i];
1961 desc_info->value_length = value_length;
1963 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1964 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1966 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1968 for (i = 0; i < value_length; i++) {
1969 g_variant_builder_add(builder1, "y", desc_value[i]);
1971 desc_val = g_variant_new("ay", builder1);
1972 g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val);
1974 g_variant_builder_add(builder, "{sa{sv}}",
1975 GATT_DESC_INTERFACE,
1978 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1979 "org.freedesktop.Dbus.ObjectManager",
1981 g_variant_new("(oa{sa{sv}})",
1982 desc_info->desc_path, builder),
1985 g_variant_builder_unref(inner_builder);
1986 g_variant_builder_unref(builder);
1987 g_variant_builder_unref(builder1);
1989 return BLUETOOTH_ERROR_NONE;
1992 int bluetooth_gatt_get_service(const char *svc_uuid)
1994 GDBusProxy *proxy = NULL;
1997 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1998 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
2000 return BLUETOOTH_ERROR_INTERNAL;
2002 uuid = g_strdup(svc_uuid);
2004 g_dbus_proxy_call(proxy,
2006 g_variant_new("(s)",
2008 G_DBUS_CALL_FLAGS_NONE, -1,
2010 (GAsyncReadyCallback) get_service_cb,
2015 return BLUETOOTH_ERROR_NONE;
2018 BT_EXPORT_API int bluetooth_gatt_register_service(
2019 const char *svc_path)
2021 register_pending_cnt++;
2023 if (__bt_gatt_get_service_state(svc_path)) {
2024 BT_DBG("service already registered \n");
2025 return BLUETOOTH_ERROR_NONE;
2028 __bt_gatt_set_service_state(svc_path, TRUE);
2030 return BLUETOOTH_ERROR_NONE;
2033 BT_EXPORT_API int bluetooth_gatt_register_application(void)
2035 GDBusProxy *proxy = NULL;
2037 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
2038 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
2039 if (proxy == NULL || app_path == NULL)
2040 return BLUETOOTH_ERROR_INTERNAL;
2042 BT_INFO("RegisterApplication");
2044 g_dbus_proxy_call(proxy,
2045 "RegisterApplication",
2046 g_variant_new("(oa{sv})",
2048 G_DBUS_CALL_FLAGS_NONE, -1,
2050 (GAsyncReadyCallback) register_application_cb,
2053 return BLUETOOTH_ERROR_NONE;
2056 BT_EXPORT_API int bluetooth_gatt_delete_services(void)
2059 int error = BLUETOOTH_ERROR_NONE;
2063 for (l = gatt_services; l != NULL; l = l->next) {
2064 struct gatt_service_info *info = l->data;
2065 BT_DBG("svc_path is %s", info->serv_path);
2066 if (bluetooth_gatt_unregister_service(info->serv_path)
2067 != BLUETOOTH_ERROR_NONE) {
2068 error = BLUETOOTH_ERROR_INTERNAL;
2069 BT_DBG(" Error in removing service %s \n",
2073 BT_DBG(" All services removed successfully.\n ");
2076 BT_DBG(" There are no registered services.\n ");
2079 g_slist_free(gatt_services);
2080 gatt_services = NULL;
2083 if (error != BLUETOOTH_ERROR_NONE)
2086 return BLUETOOTH_ERROR_NONE;
2089 BT_EXPORT_API int bluetooth_gatt_update_characteristic(
2090 const char *char_path, const char* char_value,
2093 GVariantBuilder *outer_builder;
2094 GVariantBuilder *inner_builder;
2095 GVariantBuilder *invalidated_builder;
2096 GVariant *update_value = NULL;
2097 GError *error = NULL;
2098 gboolean ret = FALSE;
2099 int err = BLUETOOTH_ERROR_NONE;
2101 gchar **line_argv = NULL;
2102 gchar *serv_path = NULL;
2104 line_argv = g_strsplit_set(char_path, "/", 0);
2105 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
2107 if (!__bt_gatt_get_service_state(serv_path)) {
2108 BT_DBG("service not registered for this characteristic \n");
2109 g_strfreev(line_argv);
2110 return BLUETOOTH_ERROR_INTERNAL;
2113 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2114 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2116 inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2117 for (i = 0; i < value_length; i++) {
2118 g_variant_builder_add(inner_builder, "y", char_value[i]);
2121 update_value = g_variant_new("ay", inner_builder);
2123 outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2124 g_variant_builder_add(outer_builder, "{sv}", "Value",
2127 BT_DBG("Updating characteristic value \n");
2128 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2130 "org.freedesktop.DBus.Properties",
2131 "PropertiesChanged",
2132 g_variant_new("(sa{sv}as)",
2133 "org.bluez.GattCharacteristic1",
2134 outer_builder, invalidated_builder),
2138 if (error != NULL) {
2139 BT_ERR("D-Bus API failure: errCode[%x], \
2141 error->code, error->message);
2142 g_clear_error(&error);
2144 err = BLUETOOTH_ERROR_INTERNAL;
2146 struct gatt_char_info *char_info = NULL;
2148 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
2149 if (char_info == NULL) {
2150 return BLUETOOTH_ERROR_INVALID_DATA;
2153 char_info->value_length = value_length;
2155 char_info->char_value = (char *)realloc(char_info->char_value, value_length);
2156 if (char_info->char_value) {
2157 for (i = 0; i < value_length; i++) {
2158 char_info->char_value[i] = char_value[i];
2163 g_strfreev(line_argv);
2164 g_variant_builder_unref(inner_builder);
2165 g_variant_builder_unref(outer_builder);
2166 g_variant_builder_unref(invalidated_builder);
2171 BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path)
2174 struct gatt_service_info *svc_info;
2176 int err = BLUETOOTH_ERROR_NONE;
2179 BT_DBG("svc_path %s", svc_path);
2180 svc_info = __bt_gatt_find_gatt_service_info(svc_path);
2183 BT_ERR("Unable to find service info");
2184 return BLUETOOTH_ERROR_NOT_FOUND;
2187 err = __bt_gatt_unregister_service(svc_path);
2188 if (err != BLUETOOTH_ERROR_NONE) {
2189 BT_DBG("Could not unregister application");
2193 for (l = svc_info->char_data; l != NULL; l = l->next) {
2194 struct gatt_char_info *char_info = l->data;
2196 for (l1 = char_info->desc_data; l1 != NULL; l1 = l1->next) {
2197 struct gatt_desc_info *desc_info = l1->data;
2199 ret = g_dbus_connection_unregister_object(g_conn,
2200 desc_info->desc_id);
2202 __bt_gatt_emit_interface_removed(
2203 desc_info->desc_path,
2204 GATT_DESC_INTERFACE);
2206 err = BLUETOOTH_ERROR_INTERNAL;
2209 ret = g_dbus_connection_unregister_object(g_conn,
2210 char_info->char_id);
2212 __bt_gatt_emit_interface_removed(char_info->char_path,
2213 GATT_CHAR_INTERFACE);
2215 err = BLUETOOTH_ERROR_INTERNAL;
2218 ret = g_dbus_connection_unregister_object(g_conn, svc_info->serv_id);
2220 __bt_gatt_emit_interface_removed(svc_info->serv_path,
2221 GATT_SERV_INTERFACE);
2223 err = BLUETOOTH_ERROR_INTERNAL;
2226 ret = g_dbus_connection_unregister_object(g_conn, svc_info->prop_id);
2228 BT_DBG("Unregistered the service on properties interface");
2231 for (tmp = gatt_services; tmp != NULL; tmp = tmp->next) {
2232 struct gatt_service_info *info = tmp->data;
2234 if (g_strcmp0(info->serv_path, svc_path) == 0) {
2235 gatt_services = g_slist_delete_link(gatt_services, tmp->data);
2239 new_service = FALSE;
2241 if (gatt_services->next == NULL)
2247 BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type,
2248 int resp_state, int offset, char *value, int value_length)
2250 struct gatt_req_info *req_info = NULL;
2252 req_info = __bt_gatt_find_request_info(request_id);
2255 if (resp_state != BLUETOOTH_ERROR_NONE) {
2257 GQuark quark = g_quark_from_string("gatt-server");
2258 GError *err = g_error_new(quark, 0, "Application Error");
2259 g_dbus_method_invocation_return_gerror(req_info->context, err);
2262 gatt_requests = g_slist_remove(gatt_requests, req_info);
2264 req_info->context = NULL;
2265 if (req_info->attr_path)
2266 g_free(req_info->attr_path);
2267 if (req_info->svc_path)
2268 g_free(req_info->svc_path);
2271 return BLUETOOTH_ERROR_NONE;
2273 if (req_type == BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ) {
2275 GVariantBuilder *inner_builder = NULL;
2276 inner_builder = g_variant_builder_new(G_VARIANT_TYPE ("ay"));
2277 if (value_length > 0 && value != NULL) {
2278 for (i = 0; i < value_length; i++)
2279 g_variant_builder_add(inner_builder, "y", value[i]);
2281 g_dbus_method_invocation_return_value(req_info->context,
2282 g_variant_new("(ay)", inner_builder));
2283 g_variant_builder_unref(inner_builder);
2285 g_dbus_method_invocation_return_value(req_info->context, NULL);
2287 gatt_requests = g_slist_remove(gatt_requests, req_info);
2289 req_info->context = NULL;
2290 if (req_info->attr_path)
2291 g_free(req_info->attr_path);
2292 if (req_info->svc_path)
2293 g_free(req_info->svc_path);
2296 return BLUETOOTH_ERROR_INTERNAL;
2299 return BLUETOOTH_ERROR_NONE;
2302 BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path,
2303 bluetooth_device_address_t *unicast_address)
2305 GVariantBuilder *outer_builder;
2306 GVariantBuilder *invalidated_builder;
2307 GError *error = NULL;
2308 gboolean notify = TRUE;
2309 gboolean ret = TRUE;
2310 int err = BLUETOOTH_ERROR_NONE;
2311 gchar **line_argv = NULL;
2312 gchar *serv_path = NULL;
2313 char addr[20] = { 0 };
2315 line_argv = g_strsplit_set(char_path, "/", 0);
2316 serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]);
2318 if (!__bt_gatt_get_service_state(serv_path)) {
2319 BT_DBG("service not registered for this characteristic \n");
2320 g_strfreev(line_argv);
2321 return BLUETOOTH_ERROR_INTERNAL;
2324 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2325 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2327 g_variant_builder_add(outer_builder, "{sv}", "Notifying",
2328 g_variant_new("b", notify));
2330 if (unicast_address) {
2331 _bt_convert_addr_type_to_string(addr,
2332 (unsigned char *)unicast_address->addr);
2334 g_variant_builder_add(outer_builder, "{sv}", "Unicast",
2335 g_variant_new("s", addr));
2337 BT_DBG("Set characteristic Notification \n");
2338 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2340 "org.freedesktop.DBus.Properties",
2341 "PropertiesChanged",
2342 g_variant_new("(sa{sv}as)",
2343 "org.bluez.GattCharacteristic1",
2344 outer_builder, invalidated_builder),
2348 if (error != NULL) {
2349 BT_ERR("D-Bus API failure: errCode[%x], \
2351 error->code, error->message);
2352 g_clear_error(&error);
2354 err = BLUETOOTH_ERROR_INTERNAL;
2357 g_strfreev(line_argv);
2358 g_variant_builder_unref(outer_builder);
2359 g_variant_builder_unref(invalidated_builder);