3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2010 Nokia Corporation
6 * Copyright (C) 2010 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
37 #include <bluetooth/bluetooth.h>
38 #include <bluetooth/sdp.h>
39 #include <bluetooth/sdp_lib.h>
41 #include <gdbus/gdbus.h>
44 #include "btio/btio.h"
50 #include "attrib/gattrib.h"
51 #include "attrib/att.h"
52 #include "attrib/gatt.h"
53 #include "attrib/att-database.h"
56 #ifdef __TIZEN_PATCH__
57 #include "src/shared/util.h"
60 #include "attrib-server.h"
62 static GSList *servers = NULL;
65 struct btd_adapter *adapter;
68 uint32_t gatt_sdp_handle;
69 uint32_t gap_sdp_handle;
73 uint16_t appearance_handle;
82 struct gatt_server *server;
84 struct btd_device *device;
94 #ifdef __TIZEN_PATCH__
95 static bt_uuid_t prim_uuid32 = {
97 .value.u32 = GATT_PRIM_SVC_UUID
100 static bt_uuid_t snd_uuid32 = {
102 .value.u32 = GATT_SND_SVC_UUID
107 static bt_uuid_t prim_uuid = {
109 .value.u16 = GATT_PRIM_SVC_UUID
111 static bt_uuid_t snd_uuid = {
113 .value.u16 = GATT_SND_SVC_UUID
115 static bt_uuid_t ccc_uuid = {
117 .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
120 static void attrib_free(void *data)
122 struct attribute *a = data;
128 static void channel_free(struct gatt_channel *channel)
130 if (channel->cleanup_id)
131 g_source_remove(channel->cleanup_id);
133 if (channel->device) {
134 device_unset_attrib(channel->device);
135 btd_device_unref(channel->device);
138 g_attrib_unref(channel->attrib);
142 static void gatt_server_free(struct gatt_server *server)
144 g_list_free_full(server->database, attrib_free);
146 if (server->l2cap_io != NULL) {
147 g_io_channel_shutdown(server->l2cap_io, FALSE, NULL);
148 g_io_channel_unref(server->l2cap_io);
151 if (server->le_io != NULL) {
152 g_io_channel_shutdown(server->le_io, FALSE, NULL);
153 g_io_channel_unref(server->le_io);
156 g_slist_free_full(server->clients, (GDestroyNotify) channel_free);
158 if (server->gatt_sdp_handle > 0)
159 adapter_service_remove(server->adapter,
160 server->gatt_sdp_handle);
162 if (server->gap_sdp_handle > 0)
163 adapter_service_remove(server->adapter, server->gap_sdp_handle);
165 if (server->adapter != NULL)
166 btd_adapter_unref(server->adapter);
171 static int adapter_cmp_addr(gconstpointer a, gconstpointer b)
173 const struct gatt_server *server = a;
174 const bdaddr_t *bdaddr = b;
176 return bacmp(btd_adapter_get_address(server->adapter), bdaddr);
179 static int adapter_cmp(gconstpointer a, gconstpointer b)
181 const struct gatt_server *server = a;
182 const struct btd_adapter *adapter = b;
184 if (server->adapter == adapter)
190 static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr)
194 l = g_slist_find_custom(servers, bdaddr, adapter_cmp_addr);
198 ba2str(bdaddr, addr);
199 error("No GATT server found in %s", addr);
206 static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
208 sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
209 uuid_t root_uuid, proto_uuid, l2cap;
210 sdp_record_t *record;
211 sdp_data_t *psm, *sh, *eh;
212 uint16_t lp = ATT_PSM;
220 record = sdp_record_alloc();
224 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
225 root = sdp_list_append(NULL, &root_uuid);
226 sdp_set_browse_groups(record, root);
227 sdp_list_free(root, NULL);
229 svclass_id = sdp_list_append(NULL, uuid);
230 sdp_set_service_classes(record, svclass_id);
231 sdp_list_free(svclass_id, NULL);
233 sdp_uuid16_create(&l2cap, L2CAP_UUID);
234 proto[0] = sdp_list_append(NULL, &l2cap);
235 psm = sdp_data_alloc(SDP_UINT16, &lp);
236 proto[0] = sdp_list_append(proto[0], psm);
237 apseq = sdp_list_append(NULL, proto[0]);
239 sdp_uuid16_create(&proto_uuid, ATT_UUID);
240 proto[1] = sdp_list_append(NULL, &proto_uuid);
241 sh = sdp_data_alloc(SDP_UINT16, &start);
242 proto[1] = sdp_list_append(proto[1], sh);
243 eh = sdp_data_alloc(SDP_UINT16, &end);
244 proto[1] = sdp_list_append(proto[1], eh);
245 apseq = sdp_list_append(apseq, proto[1]);
247 aproto = sdp_list_append(NULL, apseq);
248 sdp_set_access_protos(record, aproto);
253 sdp_list_free(proto[0], NULL);
254 sdp_list_free(proto[1], NULL);
255 sdp_list_free(apseq, NULL);
256 sdp_list_free(aproto, NULL);
261 static int handle_cmp(gconstpointer a, gconstpointer b)
263 const struct attribute *attrib = a;
264 uint16_t handle = GPOINTER_TO_UINT(b);
266 return attrib->handle - handle;
269 static int attribute_cmp(gconstpointer a1, gconstpointer a2)
271 const struct attribute *attrib1 = a1;
272 const struct attribute *attrib2 = a2;
274 return attrib1->handle - attrib2->handle;
278 #ifdef __TIZEN_PATCH__
279 static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
281 if (src->type == BT_UUID16) {
282 put_le16(src->value.u16, dst);
284 else if (src->type == BT_UUID32) {
285 put_le32(src->value.u32, dst);
287 /* Convert from 128-bit BE to LE */
288 bswap_128(&src->value.u128, dst);
292 static int attribute_uuid_cmp(gconstpointer a, gconstpointer b)
294 const struct attribute *attrib1 = a;
295 const bt_uuid_t *uuid = b;
297 return bt_uuid_cmp(&attrib1->uuid, uuid);
300 struct attribute *attribute_find(struct btd_adapter *adapter, bt_uuid_t *uuid)
304 struct gatt_server *server;
306 /* Find the attrib server database for the given adapter */
307 l = g_slist_find_custom(servers, adapter, adapter_cmp);
313 l = g_list_find_custom(server->database, GUINT_TO_POINTER(uuid),
322 static struct attribute *find_svc_range(struct gatt_server *server,
323 uint16_t start, uint16_t *end)
325 struct attribute *attrib;
332 l = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
339 #ifdef __TIZEN_PATCH__
340 if (attrib->uuid.type == BT_UUID16) {
342 if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0 &&
343 bt_uuid_cmp(&attrib->uuid, &snd_uuid) != 0)
346 #ifdef __TIZEN_PATCH__
348 else if (attrib->uuid.type == BT_UUID32) {
349 if (bt_uuid_cmp(&attrib->uuid, &prim_uuid32) != 0 &&
350 bt_uuid_cmp(&attrib->uuid, &snd_uuid32) != 0)
357 for (l = l->next; l; l = l->next) {
358 struct attribute *a = l->data;
360 #ifdef __TIZEN_PATCH__
361 if (attrib->uuid.type == BT_UUID16) {
363 if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
364 bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
367 #ifdef __TIZEN_PATCH__
369 else if (attrib->uuid.type == BT_UUID32) {
370 if (bt_uuid_cmp(&attrib->uuid, &prim_uuid32) != 0 &&
371 bt_uuid_cmp(&attrib->uuid, &snd_uuid32) != 0)
384 static uint32_t attrib_create_sdp_new(struct gatt_server *server,
385 uint16_t handle, const char *name)
387 sdp_record_t *record;
390 uuid_t svc, gap_uuid;
392 a = find_svc_range(server, handle, &end);
398 sdp_uuid16_create(&svc, att_get_u16(a->data));
399 #ifdef __TIZEN_PATCH__
400 else if (a->len == 4) {
401 sdp_uuid32_create(&svc, att_get_u32(a->data));
404 else if (a->len == 16)
405 sdp_uuid128_create(&svc, a->data);
409 record = server_record_new(&svc, handle, end);
414 sdp_set_info_attr(record, name, "BlueZ", NULL);
416 sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
417 if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
418 sdp_set_url_attr(record, "http://www.bluez.org/",
419 "http://www.bluez.org/",
420 "http://www.bluez.org/");
423 if (adapter_service_add(server->adapter, record) == 0)
424 return record->handle;
426 sdp_record_free(record);
430 static struct attribute *attrib_db_add_new(struct gatt_server *server,
431 uint16_t handle, bt_uuid_t *uuid,
432 int read_req, int write_req,
433 const uint8_t *value, size_t len)
438 DBG("handle=0x%04x", handle);
440 if (g_list_find_custom(server->database, GUINT_TO_POINTER(h),
444 a = g_new0(struct attribute, 1);
446 a->data = g_memdup(value, len);
449 a->read_req = read_req;
450 a->write_req = write_req;
452 server->database = g_list_insert_sorted(server->database, a,
458 static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
461 /* FIXME: currently, it is assumed an encrypted link is enough for
462 * authentication. This will allow to enable the SMP negotiation once
463 * it is on upstream kernel. High security level should be mapped
464 * to authentication and medium to encryption permission. */
465 if (!channel->encrypted)
466 channel->encrypted = g_attrib_is_encrypted(channel->attrib);
467 if (reqs == ATT_AUTHENTICATION && !channel->encrypted)
468 return ATT_ECODE_AUTHENTICATION;
469 else if (reqs == ATT_AUTHORIZATION)
470 return ATT_ECODE_AUTHORIZATION;
473 case ATT_OP_READ_BY_GROUP_REQ:
474 case ATT_OP_READ_BY_TYPE_REQ:
475 case ATT_OP_READ_REQ:
476 case ATT_OP_READ_BLOB_REQ:
477 case ATT_OP_READ_MULTI_REQ:
478 if (reqs == ATT_NOT_PERMITTED)
479 return ATT_ECODE_READ_NOT_PERM;
481 case ATT_OP_PREP_WRITE_REQ:
482 case ATT_OP_WRITE_REQ:
483 case ATT_OP_WRITE_CMD:
484 if (reqs == ATT_NOT_PERMITTED)
485 return ATT_ECODE_WRITE_NOT_PERM;
492 static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
493 uint16_t end, bt_uuid_t *uuid,
494 uint8_t *pdu, size_t len)
496 struct att_data_list *adl;
498 struct group_elem *cur, *old = NULL;
500 GList *dl, *database;
501 uint16_t length, last_handle, last_size = 0;
505 if (start > end || start == 0x0000)
506 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start,
507 ATT_ECODE_INVALID_HANDLE, pdu, len);
510 * Only <<Primary Service>> and <<Secondary Service>> grouping
511 * types may be used in the Read By Group Type Request.
514 #ifdef __TIZEN_PATCH__
515 if (uuid->type == BT_UUID16) {
517 if (bt_uuid_cmp(uuid, &prim_uuid) != 0 &&
518 bt_uuid_cmp(uuid, &snd_uuid) != 0)
519 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000,
520 ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);
522 #ifdef __TIZEN_PATCH__
524 else if (uuid->type == BT_UUID32) {
525 if (bt_uuid_cmp(uuid, &prim_uuid32) != 0 &&
526 bt_uuid_cmp(uuid, &snd_uuid32) != 0)
527 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000,
528 ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);
531 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000,
532 ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);
536 database = channel->server->database;
537 for (dl = database, groups = NULL, cur = NULL; dl; dl = dl->next) {
541 if (a->handle < start)
544 if (a->handle >= end)
547 #ifdef __TIZEN_PATCH__
548 if (uuid->type == BT_UUID16) {
550 /* The old group ends when a new one starts */
551 if (old && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
552 bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) {
553 old->end = last_handle;
557 #ifdef __TIZEN_PATCH__
559 if (uuid->type == BT_UUID32) {
560 if (old && (bt_uuid_cmp(&a->uuid, &prim_uuid32) == 0 ||
561 bt_uuid_cmp(&a->uuid, &snd_uuid32) == 0)) {
562 old->end = last_handle;
568 if (bt_uuid_cmp(&a->uuid, uuid) != 0) {
569 /* Still inside a service, update its last handle */
571 last_handle = a->handle;
575 if (last_size && (last_size != a->len))
578 status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ,
581 if (status == 0x00 && a->read_cb)
582 status = a->read_cb(a, channel->device,
586 g_slist_free_full(groups, g_free);
587 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ,
588 a->handle, status, pdu, len);
591 cur = g_new0(struct group_elem, 1);
592 cur->handle = a->handle;
596 /* Attribute Grouping Type found */
597 groups = g_slist_append(groups, cur);
601 last_handle = cur->handle;
605 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start,
606 ATT_ECODE_ATTR_NOT_FOUND, pdu, len);
609 cur->end = a->handle;
611 cur->end = last_handle;
613 length = g_slist_length(groups);
615 adl = att_data_list_alloc(length, last_size + 4);
617 g_slist_free_full(groups, g_free);
618 return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start,
619 ATT_ECODE_UNLIKELY, pdu, len);
622 for (i = 0, l = groups; l; l = l->next, i++) {
627 value = (void *) adl->data[i];
629 att_put_u16(cur->handle, value);
630 att_put_u16(cur->end, &value[2]);
631 /* Attribute Value */
632 memcpy(&value[4], cur->data, cur->len);
635 length = enc_read_by_grp_resp(adl, pdu, len);
637 att_data_list_free(adl);
638 g_slist_free_full(groups, g_free);
643 static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
644 uint16_t end, bt_uuid_t *uuid,
645 uint8_t *pdu, size_t len)
647 struct att_data_list *adl;
649 GList *dl, *database;
651 uint16_t num, length;
655 if (start > end || start == 0x0000)
656 return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
657 ATT_ECODE_INVALID_HANDLE, pdu, len);
659 database = channel->server->database;
660 for (dl = database, length = 0, types = NULL; dl; dl = dl->next) {
664 if (a->handle < start)
670 if (bt_uuid_cmp(&a->uuid, uuid) != 0)
673 status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ,
676 if (status == 0x00 && a->read_cb)
677 status = a->read_cb(a, channel->device,
682 return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ,
683 a->handle, status, pdu, len);
686 /* All elements must have the same length */
689 else if (a->len != length)
692 types = g_slist_append(types, a);
696 return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
697 ATT_ECODE_ATTR_NOT_FOUND, pdu, len);
699 num = g_slist_length(types);
701 /* Handle length plus attribute value length */
704 adl = att_data_list_alloc(num, length);
707 return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
708 ATT_ECODE_UNLIKELY, pdu, len);
711 for (i = 0, l = types; l; i++, l = l->next) {
716 value = (void *) adl->data[i];
718 att_put_u16(a->handle, value);
720 /* Attribute Value */
721 memcpy(&value[2], a->data, a->len);
724 length = enc_read_by_type_resp(adl, pdu, len);
726 att_data_list_free(adl);
732 static uint16_t find_info(struct gatt_channel *channel, uint16_t start,
733 uint16_t end, uint8_t *pdu, size_t len)
736 struct att_data_list *adl;
738 GList *dl, *database;
739 uint8_t format, last_type = BT_UUID_UNSPEC;
740 uint16_t length, num;
743 if (start > end || start == 0x0000)
744 return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
745 ATT_ECODE_INVALID_HANDLE, pdu, len);
747 database = channel->server->database;
748 for (dl = database, info = NULL, num = 0; dl; dl = dl->next) {
751 if (a->handle < start)
757 if (last_type == BT_UUID_UNSPEC)
758 last_type = a->uuid.type;
760 if (a->uuid.type != last_type)
763 info = g_slist_append(info, a);
766 last_type = a->uuid.type;
770 return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
771 ATT_ECODE_ATTR_NOT_FOUND, pdu, len);
773 if (last_type == BT_UUID16) {
776 } else if (last_type == BT_UUID128) {
784 adl = att_data_list_alloc(num, length + 2);
787 return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
788 ATT_ECODE_UNLIKELY, pdu, len);
791 for (i = 0, l = info; l; i++, l = l->next) {
796 value = (void *) adl->data[i];
798 att_put_u16(a->handle, value);
800 /* Attribute Value */
801 att_put_uuid(a->uuid, &value[2]);
804 length = enc_find_info_resp(format, adl, pdu, len);
806 att_data_list_free(adl);
812 static uint16_t find_by_type(struct gatt_channel *channel, uint16_t start,
813 uint16_t end, bt_uuid_t *uuid,
814 const uint8_t *value, size_t vlen,
815 uint8_t *opdu, size_t mtu)
818 struct att_range *range;
820 GList *dl, *database;
823 if (start > end || start == 0x0000)
824 return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
825 ATT_ECODE_INVALID_HANDLE, opdu, mtu);
827 /* Searching first requested handle number */
828 database = channel->server->database;
829 for (dl = database, matches = NULL, range = NULL; dl; dl = dl->next) {
832 if (a->handle < start)
838 /* Primary service? Attribute value matches? */
839 if ((bt_uuid_cmp(&a->uuid, uuid) == 0) && (a->len == vlen) &&
840 (memcmp(a->data, value, vlen) == 0)) {
842 range = g_new0(struct att_range, 1);
843 range->start = a->handle;
844 /* It is allowed to have end group handle the same as
845 * start handle, for groups with only one attribute. */
846 range->end = a->handle;
848 matches = g_slist_append(matches, range);
850 /* Update the last found handle or reset the pointer
851 * to track that a new group started: Primary or
852 * Secondary service. */
853 #ifndef __TIZEN_PATCH__
854 if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
855 bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
858 if (a->uuid.type == BT_UUID32) {
859 if (bt_uuid_cmp(&a->uuid, &prim_uuid32) == 0 ||
860 bt_uuid_cmp(&a->uuid, &snd_uuid32) == 0)
866 range->end = a->handle;
871 return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
872 ATT_ECODE_ATTR_NOT_FOUND, opdu, mtu);
874 len = enc_find_by_type_resp(matches, opdu, mtu);
876 g_slist_free_full(matches, g_free);
881 static int read_device_ccc(struct btd_device *device, uint16_t handle,
891 filename = btd_device_get_storage_path(device, "ccc");
893 warn("Unable to get ccc storage path for device");
897 key_file = g_key_file_new();
898 g_key_file_load_from_file(key_file, filename, 0, NULL);
900 sprintf(group, "%hu", handle);
902 str = g_key_file_get_string(key_file, group, "Value", NULL);
903 if (!str || sscanf(str, "%04X", &config) != 1)
910 g_key_file_free(key_file);
915 static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
916 uint8_t *pdu, size_t len)
924 l = g_list_find_custom(channel->server->database,
925 GUINT_TO_POINTER(h), handle_cmp);
927 return enc_error_resp(ATT_OP_READ_REQ, handle,
928 ATT_ECODE_INVALID_HANDLE, pdu, len);
932 if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
933 read_device_ccc(channel->device, handle, &cccval) == 0) {
936 att_put_u16(cccval, config);
937 return enc_read_resp(config, sizeof(config), pdu, len);
940 status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_req);
942 if (status == 0x00 && a->read_cb)
943 status = a->read_cb(a, channel->device, a->cb_user_data);
946 return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu,
949 return enc_read_resp(a->data, a->len, pdu, len);
952 static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
953 uint16_t offset, uint8_t *pdu, size_t len)
961 l = g_list_find_custom(channel->server->database,
962 GUINT_TO_POINTER(h), handle_cmp);
964 return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
965 ATT_ECODE_INVALID_HANDLE, pdu, len);
969 if (a->len <= offset)
970 return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
971 ATT_ECODE_INVALID_OFFSET, pdu, len);
973 if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
974 read_device_ccc(channel->device, handle, &cccval) == 0) {
977 att_put_u16(cccval, config);
978 return enc_read_blob_resp(config, sizeof(config), offset,
982 status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_req);
984 if (status == 0x00 && a->read_cb)
985 status = a->read_cb(a, channel->device, a->cb_user_data);
988 return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status,
991 return enc_read_blob_resp(a->data, a->len, offset, pdu, len);
994 static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
995 const uint8_t *value, size_t vlen,
996 uint8_t *pdu, size_t len)
1003 l = g_list_find_custom(channel->server->database,
1004 GUINT_TO_POINTER(h), handle_cmp);
1006 return enc_error_resp(ATT_OP_WRITE_REQ, handle,
1007 ATT_ECODE_INVALID_HANDLE, pdu, len);
1011 status = att_check_reqs(channel, ATT_OP_WRITE_REQ, a->write_req);
1013 return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu,
1016 if (bt_uuid_cmp(&ccc_uuid, &a->uuid) != 0) {
1018 attrib_db_update(channel->server->adapter, handle, NULL,
1022 status = a->write_cb(a, channel->device,
1025 return enc_error_resp(ATT_OP_WRITE_REQ, handle,
1029 uint16_t cccval = att_get_u16(value);
1032 char group[6], value[5];
1036 filename = btd_device_get_storage_path(channel->device, "ccc");
1038 warn("Unable to get ccc storage path for device");
1039 return enc_error_resp(ATT_OP_WRITE_REQ, handle,
1040 ATT_ECODE_WRITE_NOT_PERM,
1044 key_file = g_key_file_new();
1045 g_key_file_load_from_file(key_file, filename, 0, NULL);
1047 sprintf(group, "%hu", handle);
1048 sprintf(value, "%hX", cccval);
1049 g_key_file_set_string(key_file, group, "Value", value);
1051 data = g_key_file_to_data(key_file, &length, NULL);
1053 create_file(filename, S_IRUSR | S_IWUSR);
1054 g_file_set_contents(filename, data, length, NULL);
1057 #ifdef __TIZEN_PATCH__
1059 filename = btd_device_get_storage_path(channel->device, "ccc_sc");
1061 warn("Unable to get ccc storage path for device");
1062 return enc_error_resp(ATT_OP_WRITE_REQ, handle,
1063 ATT_ECODE_WRITE_NOT_PERM,
1067 g_key_file_free(key_file);
1068 key_file = g_key_file_new();
1069 g_key_file_load_from_file(key_file, filename, 0, NULL);
1071 memset(&group, 0x00, 6);
1072 memset(&value, 0x00, 5);
1073 sprintf(group, "%hu", handle);
1074 sprintf(value, "%hX", cccval);
1075 g_key_file_set_string(key_file, group, "Value", value);
1078 data = g_key_file_to_data(key_file, &length, NULL);
1080 create_file(filename, S_IRUSR | S_IWUSR);
1081 g_file_set_contents(filename, data, length, NULL);
1087 g_key_file_free(key_file);
1090 return enc_write_resp(pdu);
1093 static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
1094 uint8_t *pdu, size_t len)
1096 GError *gerr = NULL;
1100 if (mtu < ATT_DEFAULT_LE_MTU)
1101 return enc_error_resp(ATT_OP_MTU_REQ, 0,
1102 ATT_ECODE_REQ_NOT_SUPP, pdu, len);
1104 io = g_attrib_get_channel(channel->attrib);
1106 bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
1108 error("bt_io_get: %s", gerr->message);
1110 return enc_error_resp(ATT_OP_MTU_REQ, 0, ATT_ECODE_UNLIKELY,
1114 channel->mtu = MIN(mtu, imtu);
1115 g_attrib_set_mtu(channel->attrib, channel->mtu);
1117 return enc_mtu_resp(imtu, pdu, len);
1120 static void channel_remove(struct gatt_channel *channel)
1122 channel->server->clients = g_slist_remove(channel->server->clients,
1124 #ifdef __TIZEN_PATCH__
1125 if (channel->server->clients == NULL) {
1126 device_set_gatt_connected(channel->device, FALSE);
1129 channel_free(channel);
1132 static gboolean channel_watch_cb(GIOChannel *io, GIOCondition cond,
1135 channel_remove(user_data);
1140 static void channel_handler(const uint8_t *ipdu, uint16_t len,
1143 struct gatt_channel *channel = user_data;
1144 uint8_t opdu[channel->mtu];
1145 uint16_t length, start, end, mtu, offset;
1149 uint8_t *value = g_attrib_get_buffer(channel->attrib, &vlen);
1151 DBG("op 0x%02x", ipdu[0]);
1154 error("Too much data on ATT socket");
1155 status = ATT_ECODE_INVALID_PDU;
1160 case ATT_OP_READ_BY_GROUP_REQ:
1161 length = dec_read_by_grp_req(ipdu, len, &start, &end, &uuid);
1163 status = ATT_ECODE_INVALID_PDU;
1167 length = read_by_group(channel, start, end, &uuid, opdu,
1170 case ATT_OP_READ_BY_TYPE_REQ:
1171 length = dec_read_by_type_req(ipdu, len, &start, &end, &uuid);
1173 status = ATT_ECODE_INVALID_PDU;
1177 length = read_by_type(channel, start, end, &uuid, opdu,
1180 case ATT_OP_READ_REQ:
1181 length = dec_read_req(ipdu, len, &start);
1183 status = ATT_ECODE_INVALID_PDU;
1187 length = read_value(channel, start, opdu, channel->mtu);
1189 case ATT_OP_READ_BLOB_REQ:
1190 length = dec_read_blob_req(ipdu, len, &start, &offset);
1192 status = ATT_ECODE_INVALID_PDU;
1196 length = read_blob(channel, start, offset, opdu, channel->mtu);
1198 case ATT_OP_MTU_REQ:
1200 status = ATT_ECODE_REQ_NOT_SUPP;
1204 length = dec_mtu_req(ipdu, len, &mtu);
1206 status = ATT_ECODE_INVALID_PDU;
1210 length = mtu_exchange(channel, mtu, opdu, channel->mtu);
1212 case ATT_OP_FIND_INFO_REQ:
1213 length = dec_find_info_req(ipdu, len, &start, &end);
1215 status = ATT_ECODE_INVALID_PDU;
1219 length = find_info(channel, start, end, opdu, channel->mtu);
1221 case ATT_OP_WRITE_REQ:
1222 length = dec_write_req(ipdu, len, &start, value, &vlen);
1224 status = ATT_ECODE_INVALID_PDU;
1228 length = write_value(channel, start, value, vlen, opdu,
1231 case ATT_OP_WRITE_CMD:
1232 length = dec_write_cmd(ipdu, len, &start, value, &vlen);
1234 write_value(channel, start, value, vlen, opdu,
1237 case ATT_OP_FIND_BY_TYPE_REQ:
1238 length = dec_find_by_type_req(ipdu, len, &start, &end,
1239 &uuid, value, &vlen);
1241 status = ATT_ECODE_INVALID_PDU;
1245 length = find_by_type(channel, start, end, &uuid, value, vlen,
1246 opdu, channel->mtu);
1248 case ATT_OP_HANDLE_CNF:
1250 case ATT_OP_HANDLE_IND:
1251 case ATT_OP_HANDLE_NOTIFY:
1252 /* The attribute client is already handling these */
1254 case ATT_OP_READ_MULTI_REQ:
1255 case ATT_OP_PREP_WRITE_REQ:
1256 case ATT_OP_EXEC_WRITE_REQ:
1258 DBG("Unsupported request 0x%02x", ipdu[0]);
1259 status = ATT_ECODE_REQ_NOT_SUPP;
1264 status = ATT_ECODE_IO;
1268 length = enc_error_resp(ipdu[0], 0x0000, status, opdu,
1271 g_attrib_send(channel->attrib, 0, opdu, length, NULL, NULL, NULL);
1274 GAttrib *attrib_from_device(struct btd_device *device)
1276 struct btd_adapter *adapter = device_get_adapter(device);
1277 struct gatt_server *server;
1280 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1286 for (l = server->clients; l; l = l->next) {
1287 struct gatt_channel *channel = l->data;
1289 if (channel->device == device)
1290 return g_attrib_ref(channel->attrib);
1296 guint attrib_channel_attach(GAttrib *attrib)
1298 struct gatt_server *server;
1299 struct btd_device *device;
1300 struct gatt_channel *channel;
1303 GError *gerr = NULL;
1304 uint8_t bdaddr_type;
1308 io = g_attrib_get_channel(attrib);
1310 bt_io_get(io, &gerr,
1311 BT_IO_OPT_SOURCE_BDADDR, &src,
1312 BT_IO_OPT_DEST_BDADDR, &dst,
1313 BT_IO_OPT_DEST_TYPE, &bdaddr_type,
1314 BT_IO_OPT_CID, &cid,
1315 BT_IO_OPT_IMTU, &mtu,
1318 error("bt_io_get: %s", gerr->message);
1323 server = find_gatt_server(&src);
1327 channel = g_new0(struct gatt_channel, 1);
1328 channel->server = server;
1330 device = btd_adapter_find_device(server->adapter, &dst);
1331 if (device == NULL) {
1332 error("Device object not found for attrib server");
1337 #ifdef __TIZEN_PATCH__
1338 device_set_gatt_connected(device, TRUE);
1341 if (!device_is_bonded(device, bdaddr_type)) {
1344 filename = btd_device_get_storage_path(device, "ccc");
1351 if (cid != ATT_CID) {
1352 channel->le = FALSE;
1356 channel->mtu = ATT_DEFAULT_LE_MTU;
1359 channel->attrib = g_attrib_ref(attrib);
1360 channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS,
1361 GATTRIB_ALL_HANDLES, channel_handler, channel, NULL);
1363 channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb,
1365 #ifdef __TIZEN_PATCH__
1366 device_set_attrib(device, channel->id, channel->attrib);
1368 channel->device = btd_device_ref(device);
1370 server->clients = g_slist_append(server->clients, channel);
1375 static int channel_id_cmp(gconstpointer data, gconstpointer user_data)
1377 const struct gatt_channel *channel = data;
1378 guint id = GPOINTER_TO_UINT(user_data);
1380 return channel->id - id;
1383 gboolean attrib_channel_detach(GAttrib *attrib, guint id)
1385 struct gatt_server *server;
1386 struct gatt_channel *channel;
1387 GError *gerr = NULL;
1392 io = g_attrib_get_channel(attrib);
1394 bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_INVALID);
1397 error("bt_io_get: %s", gerr->message);
1402 server = find_gatt_server(&src);
1406 l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id),
1413 g_attrib_unregister(channel->attrib, channel->id);
1414 channel_remove(channel);
1419 static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
1426 error("%s", gerr->message);
1430 attrib = g_attrib_new(io);
1434 attrib_channel_attach(attrib);
1435 g_attrib_unref(attrib);
1438 static gboolean register_core_services(struct gatt_server *server)
1442 uint16_t appearance = 0x0000;
1443 struct gatt_info *info;
1445 /* GAP service: primary service definition */
1446 bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
1447 att_put_u16(GENERIC_ACCESS_PROFILE_ID, &atval[0]);
1448 attrib_db_add_new(server, 0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
1451 /* GAP service: device name characteristic */
1452 server->name_handle = 0x0006;
1453 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
1454 atval[0] = ATT_CHAR_PROPER_READ;
1455 att_put_u16(server->name_handle, &atval[1]);
1456 att_put_u16(GATT_CHARAC_DEVICE_NAME, &atval[3]);
1457 attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
1460 /* GAP service: device name attribute */
1461 bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
1462 attrib_db_add_new(server, server->name_handle, &uuid, ATT_NONE,
1463 ATT_NOT_PERMITTED, NULL, 0);
1465 /* GAP service: device appearance characteristic */
1466 server->appearance_handle = 0x0008;
1467 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
1468 atval[0] = ATT_CHAR_PROPER_READ;
1469 att_put_u16(server->appearance_handle, &atval[1]);
1470 att_put_u16(GATT_CHARAC_APPEARANCE, &atval[3]);
1471 attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
1474 /* GAP service: device appearance attribute */
1475 bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
1476 att_put_u16(appearance, &atval[0]);
1477 attrib_db_add_new(server, server->appearance_handle, &uuid, ATT_NONE,
1478 ATT_NOT_PERMITTED, atval, 2);
1479 server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001,
1480 "Generic Access Profile");
1481 if (server->gap_sdp_handle == 0) {
1482 error("Failed to register GAP service record");
1486 /* GATT service: primary service definition */
1487 bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
1488 att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
1489 attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
1492 #ifdef __TIZEN_PATCH__
1493 /* GATT service: service changed characteristic */
1494 server->name_handle = 0x0012;
1495 bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
1497 atval[0] = ATT_CHAR_PROPER_READ;
1498 att_put_u16(server->name_handle, &atval[1]);
1499 att_put_u16(GATT_CHARAC_SERVICE_CHANGED, &atval[3]);
1500 att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, atval);
1501 attrib_db_add_new(server, 0x0011, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
1504 /* GATT service: service changed attribute */
1505 bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
1506 attrib_db_add_new(server, server->name_handle, &uuid, ATT_NONE,
1507 ATT_NOT_PERMITTED, NULL, 0);
1510 server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
1511 "Generic Attribute Profile");
1512 if (server->gatt_sdp_handle == 0) {
1513 error("Failed to register GATT service record");
1520 int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
1522 struct gatt_server *server;
1523 GError *gerr = NULL;
1524 const bdaddr_t *addr;
1526 DBG("Start GATT server in hci%d", btd_adapter_get_index(adapter));
1528 server = g_new0(struct gatt_server, 1);
1529 server->adapter = btd_adapter_ref(adapter);
1531 addr = btd_adapter_get_address(server->adapter);
1534 server->l2cap_io = bt_io_listen(connect_event, NULL, NULL, NULL, &gerr,
1535 BT_IO_OPT_SOURCE_BDADDR, addr,
1536 BT_IO_OPT_PSM, ATT_PSM,
1537 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
1540 if (server->l2cap_io == NULL) {
1541 error("%s", gerr->message);
1543 gatt_server_free(server);
1547 if (!register_core_services(server)) {
1548 gatt_server_free(server);
1553 server->le_io = bt_io_listen(connect_event, NULL,
1554 &server->le_io, NULL, &gerr,
1555 BT_IO_OPT_SOURCE_BDADDR, addr,
1556 BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
1557 BT_IO_OPT_CID, ATT_CID,
1558 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
1561 if (server->le_io == NULL) {
1562 error("%s", gerr->message);
1564 /* Doesn't have LE support, continue */
1567 servers = g_slist_prepend(servers, server);
1571 void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
1573 struct gatt_server *server;
1576 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1580 DBG("Stop GATT server in hci%d", btd_adapter_get_index(adapter));
1583 servers = g_slist_remove(servers, server);
1584 gatt_server_free(server);
1587 uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
1592 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1596 return attrib_create_sdp_new(l->data, handle, name);
1599 void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle)
1601 adapter_service_remove(adapter, sdp_handle);
1604 static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems)
1606 struct gatt_server *server;
1611 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1616 if (server->database == NULL)
1619 for (dl = server->database, handle = 0x0001; dl; dl = dl->next) {
1620 struct attribute *a = dl->data;
1622 if ((bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
1623 bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) &&
1624 a->handle - handle >= nitems)
1625 /* Note: the range above excludes the current handle */
1628 #ifdef __TIZEN_PATCH__
1630 /* 32 bit UUID service definition */
1634 if (a->len == 16 && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
1635 bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) {
1636 /* 128 bit UUID service definition */
1640 if (a->handle == 0xffff)
1643 handle = a->handle + 1;
1646 if (0xffff - handle + 1 >= nitems)
1652 #ifdef __TIZEN_PATCH__
1653 static uint16_t find_uuid32_avail(struct btd_adapter *adapter, uint16_t nitems)
1655 struct gatt_server *server;
1660 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1665 if (server->database == NULL)
1668 for (dl = server->database, handle = 0x0001; dl; dl = dl->next) {
1669 struct attribute *a = dl->data;
1671 if ((bt_uuid_cmp(&a->uuid, &prim_uuid32) == 0 ||
1672 bt_uuid_cmp(&a->uuid, &snd_uuid32) == 0) &&
1673 a->handle - handle >= nitems) {
1674 /* Note: the range above excludes the current handle */
1678 if (a->len == 2 || a->len == 16) {
1679 /* 16 bit UUID or 128 bit UUID service definition */
1683 if (a->handle == 0xffff)
1686 handle = a->handle + 1;
1689 if (0xffff - handle + 1 >= nitems)
1696 static uint16_t find_uuid128_avail(struct btd_adapter *adapter, uint16_t nitems)
1698 uint16_t handle = 0, end = 0xffff;
1699 struct gatt_server *server;
1703 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1708 if (server->database == NULL)
1709 return 0xffff - nitems + 1;
1711 for (dl = g_list_last(server->database); dl; dl = dl->prev) {
1712 struct attribute *a = dl->data;
1717 if (bt_uuid_cmp(&a->uuid, &prim_uuid) != 0 &&
1718 bt_uuid_cmp(&a->uuid, &snd_uuid) != 0)
1721 if (end - handle >= nitems)
1722 return end - nitems + 1;
1725 /* 16 bit UUID service definition */
1729 #ifdef __TIZEN_PATCH__
1731 /* 32 bit UUID service definition */
1736 if (a->handle == 0x0001)
1739 end = a->handle - 1;
1743 if (end - 0x0001 >= nitems)
1744 return end - nitems + 1;
1749 uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
1752 g_assert(nitems > 0);
1754 if (svc_uuid->type == BT_UUID16)
1755 return find_uuid16_avail(adapter, nitems);
1756 #ifdef __TIZEN_PATCH__
1757 else if (svc_uuid->type == BT_UUID32)
1758 return find_uuid32_avail(adapter, nitems);
1760 else if (svc_uuid->type == BT_UUID128)
1761 return find_uuid128_avail(adapter, nitems);
1763 char uuidstr[MAX_LEN_UUID_STR];
1765 bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
1766 error("Service uuid: %s is neither a 16-bit nor a 128-bit uuid",
1772 struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle,
1773 bt_uuid_t *uuid, int read_req,
1774 int write_req, const uint8_t *value,
1779 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1783 return attrib_db_add_new(l->data, handle, uuid, read_req, write_req,
1787 int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
1788 bt_uuid_t *uuid, const uint8_t *value,
1789 size_t len, struct attribute **attr)
1791 struct gatt_server *server;
1792 struct attribute *a;
1797 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1803 DBG("handle=0x%04x", handle);
1805 dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
1812 a->data = g_try_realloc(a->data, len);
1813 if (len && a->data == NULL)
1817 memcpy(a->data, value, len);
1828 int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
1830 struct gatt_server *server;
1831 struct attribute *a;
1836 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1842 DBG("handle=0x%04x", handle);
1844 dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
1850 server->database = g_list_remove(server->database, a);
1857 #ifdef __TIZEN_PATCH__
1858 static uint8_t attrib_get_ccc_info(struct btd_device *device, uint16_t handle)
1860 uint16_t cccval = 0;
1866 filename = btd_device_get_storage_path(device, "ccc");
1868 warn("Unable to get ccc storage path for device");
1872 key_file = g_key_file_new();
1873 g_key_file_load_from_file(key_file, filename, 0, NULL);
1874 sprintf(group, "%hu", handle);
1876 /* Get the CCC value */
1877 value = g_key_file_get_string(key_file, group, "Value", NULL);
1881 sscanf(value, "%hX", &cccval);
1884 g_key_file_free(key_file);
1889 static uint8_t attrib_get_sc_ccc_info(struct btd_device *device, uint16_t handle)
1891 uint16_t cccval = 0;
1897 filename = btd_device_get_storage_path(device, "ccc_sc");
1899 warn("Unable to get ccc_sc storage path for device");
1903 key_file = g_key_file_new();
1904 g_key_file_load_from_file(key_file, filename, 0, NULL);
1905 sprintf(group, "%hu", handle);
1907 /* Get the CCC value */
1908 value = g_key_file_get_string(key_file, group, "Value", NULL);
1912 sscanf(value, "%hX", &cccval);
1915 g_key_file_free(key_file);
1920 void attrib_send_sc_ind(struct btd_device *device, GAttrib *attrib,
1921 uint16_t start_handle, uint16_t end_handle,
1928 pdu = g_attrib_get_buffer(attrib, &mtu);
1929 length = send_sc_indication(start_handle, end_handle, vlen, pdu, mtu);
1930 g_attrib_send(attrib, 0, pdu, length, NULL, NULL, NULL);
1933 void attrib_send_noty_ind(struct btd_device *device, GAttrib *attrib,
1934 uint16_t handle, uint16_t desc_handle,
1935 uint8_t *value, size_t vlen)
1942 cccval = attrib_get_ccc_info(device, desc_handle);
1946 pdu = g_attrib_get_buffer(attrib, &mtu);
1947 if (cccval == GATT_CLIENT_CHARAC_CFG_NOTIF_BIT) {
1948 length = enc_notification(handle, value, vlen, pdu, mtu);
1949 g_attrib_send(attrib, 0, pdu, length, NULL, NULL, NULL);
1950 } else if (cccval == GATT_CLIENT_CHARAC_CFG_IND_BIT) {
1951 length = enc_indication(handle, value, vlen, pdu, mtu);
1952 g_attrib_send(attrib, 0, pdu, length, NULL, NULL, NULL);
1957 int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
1958 const uint8_t *value, size_t len)
1960 struct gatt_server *server;
1964 l = g_slist_find_custom(servers, adapter, adapter_cmp);
1970 /* FIXME: Missing Privacy and Reconnection Address */
1973 case GATT_CHARAC_DEVICE_NAME:
1974 handle = server->name_handle;
1976 case GATT_CHARAC_APPEARANCE:
1977 handle = server->appearance_handle;
1983 return attrib_db_update(adapter, handle, NULL, value, len, NULL);