OSDN Git Service

android: include hciattach
[android-x86/external-bluetooth-bluez.git] / attrib / gatt-service.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011  Nokia Corporation
6  *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
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.
13  *
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.
18  *
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
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <glib.h>
30
31 #include "lib/bluetooth.h"
32 #include "lib/sdp.h"
33 #include "lib/uuid.h"
34
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"
43 #include "src/log.h"
44
45 struct gatt_info {
46         bt_uuid_t uuid;
47         uint8_t props;
48         int authentication;
49         int authorization;
50         GSList *callbacks;
51         unsigned int num_attrs;
52         uint16_t *value_handle;
53         uint16_t *ccc_handle;
54 };
55
56 struct attrib_cb {
57         attrib_event_t event;
58         void *fn;
59         void *user_data;
60 };
61
62 static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
63 {
64         if (src->type == BT_UUID16)
65                 put_le16(src->value.u16, dst);
66         else
67                 /* Convert from 128-bit BE to LE */
68                 bswap_128(&src->value.u128, dst);
69 }
70
71 static GSList *parse_opts(gatt_option opt1, va_list args)
72 {
73         gatt_option opt = opt1;
74         struct gatt_info *info;
75         struct attrib_cb *cb;
76         GSList *l = NULL;
77
78         info = g_new0(struct gatt_info, 1);
79         l = g_slist_append(l, info);
80
81         while (opt != GATT_OPT_INVALID) {
82                 switch (opt) {
83                 case GATT_OPT_CHR_UUID16:
84                         bt_uuid16_create(&info->uuid, va_arg(args, int));
85                         /* characteristic declaration and value */
86                         info->num_attrs += 2;
87                         break;
88                 case GATT_OPT_CHR_UUID:
89                         memcpy(&info->uuid, va_arg(args, bt_uuid_t *),
90                                                         sizeof(bt_uuid_t));
91                         /* characteristic declaration and value */
92                         info->num_attrs += 2;
93                         break;
94                 case GATT_OPT_CHR_PROPS:
95                         info->props = va_arg(args, int);
96
97                         if (info->props & (GATT_CHR_PROP_NOTIFY |
98                                                 GATT_CHR_PROP_INDICATE))
99                                 /* client characteristic configuration */
100                                 info->num_attrs += 1;
101
102                         /* TODO: "Extended Properties" property requires a
103                          * descriptor, but it is not supported yet. */
104                         break;
105                 case GATT_OPT_CHR_VALUE_CB:
106                         cb = g_new0(struct attrib_cb, 1);
107                         cb->event = va_arg(args, attrib_event_t);
108                         cb->fn = va_arg(args, void *);
109                         cb->user_data = va_arg(args, void *);
110                         info->callbacks = g_slist_append(info->callbacks, cb);
111                         break;
112                 case GATT_OPT_CHR_VALUE_GET_HANDLE:
113                         info->value_handle = va_arg(args, void *);
114                         break;
115                 case GATT_OPT_CCC_GET_HANDLE:
116                         info->ccc_handle = va_arg(args, void *);
117                         break;
118                 case GATT_OPT_CHR_AUTHENTICATION:
119                         info->authentication = va_arg(args, gatt_option);
120                         break;
121                 case GATT_OPT_CHR_AUTHORIZATION:
122                         info->authorization = va_arg(args, gatt_option);
123                         break;
124                 case GATT_CHR_VALUE_READ:
125                 case GATT_CHR_VALUE_WRITE:
126                 case GATT_CHR_VALUE_BOTH:
127                 case GATT_OPT_INVALID:
128                 default:
129                         error("Invalid option: %d", opt);
130                 }
131
132                 opt = va_arg(args, gatt_option);
133                 if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID) {
134                         info = g_new0(struct gatt_info, 1);
135                         l = g_slist_append(l, info);
136                 }
137         }
138
139         return l;
140 }
141
142 static struct attribute *add_service_declaration(struct btd_adapter *adapter,
143                                 uint16_t handle, uint16_t svc, bt_uuid_t *uuid)
144 {
145         bt_uuid_t bt_uuid;
146         uint8_t atval[16];
147         int len;
148
149         put_uuid_le(uuid, &atval[0]);
150         len = bt_uuid_len(uuid);
151
152         bt_uuid16_create(&bt_uuid, svc);
153
154         return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE,
155                                                 ATT_NOT_PERMITTED, atval, len);
156 }
157
158 static int att_read_req(int authorization, int authentication, uint8_t props)
159 {
160         if (authorization == GATT_CHR_VALUE_READ ||
161                                 authorization == GATT_CHR_VALUE_BOTH)
162                 return ATT_AUTHORIZATION;
163         else if (authentication == GATT_CHR_VALUE_READ ||
164                                 authentication == GATT_CHR_VALUE_BOTH)
165                 return ATT_AUTHENTICATION;
166         else if (!(props & GATT_CHR_PROP_READ))
167                 return ATT_NOT_PERMITTED;
168
169         return ATT_NONE;
170 }
171
172 static int att_write_req(int authorization, int authentication, uint8_t props)
173 {
174         if (authorization == GATT_CHR_VALUE_WRITE ||
175                                 authorization == GATT_CHR_VALUE_BOTH)
176                 return ATT_AUTHORIZATION;
177         else if (authentication == GATT_CHR_VALUE_WRITE ||
178                                 authentication == GATT_CHR_VALUE_BOTH)
179                 return ATT_AUTHENTICATION;
180         else if (!(props & (GATT_CHR_PROP_WRITE |
181                                         GATT_CHR_PROP_WRITE_WITHOUT_RESP)))
182                 return ATT_NOT_PERMITTED;
183
184         return ATT_NONE;
185 }
186
187 static int find_callback(gconstpointer a, gconstpointer b)
188 {
189         const struct attrib_cb *cb = a;
190         unsigned int event = GPOINTER_TO_UINT(b);
191
192         return cb->event - event;
193 }
194
195 static gboolean add_characteristic(struct btd_adapter *adapter,
196                                 uint16_t *handle, struct gatt_info *info)
197 {
198         int read_req, write_req;
199         uint16_t h = *handle;
200         struct attribute *a;
201         bt_uuid_t bt_uuid;
202         uint8_t atval[ATT_MAX_VALUE_LEN];
203         GSList *l;
204
205         if ((info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) ||
206                                                                 !info->props) {
207                 error("Characteristic UUID or properties are missing");
208                 return FALSE;
209         }
210
211         read_req = att_read_req(info->authorization, info->authentication,
212                                                                 info->props);
213         write_req = att_write_req(info->authorization, info->authentication,
214                                                                 info->props);
215
216         /* TODO: static characteristic values are not supported, therefore a
217          * callback must be always provided if a read/write property is set */
218         if (read_req != ATT_NOT_PERMITTED) {
219                 gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ);
220
221                 if (!g_slist_find_custom(info->callbacks, reqs,
222                                                         find_callback)) {
223                         error("Callback for read required");
224                         return FALSE;
225                 }
226         }
227
228         if (write_req != ATT_NOT_PERMITTED) {
229                 gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
230
231                 if (!g_slist_find_custom(info->callbacks, reqs,
232                                                         find_callback)) {
233                         error("Callback for write required");
234                         return FALSE;
235                 }
236         }
237
238         /* characteristic declaration */
239         bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID);
240         atval[0] = info->props;
241         put_le16(h + 1, &atval[1]);
242         put_uuid_le(&info->uuid, &atval[3]);
243         if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
244                                 atval, 3 + info->uuid.type / 8) == NULL)
245                 return FALSE;
246
247         /* characteristic value */
248         a = attrib_db_add(adapter, h++, &info->uuid, read_req, write_req,
249                                                                 NULL, 0);
250         if (a == NULL)
251                 return FALSE;
252
253         for (l = info->callbacks; l != NULL; l = l->next) {
254                 struct attrib_cb *cb = l->data;
255
256                 switch (cb->event) {
257                 case ATTRIB_READ:
258                         a->read_cb = cb->fn;
259                         break;
260                 case ATTRIB_WRITE:
261                         a->write_cb = cb->fn;
262                         break;
263                 }
264
265                 a->cb_user_data = cb->user_data;
266         }
267
268         if (info->value_handle != NULL)
269                 *info->value_handle = a->handle;
270
271         /* client characteristic configuration descriptor */
272         if (info->props & (GATT_CHR_PROP_NOTIFY | GATT_CHR_PROP_INDICATE)) {
273                 uint8_t cfg_val[2];
274
275                 bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID);
276                 cfg_val[0] = 0x00;
277                 cfg_val[1] = 0x00;
278                 a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE,
279                                 ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val));
280                 if (a == NULL)
281                         return FALSE;
282
283                 if (info->ccc_handle != NULL)
284                         *info->ccc_handle = a->handle;
285         }
286
287         *handle = h;
288
289         return TRUE;
290 }
291
292 static void free_gatt_info(void *data)
293 {
294         struct gatt_info *info = data;
295
296         g_slist_free_full(info->callbacks, g_free);
297         g_free(info);
298 }
299
300 static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
301                                                         uint16_t end_handle)
302 {
303         uint16_t handle;
304
305         /* For a 128-bit category primary service below handle should be checked
306          * for both non-zero as well as >= 0xffff. As on last iteration the
307          * handle will turn to 0 from 0xffff and loop will be infinite.
308          */
309         for (handle = start_handle; (handle != 0 && handle <= end_handle);
310                                                                 handle++) {
311                 if (attrib_db_del(adapter, handle) < 0)
312                         error("Can't delete handle 0x%04x", handle);
313         }
314 }
315
316 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
317                                 bt_uuid_t *svc_uuid, gatt_option opt1, ...)
318 {
319         char uuidstr[MAX_LEN_UUID_STR];
320         uint16_t start_handle, h;
321         unsigned int size;
322         va_list args;
323         GSList *chrs, *l;
324
325         bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
326
327         if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
328                 error("Invalid service uuid: %s", uuidstr);
329                 return FALSE;
330         }
331
332         va_start(args, opt1);
333         chrs = parse_opts(opt1, args);
334         va_end(args);
335
336         /* calculate how many attributes are necessary for this service */
337         for (l = chrs, size = 1; l != NULL; l = l->next) {
338                 struct gatt_info *info = l->data;
339                 size += info->num_attrs;
340         }
341
342         start_handle = attrib_db_find_avail(adapter, svc_uuid, size);
343         if (start_handle == 0) {
344                 error("Not enough free handles to register service");
345                 goto fail;
346         }
347
348         DBG("New service: handle 0x%04x, UUID %s, %d attributes",
349                                                 start_handle, uuidstr, size);
350
351         /* service declaration */
352         h = start_handle;
353         if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
354                 goto fail;
355
356         for (l = chrs; l != NULL; l = l->next) {
357                 struct gatt_info *info = l->data;
358
359                 DBG("New characteristic: handle 0x%04x", h);
360                 if (!add_characteristic(adapter, &h, info)) {
361                         service_attr_del(adapter, start_handle, h - 1);
362                         goto fail;
363                 }
364         }
365
366         g_assert(size < USHRT_MAX);
367         g_assert(h == 0 || (h - start_handle == (uint16_t) size));
368         g_slist_free_full(chrs, free_gatt_info);
369
370         return TRUE;
371
372 fail:
373         g_slist_free_full(chrs, free_gatt_info);
374         return FALSE;
375 }