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
30 #include <bluetooth/uuid.h>
31 #include <bluetooth/sdp.h>
37 #include "att-database.h"
38 #include "attrib-server.h"
39 #include "gatt-service.h"
48 unsigned int num_attrs;
49 uint16_t *value_handle;
59 static GSList *parse_opts(gatt_option opt1, va_list args)
61 gatt_option opt = opt1;
62 struct gatt_info *info;
66 info = g_new0(struct gatt_info, 1);
67 l = g_slist_append(l, info);
69 while (opt != GATT_OPT_INVALID) {
71 case GATT_OPT_CHR_UUID:
72 bt_uuid16_create(&info->uuid, va_arg(args, int));
73 /* characteristic declaration and value */
76 case GATT_OPT_CHR_PROPS:
77 info->props = va_arg(args, int);
79 if (info->props & (ATT_CHAR_PROPER_NOTIFY |
80 ATT_CHAR_PROPER_INDICATE))
81 /* client characteristic configuration */
84 /* TODO: "Extended Properties" property requires a
85 * descriptor, but it is not supported yet. */
87 case GATT_OPT_CHR_VALUE_CB:
88 cb = g_new0(struct attrib_cb, 1);
89 cb->event = va_arg(args, attrib_event_t);
90 cb->fn = va_arg(args, void *);
91 cb->user_data = va_arg(args, void *);
92 info->callbacks = g_slist_append(info->callbacks, cb);
94 case GATT_OPT_CHR_VALUE_GET_HANDLE:
95 info->value_handle = va_arg(args, void *);
97 case GATT_OPT_CCC_GET_HANDLE:
98 info->ccc_handle = va_arg(args, void *);
100 case GATT_OPT_CHR_AUTHENTICATION:
101 info->authentication = va_arg(args, gatt_option);
103 case GATT_OPT_CHR_AUTHORIZATION:
104 info->authorization = va_arg(args, gatt_option);
107 error("Invalid option: %d", opt);
110 opt = va_arg(args, gatt_option);
111 if (opt == GATT_OPT_CHR_UUID) {
112 info = g_new0(struct gatt_info, 1);
113 l = g_slist_append(l, info);
120 static struct attribute *add_service_declaration(struct btd_adapter *adapter,
121 uint16_t handle, uint16_t svc, bt_uuid_t *uuid)
127 if (uuid->type == BT_UUID16) {
128 att_put_u16(uuid->value.u16, &atval[0]);
130 } else if (uuid->type == BT_UUID128) {
131 att_put_u128(uuid->value.u128, &atval[0]);
136 bt_uuid16_create(&bt_uuid, svc);
138 return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE,
139 ATT_NOT_PERMITTED, atval, len);
142 static int att_read_reqs(int authorization, int authentication, uint8_t props)
144 if (authorization == GATT_CHR_VALUE_READ ||
145 authorization == GATT_CHR_VALUE_BOTH)
146 return ATT_AUTHORIZATION;
147 else if (authentication == GATT_CHR_VALUE_READ ||
148 authentication == GATT_CHR_VALUE_BOTH)
149 return ATT_AUTHENTICATION;
150 else if (!(props & ATT_CHAR_PROPER_READ))
151 return ATT_NOT_PERMITTED;
156 static int att_write_reqs(int authorization, int authentication, uint8_t props)
158 if (authorization == GATT_CHR_VALUE_WRITE ||
159 authorization == GATT_CHR_VALUE_BOTH)
160 return ATT_AUTHORIZATION;
161 else if (authentication == GATT_CHR_VALUE_WRITE ||
162 authentication == GATT_CHR_VALUE_BOTH)
163 return ATT_AUTHENTICATION;
164 else if (!(props & (ATT_CHAR_PROPER_WRITE |
165 ATT_CHAR_PROPER_WRITE_WITHOUT_RESP)))
166 return ATT_NOT_PERMITTED;
171 static gint find_callback(gconstpointer a, gconstpointer b)
173 const struct attrib_cb *cb = a;
174 unsigned int event = GPOINTER_TO_UINT(b);
176 return cb->event - event;
179 static gboolean add_characteristic(struct btd_adapter *adapter,
180 uint16_t *handle, struct gatt_info *info)
182 int read_reqs, write_reqs;
183 uint16_t h = *handle;
189 if (!info->uuid.value.u16 || !info->props) {
190 error("Characteristic UUID or properties are missing");
194 read_reqs = att_read_reqs(info->authorization, info->authentication,
196 write_reqs = att_write_reqs(info->authorization, info->authentication,
199 /* TODO: static characteristic values are not supported, therefore a
200 * callback must be always provided if a read/write property is set */
201 if (read_reqs != ATT_NOT_PERMITTED) {
202 gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ);
204 if (!g_slist_find_custom(info->callbacks, reqs,
206 error("Callback for read required");
211 if (write_reqs != ATT_NOT_PERMITTED) {
212 gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
214 if (!g_slist_find_custom(info->callbacks, reqs,
216 error("Callback for write required");
221 /* characteristic declaration */
222 bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID);
223 atval[0] = info->props;
224 att_put_u16(h + 1, &atval[1]);
225 att_put_u16(info->uuid.value.u16, &atval[3]);
226 if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
227 atval, sizeof(atval)) == NULL)
230 /* characteristic value */
231 a = attrib_db_add(adapter, h++, &info->uuid, read_reqs, write_reqs,
236 for (l = info->callbacks; l != NULL; l = l->next) {
237 struct attrib_cb *cb = l->data;
244 a->write_cb = cb->fn;
248 a->cb_user_data = cb->user_data;
251 if (info->value_handle != NULL)
252 *info->value_handle = a->handle;
254 /* client characteristic configuration descriptor */
255 if (info->props & (ATT_CHAR_PROPER_NOTIFY | ATT_CHAR_PROPER_INDICATE)) {
258 bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID);
261 a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE,
262 ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val));
266 if (info->ccc_handle != NULL)
267 *info->ccc_handle = a->handle;
275 static void free_gatt_info(void *data)
277 struct gatt_info *info = data;
279 g_slist_free_full(info->callbacks, g_free);
283 static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
288 for (handle = start_handle; handle <= end_handle; handle++)
289 if (attrib_db_del(adapter, handle) < 0)
290 error("Can't delete handle 0x%04x", handle);
293 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
294 bt_uuid_t *svc_uuid, gatt_option opt1, ...)
296 char uuidstr[MAX_LEN_UUID_STR];
297 uint16_t start_handle, h;
302 bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
304 if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
305 error("Invalid service uuid: %s", uuidstr);
309 va_start(args, opt1);
310 chrs = parse_opts(opt1, args);
313 /* calculate how many attributes are necessary for this service */
314 for (l = chrs, size = 1; l != NULL; l = l->next) {
315 struct gatt_info *info = l->data;
316 size += info->num_attrs;
319 start_handle = attrib_db_find_avail(adapter, svc_uuid, size);
320 if (start_handle == 0) {
321 error("Not enough free handles to register service");
325 DBG("New service: handle 0x%04x, UUID %s, %d attributes",
326 start_handle, uuidstr, size);
328 /* service declaration */
330 if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
333 for (l = chrs; l != NULL; l = l->next) {
334 struct gatt_info *info = l->data;
336 DBG("New characteristic: handle 0x%04x", h);
337 if (!add_characteristic(adapter, &h, info)) {
338 service_attr_del(adapter, start_handle, h - 1);
343 g_assert(size < USHRT_MAX);
344 g_assert(h - start_handle == (uint16_t) size);
345 g_slist_free_full(chrs, free_gatt_info);
350 g_slist_free_full(chrs, free_gatt_info);