2 * Bluetooth-frwk low energy
4 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Chanyeol Park <chanyeol.park@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
25 #include<glib/gprintf.h>
30 #include "bt-common.h"
32 #define NUMBER_OF_FLAGS 10
34 GDBusConnection *g_conn;
37 static gboolean new_service = FALSE;
38 static gboolean new_char = FALSE;
39 static int serv_id = 1;
40 static int register_pending_cnt = 0;
42 /* Introspection data for the service we are exporting */
43 static const gchar service_introspection_xml[] =
45 " <interface name='org.freedesktop.DBus.ObjectManager'>"
46 " <method name='GetManagedObjects'>"
47 " <arg type='a{oa{sa{sv}}}' name='object_paths_interfaces_and_properties' direction='out'/>"
50 " <interface name='org.bluez.GattService1'>"
51 " <property type='s' name='UUID' access='read'>"
53 " <property type='b' name='primary' access='read'>"
55 " <property type='o' name='Device' access='read'>"
57 " <property type='ao' name='Characteristics' access='read'>"
59 " <property type='s' name='Includes' access='read'>"
64 /* Introspection data for the characteristics we are exporting */
65 static const gchar characteristics_introspection_xml[] =
67 " <interface name='org.bluez.GattCharacteristic1'>"
68 " <method name='ReadValue'>"
69 " <arg type='s' name='address' direction='in'/>"
70 " <arg type='y' name='id' direction='in'/>"
71 " <arg type='q' name='offset' direction='in'/>"
72 " <arg type='ay' name='Value' direction='out'/>"
74 " <method name='WriteValue'>"
75 " <arg type='s' name='address' direction='in'/>"
76 " <arg type='y' name='id' direction='in'/>"
77 " <arg type='q' name='offset' direction='in'/>"
78 " <arg type='ay' name='value' direction='in'/>"
80 " <method name='StartNotify'>"
82 " <method name='StopNotify'>"
84 " <method name='IndicateConfirm'>"
85 " <arg type='s' name='address' direction='in'/>"
86 " <arg type='b' name='complete' direction='in'/>"
89 " <interface name='org.freedesktop.DBus.Properties'>"
90 " <property type='s' name='UUID' access='read'>"
92 " <property type='o' name='Service' access='read'>"
94 " <property type='ay' name='Value' access='readwrite'>"
96 " <property type='b' name='Notifying' access='read'>"
98 " <property type='as' name='Flags' access='read'>"
100 " <property type='s' name='Unicast' access='read'>"
102 " <property type='ao' name='Descriptors' access='read'>"
107 /* Introspection data for the descriptor we are exporting */
108 static const gchar descriptor_introspection_xml[] =
110 " <interface name='org.bluez.GattDescriptor1'>"
111 " <method name='ReadValue'>"
112 " <arg type='s' name='address' direction='in'/>"
113 " <arg type='y' name='id' direction='in'/>"
114 " <arg type='q' name='offset' direction='in'/>"
115 " <arg type='ay' name='Value' direction='out'/>"
117 " <method name='WriteValue'>"
118 " <arg type='s' name='address' direction='in'/>"
119 " <arg type='y' name='id' direction='in'/>"
120 " <arg type='q' name='offset' direction='in'/>"
121 " <arg type='ay' name='value' direction='in'/>"
124 " <interface name='org.freedesktop.DBus.Properties'>"
125 " <property type='s' name='UUID' access='read'>"
127 " <property type='o' name='Characteristic' access='read'>"
129 " <property type='ay' name='Value' access='read'>"
131 " <property type='s' name='Permissions' access='read'>"
136 struct gatt_service_info {
143 gboolean is_svc_registered;
144 gboolean is_svc_primary;
147 struct gatt_char_info {
152 gchar *char_flags[NUMBER_OF_FLAGS];
158 struct gatt_desc_info {
166 struct gatt_req_info {
171 GDBusMethodInvocation *context;
174 static GSList *gatt_services = NULL;
175 static GSList *gatt_requests = NULL;
177 #define BT_GATT_SERVICE_NAME "org.frwk.gatt_service"
178 #define BT_GATT_SERVICE_PATH "/org/frwk/gatt_service"
180 #define GATT_SERV_OBJECT_PATH "/service"
182 #define GATT_MNGR_INTERFACE "org.bluez.GattManager1"
183 #define GATT_SERV_INTERFACE "org.bluez.GattService1"
184 #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
185 #define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1"
188 #define BT_HPS_OBJECT_PATH "/org/projectx/httpproxy"
189 #define BT_HPS_INTERFACE_NAME "org.projectx.httpproxy_service"
190 #define PROPERTIES_CHANGED "PropertiesChanged"
191 #define BT_HPS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
194 static GDBusProxy *manager_gproxy = NULL;
196 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
197 const char *service_path, const char *char_path);
198 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
199 const char *serv_path, const char *char_path,
200 const char *desc_path);
202 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id);
205 static int __bt_send_event_to_hps(int event, GVariant *var)
207 GError *error = NULL;
208 GVariant *parameters;
209 GDBusMessage *msg = NULL;
213 retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
215 if (event == BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED) {
216 GVariantBuilder *inner_builder;
217 GVariantBuilder *invalidated_builder;
219 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
220 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
222 g_variant_builder_add(inner_builder, "{sv}", "WriteValue", var);
224 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
226 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
227 g_variant_builder_unref(invalidated_builder);
228 g_variant_builder_unref(inner_builder);
229 } else if (BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) {
230 GVariantBuilder *inner_builder;
231 GVariantBuilder *invalidated_builder;
233 BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED");
234 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
236 g_variant_builder_add(inner_builder, "{sv}", "ReadValue", var);
238 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
240 parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder);
241 g_variant_builder_unref(invalidated_builder);
242 g_variant_builder_unref(inner_builder);
245 msg = g_dbus_message_new_signal(BT_HPS_OBJECT_PATH, BT_HPS_INTERFACE_NAME, PROPERTIES_CHANGED);
246 g_dbus_message_set_body(msg, parameters);
247 if (!g_dbus_connection_send_message(g_conn, msg,G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) {
249 BT_ERR("D-Bus API failure: errCode[%x], \
251 error->code, error->message);
252 g_clear_error(&error);
254 return BLUETOOTH_ERROR_INTERNAL;
256 return BLUETOOTH_ERROR_NONE;
260 static void __bt_gatt_serv_method_call(GDBusConnection *connection,
262 const gchar *object_path,
263 const gchar *interface_name,
264 const gchar *method_name,
265 GVariant *parameters,
266 GDBusMethodInvocation *invocation,
271 if (g_strcmp0(method_name, "GetManagedObjects") == 0) {
272 BT_DBG("Getting values for service, chars and descriptors");
274 GVariantBuilder *builder;
275 GVariantBuilder *inner_builder1 = NULL;
276 GVariant *svc_char = NULL;
279 builder = g_variant_builder_new(
280 G_VARIANT_TYPE("a{oa{sa{sv}}}"));
282 /* Prepare inner builder for GattService1 interface */
284 GVariantBuilder *svc_builder = NULL;
285 GVariantBuilder *inner_builder = NULL;
287 if (register_pending_cnt > 1) {
288 int len = g_slist_length(gatt_services);
289 l1 = g_slist_nth(gatt_services, len - register_pending_cnt);
291 l1 = g_slist_last(gatt_services);
293 register_pending_cnt--;
295 struct gatt_service_info *serv_info = l1->data;
296 if (serv_info == NULL) {
297 BT_ERR("service info value is NULL");
298 g_dbus_method_invocation_return_value(invocation, NULL);
302 /* Prepare inner builder for GattService1 interface */
303 BT_DBG("Creating builder for service");
304 svc_builder = g_variant_builder_new(
305 G_VARIANT_TYPE("a{sa{sv}}"));
306 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
308 g_variant_builder_add(inner_builder, "{sv}", "UUID",
309 g_variant_new_string(serv_info->service_uuid));
311 g_variant_builder_add(inner_builder, "{sv}", "Primary",
312 g_variant_new_boolean(serv_info->is_svc_primary));
315 inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
316 BT_DBG("Adding Charatarisitcs list");
317 for (l4 = serv_info->char_data; l4 != NULL; l4 = l4->next) {
318 struct gatt_char_info *char_info = l4->data;
319 g_variant_builder_add(inner_builder1, "o",
320 char_info->char_path);
321 BT_DBG("%s", char_info->char_path);
324 svc_char = g_variant_new("ao", inner_builder1);
325 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
328 g_variant_builder_add(svc_builder, "{sa{sv}}",
332 g_variant_builder_add(builder, "{oa{sa{sv}}}",
333 serv_info->serv_path,
336 g_variant_builder_unref(inner_builder1);
338 /* Prepare inner builder for GattCharacteristic1 interface */
340 GSList *l2 = serv_info->char_data;
341 BT_DBG("Creating builder for characteristics \n");
344 BT_DBG("characteristic data is NULL");
346 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
348 GVariantBuilder *char_builder = NULL;
349 GVariantBuilder *inner_builder = NULL;
350 GVariantBuilder *builder1 = NULL;
351 GVariantBuilder *builder2 = NULL;
352 GVariantBuilder *builder3 = NULL;
353 GVariant *char_val = NULL;
354 GVariant *flags_val = NULL;
355 GVariant *char_desc = NULL;
356 char *unicast = NULL;
357 gboolean notify = FALSE;
360 char_builder = g_variant_builder_new(
363 inner_builder = g_variant_builder_new(
367 struct gatt_char_info *char_info = l2->data;
368 if (char_info == NULL) {
369 BT_ERR("char_info is NULL");
374 g_variant_builder_add(inner_builder, "{sv}", "UUID",
375 g_variant_new_string(char_info->char_uuid));
377 g_variant_builder_add(inner_builder, "{sv}", "Service",
378 g_variant_new("o", serv_info->serv_path));
380 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
382 if(char_info->char_value != NULL) {
383 for (i = 0; i < char_info->value_length; i++) {
384 g_variant_builder_add(builder1, "y",
385 char_info->char_value[i]);
387 char_val = g_variant_new("ay", builder1);
388 g_variant_builder_add(inner_builder, "{sv}",
392 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
394 for (i = 0; i < char_info->flags_length; i++) {
395 g_variant_builder_add(builder2, "s",
396 char_info->char_flags[i]);
399 flags_val = g_variant_new("as", builder2);
400 g_variant_builder_add(inner_builder, "{sv}", "Flags",
404 g_variant_builder_add(inner_builder, "{sv}", "Notifying",
405 g_variant_new("b", notify));
408 unicast = g_strdup("00:00:00:00:00:00");
409 g_variant_builder_add(inner_builder, "{sv}", "Unicast",
410 g_variant_new("s", unicast));
413 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
414 BT_DBG("Adding Descriptors list");
416 for (l4 = char_info->desc_data; l4 != NULL; l4 = l4->next) {
417 struct gatt_desc_info *desc_info = l4->data;
418 g_variant_builder_add(builder3, "o",
419 desc_info->desc_path);
420 BT_DBG("%s", desc_info->desc_path);
423 char_desc = g_variant_new("ao", builder3);
424 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
427 g_variant_builder_add(char_builder, "{sa{sv}}",
428 GATT_CHAR_INTERFACE , inner_builder);
429 g_variant_builder_add(builder, "{oa{sa{sv}}}",
430 char_info->char_path, char_builder);
432 /*Prepare inner builder for GattDescriptor1 interface*/
434 GSList *l3 = char_info->desc_data;
437 BT_DBG("descriptor data is NULL");
439 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
441 BT_DBG("Creating builder for descriptor \n");
443 GVariantBuilder *desc_builder = NULL;
444 GVariantBuilder *inner_builder = NULL;
445 GVariantBuilder *builder1 = NULL;
446 GVariant *desc_val = NULL;
448 desc_builder = g_variant_builder_new(
451 inner_builder = g_variant_builder_new(
455 struct gatt_desc_info *desc_info = l3->data;
456 if (desc_info == NULL) {
457 BT_ERR("desc_info is NULL");
462 g_variant_builder_add(inner_builder,
464 g_variant_new_string(
465 desc_info->desc_uuid));
468 g_variant_builder_add(inner_builder, "{sv}",
471 char_info->char_path));
474 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
476 if(desc_info->desc_value != NULL) {
477 for (i = 0; i < desc_info->value_length; i++) {
478 g_variant_builder_add(builder1, "y",
479 desc_info->desc_value[i]);
481 desc_val = g_variant_new("ay", builder1);
482 g_variant_builder_add(inner_builder, "{sv}",
486 g_variant_builder_add(desc_builder, "{sa{sv}}",
490 g_variant_builder_add(builder, "{oa{sa{sv}}}",
491 desc_info->desc_path,
494 /*unref descriptor builder pointers*/
495 g_variant_builder_unref(builder1);
496 g_variant_builder_unref(inner_builder);
497 g_variant_builder_unref(desc_builder);
502 /*unref char builder pointers*/
503 g_variant_builder_unref(builder1);
504 g_variant_builder_unref(builder2);
505 g_variant_builder_unref(builder3);
506 g_variant_builder_unref(inner_builder);
507 g_variant_builder_unref(char_builder);
510 /*unref service builder pointers*/
511 g_variant_builder_unref(inner_builder);
512 g_variant_builder_unref(svc_builder);
514 /* Return builder as method reply */
515 BT_DBG("Sending gatt service builder values to Bluez");
516 g_dbus_method_invocation_return_value(invocation,
523 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const char *char_path)
527 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
528 struct gatt_service_info *serv_info = l1->data;
530 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
531 struct gatt_char_info *char_info = l2->data;
533 if (g_strcmp0(char_info->char_path, char_path)
538 BT_ERR("Gatt service not found");
542 static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const char *desc_path)
544 GSList *l1, *l2, *l3;
546 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
547 struct gatt_service_info *serv_info = l1->data;
549 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
550 struct gatt_char_info *char_info = l2->data;
552 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
553 struct gatt_desc_info *desc_info = l3->data;
555 if (g_strcmp0(desc_info->desc_path, desc_path)
561 BT_ERR("Gatt service not found");
565 static struct gatt_char_info *__bt_gatt_find_gatt_char_from_desc(const char *desc_path)
567 GSList *l1, *l2, *l3;
569 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
570 struct gatt_service_info *serv_info = l1->data;
572 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
573 struct gatt_char_info *char_info = l2->data;
575 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
576 struct gatt_desc_info *desc_info = l3->data;
578 if (g_strcmp0(desc_info->desc_path, desc_path)
584 BT_ERR("Gatt Characterisitc not found");
588 static void __bt_gatt_char_method_call(GDBusConnection *connection,
590 const gchar *object_path,
591 const gchar *interface_name,
592 const gchar *method_name,
593 GVariant *parameters,
594 GDBusMethodInvocation *invocation,
598 if (g_strcmp0(method_name, "ReadValue") == 0) {
602 bt_gatt_read_req_t read_req = {0, };
603 bt_user_info_t *user_info = NULL;
604 struct gatt_req_info *req_info = NULL;
605 struct gatt_service_info *svc_info = NULL;
610 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
612 BT_DBG("Application path = %s", object_path);
614 BT_DBG("Remote Device address number = %s", addr);
615 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
617 BT_DBG("Sender = %s", sender);
619 read_req.att_handle = g_strdup(object_path);
620 read_req.address = g_strdup(addr);
621 read_req.req_id = req_id;
622 read_req.offset = offset;
623 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
624 if (svc_info != NULL) {
625 read_req.service_handle = g_strdup(svc_info->serv_path);
626 user_info = _bt_get_user_data(BT_COMMON);
628 GVariant *param = NULL;
631 /* Store requets information */
632 req_info = g_new0(struct gatt_req_info, 1);
633 req_info->attr_path = g_strdup(object_path);
634 req_info->svc_path = g_strdup(read_req.service_handle);
635 req_info->request_id= req_id;
636 req_info->offset = offset;
637 req_info->context = invocation;
638 gatt_requests = g_slist_append(gatt_requests, req_info);
640 if (user_info != NULL) {
641 struct gatt_char_info *char_info = NULL;
643 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
644 BLUETOOTH_ERROR_NONE, &read_req,
645 user_info->cb, user_info->user_data);
648 param = g_variant_new("(sssyq)",
650 read_req.service_handle,
654 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param);
658 if (read_req.att_handle)
659 g_free(read_req.att_handle);
660 if (read_req.address)
661 g_free(read_req.address);
662 if (read_req.service_handle)
663 g_free(read_req.service_handle);
665 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
666 GVariant *var = NULL;
670 bt_gatt_value_change_t value_change = {0, };
671 bt_user_info_t *user_info = NULL;
673 struct gatt_service_info *svc_info = NULL;
674 struct gatt_req_info *req_info = NULL;
676 GVariant *param = NULL;
679 BT_DBG("WriteValue");
680 BT_DBG("Application path = %s", object_path);
681 BT_DBG("Sender = %s", sender);
683 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
685 value_change.att_handle = g_strdup(object_path);
686 value_change.address = g_strdup(addr);
687 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
688 if (svc_info == NULL) {
689 g_variant_unref(var);
690 g_dbus_method_invocation_return_value(invocation, NULL);
694 value_change.service_handle = g_strdup(svc_info->serv_path);
695 value_change.offset = offset;
696 value_change.req_id = req_id;
698 len = g_variant_get_size(var);
702 value_change.att_value = (guint8 *)malloc(len);
703 if (!value_change.att_value) {
704 BT_ERR("att_value is NULL");
705 g_variant_unref(var);
706 g_dbus_method_invocation_return_value(invocation, NULL);
710 data = (char *)g_variant_get_data(var);
711 memcpy(value_change.att_value, data, len);
714 value_change.val_len = len;
716 /* Store requets information */
717 req_info = g_new0(struct gatt_req_info, 1);
718 req_info->attr_path = g_strdup(object_path);
719 req_info->svc_path = g_strdup(value_change.service_handle);
720 req_info->request_id= req_id;
721 req_info->offset = offset;
722 req_info->context = invocation;
723 gatt_requests = g_slist_append(gatt_requests, req_info);
725 user_info = _bt_get_user_data(BT_COMMON);
726 if (user_info != NULL) {
728 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
729 BLUETOOTH_ERROR_NONE, &value_change,
730 user_info->cb, user_info->user_data);
735 svc_path = g_strdup(svc_info->serv_path);
736 param = g_variant_new("(sssyq@ay)",
743 __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, param);
748 g_variant_unref(var);
750 } else if (g_strcmp0(method_name, "StartNotify") == 0) {
751 bt_user_info_t *user_info = NULL;
752 bt_gatt_char_notify_change_t notify_change = {0, };
753 BT_DBG("StartNotify");
754 user_info = _bt_get_user_data(BT_COMMON);
755 if (user_info != NULL) {
756 struct gatt_service_info *svc_info = NULL;
757 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
759 notify_change.service_handle = g_strdup(svc_info->serv_path);
760 notify_change.att_handle = g_strdup(object_path);
761 notify_change.att_notify = TRUE;
763 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
764 BLUETOOTH_ERROR_NONE, ¬ify_change,
765 user_info->cb, user_info->user_data);
768 } else if (g_strcmp0(method_name, "StopNotify") == 0) {
769 bt_user_info_t *user_info = NULL;
770 bt_gatt_char_notify_change_t notify_change = {0, };
771 BT_DBG("StopNotify");
772 user_info = _bt_get_user_data(BT_COMMON);
773 if (user_info != NULL) {
774 struct gatt_service_info *svc_info = NULL;
775 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
777 notify_change.service_handle = g_strdup(svc_info->serv_path);
778 notify_change.att_handle = g_strdup(object_path);
779 notify_change.att_notify = FALSE;
781 BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED,
782 BLUETOOTH_ERROR_NONE, ¬ify_change,
783 user_info->cb, user_info->user_data);
786 } else if (g_strcmp0(method_name, "IndicateConfirm") == 0) {
788 bt_gatt_indicate_confirm_t confirm = {0, };
789 bt_user_info_t *user_info = NULL;
790 gboolean complete = 0;
791 struct gatt_service_info *svc_info = NULL;
793 BT_DBG("IndicateConfirm");
794 BT_DBG("Application path = %s", object_path);
795 BT_DBG("Sender = %s", sender);
797 g_variant_get(parameters, "(&sb)", &addr, &complete);
799 BT_DBG("Remote Device address number = %s", addr);
800 confirm.att_handle = g_strdup(object_path);
801 confirm.address = g_strdup(addr);
802 confirm.complete = complete;
804 svc_info = __bt_gatt_find_gatt_service_from_char(object_path);
805 if (svc_info != NULL) {
806 confirm.service_handle = g_strdup(svc_info->serv_path);
807 user_info = _bt_get_user_data(BT_COMMON);
809 if (user_info != NULL) {
811 BLUETOOTH_EVENT_GATT_SERVER_INDICATE_CONFIRMED,
812 BLUETOOTH_ERROR_NONE, &confirm,
813 user_info->cb, user_info->user_data);
817 g_dbus_method_invocation_return_value(invocation, NULL);
820 static void __bt_gatt_desc_method_call(GDBusConnection *connection,
822 const gchar *object_path,
823 const gchar *interface_name,
824 const gchar *method_name,
825 GVariant *parameters,
826 GDBusMethodInvocation *invocation,
829 GVariantBuilder *inner_builder = NULL;
832 if (g_strcmp0(method_name, "ReadValue") == 0) {
836 bt_gatt_read_req_t read_req = {0, };
837 bt_user_info_t *user_info = NULL;
838 struct gatt_req_info *req_info = NULL;
839 struct gatt_service_info *svc_info = NULL;
842 g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset);
844 BT_DBG("Application path = %s", object_path);
846 BT_DBG("Remote Device address number = %s", addr);
847 BT_DBG("Request id = %d, Offset = %d", req_id, offset);
849 BT_DBG("Sender = %s", sender);
851 read_req.att_handle = g_strdup(object_path);
852 read_req.address = g_strdup(addr);
853 read_req.req_id = req_id;
854 read_req.offset = offset;
855 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
856 if (svc_info != NULL) {
857 read_req.service_handle = g_strdup(svc_info->serv_path);
858 user_info = _bt_get_user_data(BT_COMMON);
860 /* Store requets information */
861 req_info = g_new0(struct gatt_req_info, 1);
862 req_info->attr_path = g_strdup(object_path);
863 req_info->svc_path = g_strdup(read_req.service_handle);
864 req_info->request_id= req_id;
865 req_info->offset = offset;
866 req_info->context = invocation;
867 gatt_requests = g_slist_append(gatt_requests, req_info);
869 if (user_info != NULL) {
870 struct gatt_char_info *char_info = NULL;
873 BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED,
874 BLUETOOTH_ERROR_NONE, &read_req,
875 user_info->cb, user_info->user_data);
879 if (read_req.att_handle)
880 g_free(read_req.att_handle);
881 if (read_req.address)
882 g_free(read_req.address);
883 if (read_req.service_handle)
884 g_free(read_req.service_handle);
887 } else if (g_strcmp0(method_name, "WriteValue") == 0) {
888 GVariant *var = NULL;
892 bt_gatt_value_change_t value_change = {0, };
893 bt_user_info_t *user_info = NULL;
895 struct gatt_service_info *svc_info = NULL;
896 struct gatt_req_info *req_info = NULL;
898 BT_DBG("WriteValue");
899 BT_DBG("Application path = %s", object_path);
900 BT_DBG("Sender = %s", sender);
902 g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var);
904 value_change.att_handle = g_strdup(object_path);
905 value_change.address = g_strdup(addr);
906 svc_info = __bt_gatt_find_gatt_service_from_desc(object_path);
907 if (svc_info == NULL) {
908 g_variant_unref(var);
909 g_dbus_method_invocation_return_value(invocation, NULL);
913 value_change.service_handle = g_strdup(svc_info->serv_path);
914 value_change.offset = offset;
915 value_change.req_id = req_id;
917 len = g_variant_get_size(var);
921 value_change.att_value = (guint8 *)malloc(len);
922 if (!value_change.att_value) {
923 BT_ERR("att_value is NULL");
924 g_variant_unref(var);
925 g_dbus_method_invocation_return_value(invocation, NULL);
928 data = (char *)g_variant_get_data(var);
929 memcpy(value_change.att_value, data, len);
931 g_variant_unref(var);
933 value_change.val_len = len;
935 /* Store requets information */
936 req_info = g_new0(struct gatt_req_info, 1);
937 req_info->attr_path = g_strdup(object_path);
938 req_info->svc_path = g_strdup(value_change.service_handle);
939 req_info->request_id= req_id;
940 req_info->offset = offset;
941 req_info->context = invocation;
942 gatt_requests = g_slist_append(gatt_requests, req_info);
944 user_info = _bt_get_user_data(BT_COMMON);
945 if (user_info != NULL) {
947 BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED,
948 BLUETOOTH_ERROR_NONE, &value_change,
949 user_info->cb, user_info->user_data);
953 g_dbus_method_invocation_return_value(invocation, NULL);
956 gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface)
959 GError *error = NULL;
960 GVariantBuilder *array_builder;
962 array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
963 g_variant_builder_init(array_builder, G_VARIANT_TYPE ("as"));
964 g_variant_builder_add(array_builder, "s", interface);
966 ret = g_dbus_connection_emit_signal(g_conn, NULL, "/",
967 "org.freedesktop.Dbus.Objectmanager",
969 g_variant_new ("(oas)",
970 object_path, array_builder),
975 /* dbus gives error cause */
976 BT_ERR("d-bus api failure: errcode[%x], message[%s]",
977 error->code, error->message);
978 g_clear_error(&error);
981 g_variant_builder_unref(array_builder);
986 static const GDBusInterfaceVTable desc_interface_vtable = {
987 __bt_gatt_desc_method_call,
992 static const GDBusInterfaceVTable char_interface_vtable = {
993 __bt_gatt_char_method_call,
998 static const GDBusInterfaceVTable serv_interface_vtable = {
999 __bt_gatt_serv_method_call,
1005 static GDBusNodeInfo *__bt_gatt_create_method_node_info(
1006 const gchar *introspection_data)
1009 GDBusNodeInfo *node_info = NULL;
1011 if (introspection_data == NULL)
1014 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
1017 BT_ERR("Unable to create node: %s", err->message);
1018 g_clear_error(&err);
1023 static struct gatt_service_info *__bt_gatt_find_gatt_service_info(
1024 const char *service_path)
1028 for (l = gatt_services; l != NULL; l = l->next) {
1029 struct gatt_service_info *info = l->data;
1031 if (g_strcmp0(info->serv_path, service_path) == 0)
1034 BT_ERR("Gatt service not found");
1038 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
1039 const char *service_path, const char *char_path)
1043 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1044 struct gatt_service_info *serv_info = l1->data;
1046 if (g_strcmp0(serv_info->serv_path, service_path) == 0) {
1048 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1049 struct gatt_char_info *char_info = l2->data;
1051 if (g_strcmp0(char_info->char_path, char_path)
1055 BT_ERR("Gatt characteristic not found");
1059 BT_ERR("Gatt service not found");
1063 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
1064 const char *serv_path, const char *char_path,
1065 const char *desc_path)
1067 GSList *l1, *l2, *l3;
1069 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1070 struct gatt_service_info *serv_info = l1->data;
1072 if (g_strcmp0(serv_info->serv_path, serv_path) == 0) {
1073 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1074 struct gatt_char_info *char_info = l2->data;
1076 if (g_strcmp0(char_info->char_path, char_path)
1078 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
1079 struct gatt_desc_info *desc_info = l3->data;
1080 if (g_strcmp0(desc_info->desc_path,
1089 BT_ERR("Gatt descriptor not found");
1093 static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id)
1097 for (l = gatt_requests; l != NULL; l = l->next) {
1098 struct gatt_req_info *req_info = l->data;
1100 if (req_info && req_info->request_id == request_id) {
1104 BT_ERR("Gatt Request not found");
1108 static int char_info_cmp(gconstpointer a1, gconstpointer a2)
1110 const struct gatt_char_info *attrib1 = a1;
1111 const struct gatt_char_info *attrib2 = a2;
1113 return g_strcmp0(attrib1->char_path, attrib2->char_path);
1116 static int desc_info_cmp(gconstpointer a1, gconstpointer a2)
1118 const struct gatt_desc_info *attrib1 = a1;
1119 const struct gatt_desc_info *attrib2 = a2;
1121 return g_strcmp0(attrib1->desc_path, attrib2->desc_path);
1124 static gboolean __bt_gatt_update_attribute_info(struct gatt_req_info *req_info,
1125 char *value, int value_length)
1127 GSList *l1, *l2, *l3;
1129 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
1130 struct gatt_service_info *serv_info = l1->data;
1132 if (serv_info && g_strcmp0(serv_info->serv_path, req_info->svc_path) == 0) {
1134 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
1135 struct gatt_char_info *char_info = l2->data;
1138 if (g_strcmp0(char_info->char_path, req_info->attr_path) == 0) {
1139 memcpy(&char_info->char_value[req_info->offset], value, value_length);
1140 serv_info->char_data = g_slist_insert_sorted (serv_info->char_data, char_info, char_info_cmp);
1144 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
1145 struct gatt_desc_info *desc_info = l3->data;
1147 if (desc_info && g_strcmp0(desc_info->desc_path, req_info->attr_path)
1149 memcpy(&desc_info->desc_value[req_info->offset], value, value_length);
1150 char_info->desc_data = g_slist_insert_sorted (char_info->desc_data, desc_info, desc_info_cmp);
1166 static GDBusProxy *__bt_gatt_gdbus_init_manager_proxy(const gchar *service,
1167 const gchar *path, const gchar *interface)
1173 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
1178 BT_ERR("Unable to connect to gdbus: %s", err->message);
1179 g_clear_error(&err);
1184 proxy = g_dbus_proxy_new_sync(g_conn,
1185 G_DBUS_PROXY_FLAGS_NONE, NULL,
1187 interface, NULL, &err);
1191 BT_ERR("Unable to create proxy: %s", err->message);
1192 g_clear_error(&err);
1196 manager_gproxy = proxy;
1201 static GDBusProxy *__bt_gatt_gdbus_get_manager_proxy(const gchar *service,
1202 const gchar *path, const gchar *interface)
1204 return (manager_gproxy) ? manager_gproxy :
1205 __bt_gatt_gdbus_init_manager_proxy(service,
1209 int bluetooth_gatt_convert_prop2string(
1210 bt_gatt_characteristic_property_t properties,
1211 char *char_properties[])
1215 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) {
1216 char_properties[flag_count] = g_strdup("broadcast");
1219 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) {
1220 char_properties[flag_count] = g_strdup("read");
1223 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) {
1224 char_properties[flag_count] = g_strdup("write-without-response");
1227 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) {
1228 char_properties[flag_count] = g_strdup("write");
1231 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) {
1232 char_properties[flag_count] = g_strdup("notify");
1235 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) {
1236 char_properties[flag_count] = g_strdup("indicate");
1239 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) {
1240 char_properties[flag_count] = g_strdup("authenticated-signed-writes");
1244 if (flag_count == 0) {
1245 char_properties[flag_count] = g_strdup("read");
1252 static void __bt_gatt_set_service_state(const char *service_path,
1255 struct gatt_service_info *svc_info = NULL;
1256 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1258 if (svc_info != NULL) {
1259 BT_DBG("Updating the gatt service register state %d", state);
1260 svc_info->is_svc_registered = state;
1264 BT_DBG("gatt service not found");
1267 static gboolean __bt_gatt_get_service_state(const char *service_path)
1269 struct gatt_service_info *svc_info = NULL;
1271 svc_info = __bt_gatt_find_gatt_service_info(service_path);
1273 if (svc_info != NULL) {
1274 BT_DBG("Return the state of the gatt service %d",
1275 svc_info->is_svc_registered);
1276 return svc_info->is_svc_registered;
1279 BT_DBG("gatt service info is NULL");
1283 void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1285 GError *error = NULL;
1287 GVariantIter *iter = NULL;
1288 const gchar *key = NULL;
1289 GVariant *value = NULL;
1290 const gchar *service = NULL;
1291 const gchar *characteristic = NULL;
1292 const gchar *descriptor = NULL;
1296 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1298 if (result == NULL) {
1299 /* dBUS-RPC is failed */
1300 BT_ERR("Dbus-RPC is failed\n");
1302 if (error != NULL) {
1303 /* dBUS gives error cause */
1304 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1305 error->code, error->message);
1306 g_clear_error(&error);
1309 char *char_cmp = NULL;
1310 g_variant_get (result, "(a{sv})", &iter);
1311 char_cmp = g_strdup_printf("Characteristic%d", n_char);
1313 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
1314 if (g_strcmp0(key, "Service") == 0) {
1315 service = g_variant_get_string(value, NULL);
1316 BT_DBG("Service %s", service);
1317 } else if (g_strcmp0(key, char_cmp) == 0) {
1318 characteristic = g_variant_get_string(value, NULL);
1320 char_cmp = g_strdup_printf("Characteristic%d", ++n_char);
1321 BT_DBG("%s", characteristic);
1322 } else if (g_strcmp0(key, "Descriptor") == 0) {
1323 descriptor = g_variant_get_string(value, NULL);
1324 BT_DBG("Descriptor %s", descriptor);
1327 /* TODO: Store the service informationa and
1328 * Send respponse to CAPI layer. */
1330 g_variant_unref(result);
1335 void register_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
1337 BT_DBG("register_service_cb\n");
1339 GError *error = NULL;
1342 register_pending_cnt = 0;
1344 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1346 if (result == NULL) {
1347 /* dBUS-RPC is failed */
1348 BT_ERR("Dbus-RPC is failed\n");
1350 if (error != NULL) {
1351 /* dBUS gives error cause */
1352 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1353 error->code, error->message);
1354 g_clear_error(&error);
1359 void unregister_service_cb(GObject *object, GAsyncResult *res,
1362 BT_DBG("unregister_service_cb\n");
1364 GError *error = NULL;
1367 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
1369 if (result == NULL) {
1370 /* dBUS-RPC is failed */
1371 BT_ERR("Dbus-RPC is failed\n");
1373 if (error != NULL) {
1374 /* dBUS gives error cause */
1375 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
1376 error->code, error->message);
1377 g_clear_error(&error);
1382 static int __bt_gatt_unregister_service(const char *service_path)
1384 if (!__bt_gatt_get_service_state(service_path)) {
1385 BT_DBG("service not registered \n");
1386 return BLUETOOTH_ERROR_NOT_FOUND;
1389 GDBusProxy *proxy = NULL;
1391 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1392 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
1395 return BLUETOOTH_ERROR_INTERNAL;
1397 /* Async Call to Unregister Service */
1398 g_dbus_proxy_call(proxy,
1399 "UnregisterService",
1400 g_variant_new("(o)",
1402 G_DBUS_CALL_FLAGS_NONE, -1,
1404 (GAsyncReadyCallback) unregister_service_cb,
1407 __bt_gatt_set_service_state(service_path, FALSE);
1409 return BLUETOOTH_ERROR_NONE;
1412 static GDBusConnection *__bt_gatt_get_gdbus_connection(void)
1414 GDBusConnection *local_system_gconn = NULL;
1417 if (g_conn == NULL) {
1418 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1421 BT_ERR("Unable to connect to dbus: %s", err->message);
1422 g_clear_error(&err);
1426 } else if (g_dbus_connection_is_closed(g_conn)) {
1427 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1429 if (!local_system_gconn) {
1430 BT_ERR("Unable to connect to dbus: %s", err->message);
1431 g_clear_error(&err);
1434 g_conn = local_system_gconn;
1440 BT_EXPORT_API int bluetooth_gatt_init(void)
1442 GDBusConnection *conn;
1444 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
1445 BT_GATT_SERVICE_NAME,
1446 G_BUS_NAME_OWNER_FLAGS_NONE,
1447 NULL, NULL, NULL, NULL, NULL);
1449 BT_DBG("owner_id is [%d]", owner_id);
1453 conn = __bt_gatt_get_gdbus_connection();
1455 BT_ERR("Unable to get connection");
1456 return BLUETOOTH_ERROR_INTERNAL;
1459 return BLUETOOTH_ERROR_NONE;
1462 BT_EXPORT_API int bluetooth_gatt_deinit()
1464 /* Unown gdbus bus */
1467 /* remove/unregister all services */
1468 BT_DBG("removing all registered gatt service\n");
1469 bluetooth_gatt_delete_services();
1471 g_bus_unown_name(owner_id);
1473 BT_DBG("Gatt service deinitialized \n");
1475 g_slist_free(gatt_services);
1476 gatt_services = NULL;
1478 return BLUETOOTH_ERROR_NONE;
1481 return BLUETOOTH_ERROR_NOT_FOUND;
1484 BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid,
1487 GError *error = NULL;
1489 GDBusNodeInfo *node_info;
1491 GVariantBuilder *builder = NULL;
1492 GVariantBuilder *builder1 = NULL;
1493 GVariantBuilder *inner_builder = NULL;
1494 gboolean svc_primary = TRUE;
1495 struct gatt_service_info *serv_info = NULL;
1497 node_info = __bt_gatt_create_method_node_info(
1498 service_introspection_xml);
1500 if (node_info == NULL)
1501 return BLUETOOTH_ERROR_INTERNAL;
1503 path = g_strdup_printf(GATT_SERV_OBJECT_PATH"%d", serv_id++);
1504 BT_DBG("gatt service path is [%s]", path);
1506 object_id = g_dbus_connection_register_object(g_conn, path,
1507 node_info->interfaces[0],
1508 &serv_interface_vtable,
1509 NULL, NULL, &error);
1511 if (object_id == 0) {
1512 BT_ERR("failed to register: %s", error->message);
1513 g_error_free(error);
1516 return BLUETOOTH_ERROR_INTERNAL;
1519 /* Add object_id/gatt service information; it's required at the time of
1520 * service unregister and Getmanagedobjects
1522 serv_info = g_new0(struct gatt_service_info, 1);
1524 serv_info->serv_path = g_strdup(path);
1525 serv_info->serv_id = object_id;
1526 serv_info->service_uuid = g_strdup(svc_uuid);
1527 serv_info->is_svc_registered = FALSE;
1528 serv_info->is_svc_primary = svc_primary;
1530 gatt_services = g_slist_append(gatt_services, serv_info);
1532 /* emit interfacesadded signal here for service path */
1533 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1534 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1536 g_variant_builder_add(inner_builder, "{sv}",
1537 "UUID", g_variant_new_string(svc_uuid));
1539 g_variant_builder_add(inner_builder, "{sv}",
1540 "Primary", g_variant_new_boolean(svc_primary));
1542 builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1544 g_variant_builder_add(inner_builder, "{sv}", "Characteristics",
1545 g_variant_new("ao", builder1));
1547 g_variant_builder_add(builder, "{sa{sv}}",
1548 GATT_SERV_INTERFACE, inner_builder);
1550 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1551 "org.freedesktop.Dbus.ObjectManager",
1553 g_variant_new("(oa{sa{sv}})",
1559 *svc_path = g_strdup(path);
1562 g_variant_builder_unref(inner_builder);
1563 g_variant_builder_unref(builder);
1564 g_variant_builder_unref(builder1);
1566 return BLUETOOTH_ERROR_NONE;
1569 BT_EXPORT_API int bluetooth_gatt_add_new_characteristic(
1570 const char *svc_path, const char *char_uuid,
1571 bt_gatt_characteristic_property_t properties,
1575 GError *error = NULL;
1577 GDBusNodeInfo *node_info;
1579 GVariantBuilder *builder = NULL;
1580 GVariantBuilder *inner_builder = NULL;
1581 struct gatt_service_info *serv_info = NULL;
1582 struct gatt_char_info *char_info = NULL;
1583 GVariantBuilder *builder2 = NULL;
1584 GVariantBuilder *builder3 = NULL;
1585 GVariant *flags_val = NULL;
1587 char *char_flags[NUMBER_OF_FLAGS];
1592 new_service = FALSE;
1595 BT_DBG("gatt svc_path path is [%s]", svc_path);
1596 serv_info = __bt_gatt_find_gatt_service_info(svc_path);
1597 if (serv_info == NULL)
1598 return BLUETOOTH_ERROR_INVALID_PARAM;
1600 node_info = __bt_gatt_create_method_node_info(
1601 characteristics_introspection_xml);
1603 if (node_info == NULL)
1604 return BLUETOOTH_ERROR_INTERNAL;
1606 path = g_strdup_printf("%s/characteristic%d", svc_path, char_id++);
1607 BT_DBG("gatt characteristic path is [%s]", path);
1609 object_id = g_dbus_connection_register_object(g_conn, path,
1610 node_info->interfaces[0],
1611 &char_interface_vtable,
1612 NULL, NULL, &error);
1614 if (object_id == 0) {
1615 BT_ERR("failed to register: %s", error->message);
1616 g_error_free(error);
1619 return BLUETOOTH_ERROR_INTERNAL;
1622 flag_count = bluetooth_gatt_convert_prop2string(properties, char_flags);
1624 char_info = g_new0(struct gatt_char_info, 1);
1626 char_info->char_path = g_strdup(path);
1627 char_info->char_id = object_id;
1628 char_info->char_uuid = g_strdup(char_uuid);
1630 for (i = 0; i < flag_count; i++) {
1631 char_info->char_flags[i] = char_flags[i];
1634 char_info->flags_length = flag_count;
1636 serv_info->char_data = g_slist_append(serv_info->char_data, char_info);
1638 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1639 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1641 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1642 g_variant_new("s", char_uuid));
1643 g_variant_builder_add(inner_builder, "{sv}", "Service",
1644 g_variant_new("o", svc_path));
1646 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1648 for (i = 0; i < flag_count; i++) {
1649 g_variant_builder_add(builder2, "s", char_flags[i]);
1652 flags_val = g_variant_new("as", builder2);
1653 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1656 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao"));
1658 g_variant_builder_add(inner_builder, "{sv}", "Descriptors",
1659 g_variant_new("ao", builder3));
1661 g_variant_builder_add(builder, "{sa{sv}}",
1662 GATT_CHAR_INTERFACE,
1665 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1666 "org.freedesktop.Dbus.ObjectManager",
1668 g_variant_new("(oa{sa{sv}})",
1672 *char_path = g_strdup(path);
1678 g_variant_builder_unref(inner_builder);
1679 g_variant_builder_unref(builder);
1680 g_variant_builder_unref(builder2);
1681 g_variant_builder_unref(builder3);
1683 return BLUETOOTH_ERROR_NONE;
1686 BT_EXPORT_API int bluetooth_gatt_set_characteristic_value(
1687 const char *characteristic, const char *char_value,
1690 gchar **line_argv = NULL;
1691 char *serv_path = NULL;
1692 struct gatt_char_info *char_info = NULL;
1693 GVariantBuilder *builder1 = NULL;
1694 GVariantBuilder *builder = NULL;
1695 GVariantBuilder *inner_builder = NULL;
1696 GVariant *char_val = NULL;
1697 GError *error = NULL;
1699 int res = BLUETOOTH_ERROR_NONE;
1701 line_argv = g_strsplit_set(characteristic, "/", 0);
1702 serv_path = g_strdup_printf("/%s", line_argv[1]);
1704 char_info = __bt_gatt_find_gatt_char_info(serv_path, characteristic);
1706 if (char_info == NULL) {
1707 /* Fix : RESOURCE_LEAK */
1708 res = BLUETOOTH_ERROR_INVALID_PARAM;
1712 char_info->value_length = value_length;
1714 char_info->char_value = (char *)malloc(value_length);
1715 /* Fix : NULL_RETURNS */
1716 if (char_info->char_value == NULL) {
1717 res = BLUETOOTH_ERROR_MEMORY_ALLOCATION;
1721 for (i = 0; i < value_length; i++)
1722 char_info->char_value[i] = char_value[i];
1724 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1725 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1727 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1729 for (i = 0; i < value_length; i++) {
1730 g_variant_builder_add(builder1, "y", char_value[i]);
1733 char_val = g_variant_new("ay", builder1);
1734 g_variant_builder_add(inner_builder, "{sv}", "Value", char_val);
1736 g_variant_builder_add(builder, "{sa{sv}}",
1737 GATT_CHAR_INTERFACE,
1740 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1741 "org.freedesktop.Dbus.ObjectManager",
1743 g_variant_new("(oa{sa{sv}})",
1744 char_info->char_path, builder),
1747 g_variant_builder_unref(inner_builder);
1748 g_variant_builder_unref(builder);
1749 g_variant_builder_unref(builder1);
1751 g_strfreev(line_argv);
1757 BT_EXPORT_API int bluetooth_gatt_add_descriptor(
1758 const char *char_path, const char *desc_uuid,
1761 static int desc_id = 1;
1762 GError *error = NULL;
1764 GDBusNodeInfo *node_info;
1766 GVariantBuilder *builder = NULL;
1767 GVariantBuilder *inner_builder = NULL;
1768 struct gatt_char_info *char_info = NULL;
1769 struct gatt_desc_info *desc_info = NULL;
1770 gchar **line_argv = NULL;
1778 line_argv = g_strsplit_set(char_path, "/", 0);
1779 serv_path = g_strdup_printf("/%s", line_argv[1]);
1781 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
1782 if (char_info == NULL) {
1783 g_strfreev(line_argv);
1784 return BLUETOOTH_ERROR_INVALID_PARAM;
1787 node_info = __bt_gatt_create_method_node_info(
1788 descriptor_introspection_xml);
1790 if (node_info == NULL) {
1791 g_strfreev(line_argv);
1792 return BLUETOOTH_ERROR_INTERNAL;
1795 path = g_strdup_printf("%s/descriptor%d", char_path, desc_id++);
1796 BT_DBG("gatt descriptor path is [%s]", path);
1798 object_id = g_dbus_connection_register_object(g_conn, path,
1799 node_info->interfaces[0],
1800 &desc_interface_vtable,
1801 NULL, NULL, &error);
1803 if (object_id == 0) {
1804 BT_ERR("failed to register: %s", error->message);
1805 g_error_free(error);
1807 g_strfreev(line_argv);
1809 return BLUETOOTH_ERROR_INTERNAL;
1812 desc_info = g_new0(struct gatt_desc_info, 1);
1814 desc_info->desc_path = g_strdup(path);
1815 desc_info->desc_id = object_id;
1816 desc_info->desc_uuid = g_strdup(desc_uuid);
1818 char_info->desc_data = g_slist_append(char_info->desc_data, desc_info);
1820 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1821 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1823 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1824 g_variant_new("s", desc_uuid));
1825 g_variant_builder_add(inner_builder, "{sv}", "Characteristic",
1826 g_variant_new("o", char_path));
1828 g_variant_builder_add(builder, "{sa{sv}}",
1829 GATT_DESC_INTERFACE,
1832 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1833 "org.freedesktop.Dbus.ObjectManager",
1835 g_variant_new("(oa{sa{sv}})",
1839 *desc_path = g_strdup(path);
1842 g_strfreev(line_argv);
1843 g_variant_builder_unref(inner_builder);
1844 g_variant_builder_unref(builder);
1846 return BLUETOOTH_ERROR_NONE;
1849 BT_EXPORT_API int bluetooth_gatt_set_descriptor_value(
1850 const char *desc_path, const char *desc_value,
1853 GError *error = NULL;
1854 GVariantBuilder *builder = NULL;
1855 GVariantBuilder *inner_builder = NULL;
1856 GVariantBuilder *builder1 = NULL;
1857 struct gatt_desc_info *desc_info = NULL;
1858 gchar **line_argv = NULL;
1860 GVariant *desc_val = NULL;
1861 char *serv_path = NULL;
1864 line_argv = g_strsplit_set(desc_path, "/", 0);
1865 serv_path = g_strdup_printf("/%s", line_argv[1]);
1866 char_path = g_strdup_printf("%s/%s", serv_path, line_argv[2]);
1868 desc_info = __bt_gatt_find_gatt_desc_info(serv_path, char_path, desc_path);
1870 /* Free the allocated memory */
1871 g_strfreev(line_argv);
1875 /* Fix : NULL_RETURNS */
1876 retv_if(desc_info == NULL, BLUETOOTH_ERROR_INVALID_PARAM);
1878 desc_info->desc_value = (char *)malloc(value_length);
1880 /* Fix : NULL_RETURNS */
1881 retv_if(desc_info->desc_value == NULL, BLUETOOTH_ERROR_MEMORY_ALLOCATION);
1883 for (i = 0; i < value_length; i++)
1884 desc_info->desc_value[i] = desc_value[i];
1886 desc_info->value_length = value_length;
1888 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1889 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1891 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1893 for (i = 0; i < value_length; i++) {
1894 g_variant_builder_add(builder1, "y", desc_value[i]);
1896 desc_val = g_variant_new("ay", builder1);
1897 g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val);
1899 g_variant_builder_add(builder, "{sa{sv}}",
1900 GATT_DESC_INTERFACE,
1903 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1904 "org.freedesktop.Dbus.ObjectManager",
1906 g_variant_new("(oa{sa{sv}})",
1907 desc_info->desc_path, builder),
1910 g_variant_builder_unref(inner_builder);
1911 g_variant_builder_unref(builder);
1912 g_variant_builder_unref(builder1);
1914 return BLUETOOTH_ERROR_NONE;
1917 int bluetooth_gatt_get_service(const char *svc_uuid)
1919 GDBusProxy *proxy = NULL;
1922 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1923 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
1925 return BLUETOOTH_ERROR_INTERNAL;
1927 uuid = g_strdup(svc_uuid);
1929 g_dbus_proxy_call(proxy,
1931 g_variant_new("(s)",
1933 G_DBUS_CALL_FLAGS_NONE, -1,
1935 (GAsyncReadyCallback) get_service_cb,
1940 return BLUETOOTH_ERROR_NONE;
1943 BT_EXPORT_API int bluetooth_gatt_register_service(
1944 const char *svc_path)
1946 GDBusProxy *proxy = NULL;
1949 register_pending_cnt++;
1951 if (__bt_gatt_get_service_state(svc_path)) {
1952 BT_DBG("service already registered \n");
1953 return BLUETOOTH_ERROR_NONE;
1956 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1957 "/org/bluez/hci0", GATT_MNGR_INTERFACE);
1959 return BLUETOOTH_ERROR_INTERNAL;
1961 path = g_strdup(svc_path);
1963 g_dbus_proxy_call(proxy,
1965 g_variant_new("(oa{sv})",
1967 G_DBUS_CALL_FLAGS_NONE, -1,
1969 (GAsyncReadyCallback) register_service_cb,
1972 __bt_gatt_set_service_state(svc_path, TRUE);
1976 return BLUETOOTH_ERROR_NONE;
1979 BT_EXPORT_API int bluetooth_gatt_delete_services(void)
1982 int error = BLUETOOTH_ERROR_NONE;
1986 for (l = gatt_services; l != NULL; l = l->next) {
1987 struct gatt_service_info *info = l->data;
1988 BT_DBG("svc_path is %s", info->serv_path);
1989 if (bluetooth_gatt_unregister_service(info->serv_path)
1990 != BLUETOOTH_ERROR_NONE) {
1991 error = BLUETOOTH_ERROR_INTERNAL;
1992 BT_DBG(" Error in removing service %s \n",
1996 BT_DBG(" All services removed successfully.\n ");
1999 BT_DBG(" There are no registered services.\n ");
2002 g_slist_free(gatt_services);
2003 gatt_services = NULL;
2006 if (error != BLUETOOTH_ERROR_NONE)
2009 return BLUETOOTH_ERROR_NONE;
2012 BT_EXPORT_API int bluetooth_gatt_update_characteristic(
2013 const char *char_path, const char* char_value,
2016 GVariantBuilder *outer_builder;
2017 GVariantBuilder *inner_builder;
2018 GVariantBuilder *invalidated_builder;
2019 GVariant *update_value = NULL;
2020 GError *error = NULL;
2021 gboolean ret = FALSE;
2022 int err = BLUETOOTH_ERROR_NONE;
2024 gchar **line_argv = NULL;
2025 gchar *serv_path = NULL;
2027 line_argv = g_strsplit_set(char_path, "/", 0);
2028 serv_path = g_strdup_printf("/%s", line_argv[1]);
2030 if (!__bt_gatt_get_service_state(serv_path)) {
2031 BT_DBG("service not registered for this characteristic \n");
2032 g_strfreev(line_argv);
2033 return BLUETOOTH_ERROR_INTERNAL;
2036 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2037 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2039 inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2040 for (i = 0; i < value_length; i++) {
2041 g_variant_builder_add(inner_builder, "y", char_value[i]);
2044 update_value = g_variant_new("ay", inner_builder);
2046 outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
2047 g_variant_builder_add(outer_builder, "{sv}", "Value",
2050 BT_DBG("Updating characteristic value \n");
2051 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2053 "org.freedesktop.DBus.Properties",
2054 "PropertiesChanged",
2055 g_variant_new("(sa{sv}as)",
2056 "org.bluez.GattCharacteristic1",
2057 outer_builder, invalidated_builder),
2061 if (error != NULL) {
2062 BT_ERR("D-Bus API failure: errCode[%x], \
2064 error->code, error->message);
2065 g_clear_error(&error);
2067 err = BLUETOOTH_ERROR_INTERNAL;
2069 struct gatt_char_info *char_info = NULL;
2071 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
2072 if (char_info == NULL) {
2073 return BLUETOOTH_ERROR_INVALID_DATA;
2076 char_info->value_length = value_length;
2078 char_info->char_value = (char *)realloc(char_info->char_value, value_length);
2079 if (char_info->char_value) {
2080 for (i = 0; i < value_length; i++) {
2081 char_info->char_value[i] = char_value[i];
2086 g_strfreev(line_argv);
2087 g_variant_builder_unref(inner_builder);
2088 g_variant_builder_unref(outer_builder);
2089 g_variant_builder_unref(invalidated_builder);
2094 BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path)
2097 struct gatt_service_info *svc_info;
2099 int err = BLUETOOTH_ERROR_NONE;
2102 BT_DBG("svc_path %s", svc_path);
2103 svc_info = __bt_gatt_find_gatt_service_info(svc_path);
2106 BT_ERR("Unable to find service info");
2107 return BLUETOOTH_ERROR_NOT_FOUND;
2110 err = __bt_gatt_unregister_service(svc_path);
2111 if (err != BLUETOOTH_ERROR_NONE) {
2112 BT_DBG("Could not unregister application");
2116 for (l = svc_info->char_data; l != NULL; l = l->next) {
2117 struct gatt_char_info *char_info = l->data;
2119 for (l1 = char_info->desc_data; l1 != NULL; l1 = l1->next) {
2120 struct gatt_desc_info *desc_info = l1->data;
2122 ret = g_dbus_connection_unregister_object(g_conn,
2123 desc_info->desc_id);
2125 __bt_gatt_emit_interface_removed(
2126 desc_info->desc_path,
2127 GATT_DESC_INTERFACE);
2129 err = BLUETOOTH_ERROR_INTERNAL;
2132 ret = g_dbus_connection_unregister_object(g_conn,
2133 char_info->char_id);
2135 __bt_gatt_emit_interface_removed(char_info->char_path,
2136 GATT_CHAR_INTERFACE);
2138 err = BLUETOOTH_ERROR_INTERNAL;
2141 ret = g_dbus_connection_unregister_object(g_conn, svc_info->serv_id);
2143 __bt_gatt_emit_interface_removed(svc_info->serv_path,
2144 GATT_SERV_INTERFACE);
2146 err = BLUETOOTH_ERROR_INTERNAL;
2149 ret = g_dbus_connection_unregister_object(g_conn, svc_info->prop_id);
2151 BT_DBG("Unregistered the service on properties interface");
2154 for (tmp = gatt_services; tmp != NULL; tmp = tmp->next) {
2155 struct gatt_service_info *info = tmp->data;
2157 if (g_strcmp0(info->serv_path, svc_path) == 0) {
2158 gatt_services = g_slist_delete_link(gatt_services, tmp->data);
2162 new_service = FALSE;
2164 if (gatt_services->next == NULL)
2170 BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type,
2171 int resp_state, int offset, char *value, int value_length)
2173 struct gatt_req_info *req_info = NULL;
2175 req_info = __bt_gatt_find_request_info(request_id);
2178 if (resp_state != BLUETOOTH_ERROR_NONE) {
2180 GQuark quark = g_quark_from_string("gatt-server");
2181 GError *err = g_error_new(quark, 0, "Application Error");
2182 g_dbus_method_invocation_return_gerror(req_info->context, err);
2185 gatt_requests = g_slist_remove(gatt_requests, req_info);
2187 req_info->context = NULL;
2188 if (req_info->attr_path)
2189 g_free(req_info->attr_path);
2190 if (req_info->svc_path)
2191 g_free(req_info->svc_path);
2194 return BLUETOOTH_ERROR_NONE;
2196 if (req_type == BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ) {
2198 GVariantBuilder *inner_builder = NULL;
2199 inner_builder = g_variant_builder_new(G_VARIANT_TYPE ("ay"));
2200 if (value_length > 0 && value != NULL) {
2201 for (i = 0; i < value_length; i++)
2202 g_variant_builder_add(inner_builder, "y", value[i]);
2204 g_dbus_method_invocation_return_value(req_info->context,
2205 g_variant_new("(ay)", inner_builder));
2206 g_variant_builder_unref(inner_builder);
2208 g_dbus_method_invocation_return_value(req_info->context, NULL);
2210 gatt_requests = g_slist_remove(gatt_requests, req_info);
2212 req_info->context = NULL;
2213 if (req_info->attr_path)
2214 g_free(req_info->attr_path);
2215 if (req_info->svc_path)
2216 g_free(req_info->svc_path);
2219 return BLUETOOTH_ERROR_INTERNAL;
2222 return BLUETOOTH_ERROR_NONE;
2225 BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path,
2226 bluetooth_device_address_t *unicast_address)
2228 GVariantBuilder *outer_builder;
2229 GVariantBuilder *invalidated_builder;
2230 GError *error = NULL;
2231 gboolean notify = TRUE;
2232 gboolean ret = TRUE;
2233 int err = BLUETOOTH_ERROR_NONE;
2234 gchar **line_argv = NULL;
2235 gchar *serv_path = NULL;
2236 char addr[20] = { 0 };
2238 line_argv = g_strsplit_set(char_path, "/", 0);
2239 serv_path = g_strdup_printf("/%s", line_argv[1]);
2241 if (!__bt_gatt_get_service_state(serv_path)) {
2242 BT_DBG("service not registered for this characteristic \n");
2243 g_strfreev(line_argv);
2244 return BLUETOOTH_ERROR_INTERNAL;
2247 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
2248 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
2250 g_variant_builder_add(outer_builder, "{sv}", "Notifying",
2251 g_variant_new("b", notify));
2253 if (unicast_address) {
2254 _bt_convert_addr_type_to_string(addr,
2255 (unsigned char *)unicast_address->addr);
2257 g_variant_builder_add(outer_builder, "{sv}", "Unicast",
2258 g_variant_new("s", addr));
2260 BT_DBG("Set characteristic Notification \n");
2261 ret = g_dbus_connection_emit_signal(g_conn, NULL,
2263 "org.freedesktop.DBus.Properties",
2264 "PropertiesChanged",
2265 g_variant_new("(sa{sv}as)",
2266 "org.bluez.GattCharacteristic1",
2267 outer_builder, invalidated_builder),
2271 if (error != NULL) {
2272 BT_ERR("D-Bus API failure: errCode[%x], \
2274 error->code, error->message);
2275 g_clear_error(&error);
2277 err = BLUETOOTH_ERROR_INTERNAL;
2280 g_strfreev(line_argv);
2281 g_variant_builder_unref(outer_builder);
2282 g_variant_builder_unref(invalidated_builder);