3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011 Nokia Corporation
6 * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "lib/bluetooth.h"
35 #include "src/adapter.h"
36 #include "src/shared/util.h"
37 #include "attrib/gattrib.h"
38 #include "attrib/att.h"
39 #include "attrib/gatt.h"
40 #include "attrib/att-database.h"
41 #include "src/attrib-server.h"
42 #include "attrib/gatt-service.h"
44 #ifdef __TIZEN_PATCH__
45 #include "src/device.h"
54 unsigned int num_attrs;
55 uint16_t *value_handle;
65 static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
67 if (src->type == BT_UUID16)
68 put_le16(src->value.u16, dst);
70 /* Convert from 128-bit BE to LE */
71 bswap_128(&src->value.u128, dst);
74 static GSList *parse_opts(gatt_option opt1, va_list args)
76 gatt_option opt = opt1;
77 struct gatt_info *info;
81 info = g_new0(struct gatt_info, 1);
82 l = g_slist_append(l, info);
84 while (opt != GATT_OPT_INVALID) {
86 case GATT_OPT_CHR_UUID16:
87 #ifdef __TIZEN_PATCH__
88 case GATT_OPT_DESC_UUID16:
90 bt_uuid16_create(&info->uuid, va_arg(args, int));
91 /* characteristic declaration and value */
94 case GATT_OPT_CHR_UUID:
95 #ifdef __TIZEN_PATCH__
96 case GATT_OPT_DESC_UUID:
98 memcpy(&info->uuid, va_arg(args, bt_uuid_t *),
100 /* characteristic declaration and value */
101 info->num_attrs += 2;
103 case GATT_OPT_CHR_PROPS:
104 #ifdef __TIZEN_PATCH__
105 case GATT_OPT_DESC_PROPS:
107 info->props = va_arg(args, int);
109 if (info->props & (GATT_CHR_PROP_NOTIFY |
110 GATT_CHR_PROP_INDICATE))
111 /* client characteristic configuration */
112 info->num_attrs += 1;
114 /* TODO: "Extended Properties" property requires a
115 * descriptor, but it is not supported yet. */
117 case GATT_OPT_CHR_VALUE_CB:
118 #ifdef __TIZEN_PATCH__
119 case GATT_OPT_DESC_VALUE_CB:
121 cb = g_new0(struct attrib_cb, 1);
122 cb->event = va_arg(args, attrib_event_t);
123 cb->fn = va_arg(args, void *);
124 cb->user_data = va_arg(args, void *);
125 info->callbacks = g_slist_append(info->callbacks, cb);
127 case GATT_OPT_CHR_VALUE_GET_HANDLE:
128 info->value_handle = va_arg(args, void *);
130 case GATT_OPT_CCC_GET_HANDLE:
131 info->ccc_handle = va_arg(args, void *);
133 case GATT_OPT_CHR_AUTHENTICATION:
134 info->authentication = va_arg(args, gatt_option);
136 case GATT_OPT_CHR_AUTHORIZATION:
137 info->authorization = va_arg(args, gatt_option);
139 case GATT_CHR_VALUE_READ:
140 case GATT_CHR_VALUE_WRITE:
141 case GATT_CHR_VALUE_BOTH:
142 case GATT_OPT_INVALID:
144 error("Invalid option: %d", opt);
147 opt = va_arg(args, gatt_option);
148 #ifdef __TIZEN_PATCH__
149 if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID ||
150 opt == GATT_OPT_DESC_UUID16 || opt == GATT_OPT_DESC_UUID) {
152 if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID) {
154 info = g_new0(struct gatt_info, 1);
155 l = g_slist_append(l, info);
162 static struct attribute *add_service_declaration(struct btd_adapter *adapter,
163 uint16_t handle, uint16_t svc, bt_uuid_t *uuid)
169 put_uuid_le(uuid, &atval[0]);
170 len = bt_uuid_len(uuid);
172 bt_uuid16_create(&bt_uuid, svc);
174 return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE,
175 ATT_NOT_PERMITTED, atval, len);
178 static int att_read_req(int authorization, int authentication, uint8_t props)
180 if (authorization == GATT_CHR_VALUE_READ ||
181 authorization == GATT_CHR_VALUE_BOTH)
182 return ATT_AUTHORIZATION;
183 else if (authentication == GATT_CHR_VALUE_READ ||
184 authentication == GATT_CHR_VALUE_BOTH)
185 return ATT_AUTHENTICATION;
186 else if (!(props & GATT_CHR_PROP_READ))
187 return ATT_NOT_PERMITTED;
192 static int att_write_req(int authorization, int authentication, uint8_t props)
194 if (authorization == GATT_CHR_VALUE_WRITE ||
195 authorization == GATT_CHR_VALUE_BOTH)
196 return ATT_AUTHORIZATION;
197 else if (authentication == GATT_CHR_VALUE_WRITE ||
198 authentication == GATT_CHR_VALUE_BOTH)
199 return ATT_AUTHENTICATION;
200 else if (!(props & (GATT_CHR_PROP_WRITE |
201 GATT_CHR_PROP_WRITE_WITHOUT_RESP)))
202 return ATT_NOT_PERMITTED;
207 static int find_callback(gconstpointer a, gconstpointer b)
209 const struct attrib_cb *cb = a;
210 unsigned int event = GPOINTER_TO_UINT(b);
212 return cb->event - event;
215 #ifdef __TIZEN_PATCH__
216 static gboolean add_descriptor(struct btd_adapter *adapter,
217 uint16_t *handle, struct gatt_info *info)
219 uint16_t h = *handle;
222 uint8_t atval[ATT_MAX_VALUE_LEN];
225 if (info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) {
226 error("Discriptors UUID or properties are missing");
230 /* Description declaration */
231 if (info->uuid.type == BT_UUID16)
232 bt_uuid16_create(&bt_uuid, info->uuid.value.u16);
234 bt_uuid128_create(&bt_uuid, info->uuid.value.u128);
236 put_uuid_le(&info->uuid, &atval[0]);
237 /* API not available in bluez 5.25
238 * att_put_uuid(info->uuid, &atval[0]);*/
240 a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
241 atval, info->uuid.type / 8);
247 for (l = info->callbacks; l != NULL; l = l->next) {
248 struct attrib_cb *cb = l->data;
255 a->write_cb = cb->fn;
259 a->cb_user_data = cb->user_data;
262 if (info->value_handle != NULL)
263 *info->value_handle = a->handle;
271 static gboolean add_characteristic(struct btd_adapter *adapter,
272 uint16_t *handle, struct gatt_info *info)
274 int read_req, write_req;
275 uint16_t h = *handle;
278 uint8_t atval[ATT_MAX_VALUE_LEN];
281 if ((info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) ||
283 error("Characteristic UUID or properties are missing");
287 read_req = att_read_req(info->authorization, info->authentication,
289 write_req = att_write_req(info->authorization, info->authentication,
292 /* TODO: static characteristic values are not supported, therefore a
293 * callback must be always provided if a read/write property is set */
294 if (read_req != ATT_NOT_PERMITTED) {
295 gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ);
297 if (!g_slist_find_custom(info->callbacks, reqs,
299 error("Callback for read required");
304 if (write_req != ATT_NOT_PERMITTED) {
305 gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
307 if (!g_slist_find_custom(info->callbacks, reqs,
309 error("Callback for write required");
314 /* characteristic declaration */
315 bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID);
316 atval[0] = info->props;
317 put_le16(h + 1, &atval[1]);
318 put_uuid_le(&info->uuid, &atval[3]);
319 if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
320 atval, 3 + info->uuid.type / 8) == NULL)
323 /* characteristic value */
324 a = attrib_db_add(adapter, h++, &info->uuid, read_req, write_req,
329 for (l = info->callbacks; l != NULL; l = l->next) {
330 struct attrib_cb *cb = l->data;
337 a->write_cb = cb->fn;
341 a->cb_user_data = cb->user_data;
344 if (info->value_handle != NULL)
345 *info->value_handle = a->handle;
347 #ifndef __TIZEN_PATCH__
348 /* Since old attrib service implementation add descriptor by default
349 * if notification and indication properties are set, As per new gatt server implemenation
350 * CCCD are added by the application*/
351 /* client characteristic configuration descriptor */
352 if (info->props & (GATT_CHR_PROP_NOTIFY | GATT_CHR_PROP_INDICATE)) {
355 bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID);
358 a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE,
359 ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val));
363 if (info->ccc_handle != NULL)
364 *info->ccc_handle = a->handle;
373 static void free_gatt_info(void *data)
375 struct gatt_info *info = data;
377 g_slist_free_full(info->callbacks, g_free);
381 static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
386 /* For a 128-bit category primary service below handle should be checked
387 * for both non-zero as well as >= 0xffff. As on last iteration the
388 * handle will turn to 0 from 0xffff and loop will be infinite.
390 for (handle = start_handle; (handle != 0 && handle <= end_handle);
392 if (attrib_db_del(adapter, handle) < 0)
393 error("Can't delete handle 0x%04x", handle);
397 #ifdef __TIZEN_PATCH__
398 static int is_gatt_connected(gconstpointer a1, gconstpointer a2)
400 const struct btd_device *dev = a1;
402 if (device_get_gatt_connected(dev))
408 bool gatt_send_noty_ind(struct btd_adapter *adapter, const bt_uuid_t *uuid,
409 uint8_t *value, size_t len)
413 GList *l, *connections;
414 struct btd_device *dev;
415 uint16_t desc_handle;
417 a = attribute_find(adapter, uuid);
421 desc_handle = a->handle + 1;
423 connections = (GList *)btd_adapter_get_connections(adapter);
426 l = g_list_find_custom(connections, GUINT_TO_POINTER(NULL),
430 attrib = attrib_from_device(dev);
432 /* Send the characteristic handle and value
433 * as notification or indication*/
434 attrib_send_noty_ind(dev, attrib, a->handle,
435 desc_handle, value, len);
436 g_attrib_unref(attrib);
438 connections = (GList *)g_slist_next(connections);
446 bool gatt_update_db(struct btd_adapter *adapter, const bt_uuid_t *uuid,
447 uint8_t *value, size_t len)
452 a = attribute_find(adapter, uuid);
455 status = attrib_db_update(adapter, a->handle, NULL, value, len, NULL);
463 bool gatt_add_descriptor(struct btd_adapter *adapter, uint16_t *handle,
464 uint16_t start_handle, gatt_option opt1, ...)
468 uint16_t disc_handle = *handle;
470 va_start(args, opt1);
471 disc = parse_opts(opt1, args);
474 for (l = disc; l != NULL; l = l->next) {
475 struct gatt_info *info = l->data;
477 DBG("New Descriptor: handle 0x%04x, start handle 0x%04x",
478 disc_handle, start_handle);
479 if (!add_descriptor(adapter, &disc_handle, info)) {
484 g_slist_free_full(disc, free_gatt_info);
485 *handle = disc_handle;
490 g_slist_free_full(disc, free_gatt_info);
494 bool gatt_add_characteristic(struct btd_adapter *adapter,
495 uint16_t *handle, uint16_t start_handle,
496 gatt_option opt1, ...)
500 uint16_t char_handle = *handle;
502 va_start(args, opt1);
503 chrs = parse_opts(opt1, args);
506 for (l = chrs; l != NULL; l = l->next) {
507 struct gatt_info *info = l->data;
509 DBG("New characteristic: handle 0x%04x, start handle 0x%04x",
510 char_handle, start_handle);
511 if (!add_characteristic(adapter, &char_handle, info)) {
512 service_attr_del(adapter, start_handle,
518 g_slist_free_full(chrs, free_gatt_info);
519 *handle = char_handle;
524 g_slist_free_full(chrs, free_gatt_info);
528 void attrib_remove_service(struct btd_adapter *adapter, uint16_t start_handle,
531 DBG("gatt_remove_service");
532 service_attr_del(adapter, start_handle, end_handle);
535 uint16_t gatt_prim_service_add(struct btd_adapter *adapter, uint16_t uuid,
536 bt_uuid_t *svc_uuid, unsigned int size,
537 uint16_t *start_handle)
539 char uuidstr[MAX_LEN_UUID_STR];
542 bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
543 if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
544 error("Invalid service uuid: %s", uuidstr);
548 handle = attrib_db_find_avail(adapter, svc_uuid, size);
550 error("Not enough free handles to register service");
554 DBG("New service: handle 0x%04x, UUID %s, %d attributes",
555 handle, uuidstr, size);
557 /* service declaration */
559 *start_handle = handle;
560 if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
570 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
571 bt_uuid_t *svc_uuid, gatt_option opt1, ...)
573 char uuidstr[MAX_LEN_UUID_STR];
574 uint16_t start_handle, h;
579 bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
581 if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
582 error("Invalid service uuid: %s", uuidstr);
586 va_start(args, opt1);
587 chrs = parse_opts(opt1, args);
590 /* calculate how many attributes are necessary for this service */
591 for (l = chrs, size = 1; l != NULL; l = l->next) {
592 struct gatt_info *info = l->data;
593 size += info->num_attrs;
596 start_handle = attrib_db_find_avail(adapter, svc_uuid, size);
597 if (start_handle == 0) {
598 error("Not enough free handles to register service");
602 DBG("New service: handle 0x%04x, UUID %s, %d attributes",
603 start_handle, uuidstr, size);
605 /* service declaration */
607 if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
610 for (l = chrs; l != NULL; l = l->next) {
611 struct gatt_info *info = l->data;
613 DBG("New characteristic: handle 0x%04x", h);
614 if (!add_characteristic(adapter, &h, info)) {
615 service_attr_del(adapter, start_handle, h - 1);
620 g_assert(size < USHRT_MAX);
621 g_assert(h == 0 || (h - start_handle == (uint16_t) size));
622 g_slist_free_full(chrs, free_gatt_info);
627 g_slist_free_full(chrs, free_gatt_info);
632 guint gatt_char_value_notify(GAttrib *attrib, uint16_t handle, uint8_t *value,
633 int vlen, GAttribResultFunc func, gpointer user_data)
636 uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
639 plen = enc_notification(handle, value, vlen, buf, buflen);
643 return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
646 guint gatt_char_value_indicate(GAttrib *attrib, uint16_t handle, uint8_t *value,
647 int vlen, GAttribResultFunc func, gpointer user_data)
650 uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
653 plen = enc_indication(handle, value, vlen, buf, buflen);
657 return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);