tizen 2.3.1 release
[framework/connectivity/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 #ifdef __TIZEN_PATCH__
45 #include "src/device.h"
46 #endif
47
48 struct gatt_info {
49         bt_uuid_t uuid;
50         uint8_t props;
51         int authentication;
52         int authorization;
53         GSList *callbacks;
54         unsigned int num_attrs;
55         uint16_t *value_handle;
56         uint16_t *ccc_handle;
57 };
58
59 struct attrib_cb {
60         attrib_event_t event;
61         void *fn;
62         void *user_data;
63 };
64
65 static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
66 {
67         if (src->type == BT_UUID16)
68                 put_le16(src->value.u16, dst);
69         else
70                 /* Convert from 128-bit BE to LE */
71                 bswap_128(&src->value.u128, dst);
72 }
73
74 static GSList *parse_opts(gatt_option opt1, va_list args)
75 {
76         gatt_option opt = opt1;
77         struct gatt_info *info;
78         struct attrib_cb *cb;
79         GSList *l = NULL;
80
81         info = g_new0(struct gatt_info, 1);
82         l = g_slist_append(l, info);
83
84         while (opt != GATT_OPT_INVALID) {
85                 switch (opt) {
86                 case GATT_OPT_CHR_UUID16:
87 #ifdef __TIZEN_PATCH__
88                 case GATT_OPT_DESC_UUID16:
89 #endif
90                         bt_uuid16_create(&info->uuid, va_arg(args, int));
91                         /* characteristic declaration and value */
92                         info->num_attrs += 2;
93                         break;
94                 case GATT_OPT_CHR_UUID:
95 #ifdef __TIZEN_PATCH__
96                 case GATT_OPT_DESC_UUID:
97 #endif
98                         memcpy(&info->uuid, va_arg(args, bt_uuid_t *),
99                                                         sizeof(bt_uuid_t));
100                         /* characteristic declaration and value */
101                         info->num_attrs += 2;
102                         break;
103                 case GATT_OPT_CHR_PROPS:
104 #ifdef __TIZEN_PATCH__
105                 case GATT_OPT_DESC_PROPS:
106 #endif
107                         info->props = va_arg(args, int);
108
109                         if (info->props & (GATT_CHR_PROP_NOTIFY |
110                                                 GATT_CHR_PROP_INDICATE))
111                                 /* client characteristic configuration */
112                                 info->num_attrs += 1;
113
114                         /* TODO: "Extended Properties" property requires a
115                          * descriptor, but it is not supported yet. */
116                         break;
117                 case GATT_OPT_CHR_VALUE_CB:
118 #ifdef __TIZEN_PATCH__
119                 case GATT_OPT_DESC_VALUE_CB:
120 #endif
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);
126                         break;
127                 case GATT_OPT_CHR_VALUE_GET_HANDLE:
128                         info->value_handle = va_arg(args, void *);
129                         break;
130                 case GATT_OPT_CCC_GET_HANDLE:
131                         info->ccc_handle = va_arg(args, void *);
132                         break;
133                 case GATT_OPT_CHR_AUTHENTICATION:
134                         info->authentication = va_arg(args, gatt_option);
135                         break;
136                 case GATT_OPT_CHR_AUTHORIZATION:
137                         info->authorization = va_arg(args, gatt_option);
138                         break;
139                 case GATT_CHR_VALUE_READ:
140                 case GATT_CHR_VALUE_WRITE:
141                 case GATT_CHR_VALUE_BOTH:
142                 case GATT_OPT_INVALID:
143                 default:
144                         error("Invalid option: %d", opt);
145                 }
146
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) {
151 #else
152                 if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID) {
153 #endif
154                         info = g_new0(struct gatt_info, 1);
155                         l = g_slist_append(l, info);
156                 }
157         }
158
159         return l;
160 }
161
162 static struct attribute *add_service_declaration(struct btd_adapter *adapter,
163                                 uint16_t handle, uint16_t svc, bt_uuid_t *uuid)
164 {
165         bt_uuid_t bt_uuid;
166         uint8_t atval[16];
167         int len;
168
169         put_uuid_le(uuid, &atval[0]);
170         len = bt_uuid_len(uuid);
171
172         bt_uuid16_create(&bt_uuid, svc);
173
174         return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE,
175                                                 ATT_NOT_PERMITTED, atval, len);
176 }
177
178 static int att_read_req(int authorization, int authentication, uint8_t props)
179 {
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;
188
189         return ATT_NONE;
190 }
191
192 static int att_write_req(int authorization, int authentication, uint8_t props)
193 {
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;
203
204         return ATT_NONE;
205 }
206
207 static int find_callback(gconstpointer a, gconstpointer b)
208 {
209         const struct attrib_cb *cb = a;
210         unsigned int event = GPOINTER_TO_UINT(b);
211
212         return cb->event - event;
213 }
214
215 #ifdef __TIZEN_PATCH__
216 static gboolean add_descriptor(struct btd_adapter *adapter,
217                                 uint16_t *handle, struct gatt_info *info)
218 {
219         uint16_t h = *handle;
220         struct attribute *a;
221         bt_uuid_t bt_uuid;
222         uint8_t atval[ATT_MAX_VALUE_LEN];
223         GSList *l;
224
225         if (info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) {
226                 error("Discriptors UUID or properties are missing");
227                 return FALSE;
228         }
229
230         /* Description declaration */
231         if (info->uuid.type == BT_UUID16)
232                 bt_uuid16_create(&bt_uuid, info->uuid.value.u16);
233         else
234                 bt_uuid128_create(&bt_uuid, info->uuid.value.u128);
235
236         put_uuid_le(&info->uuid, &atval[0]);
237 /*      API not available in bluez 5.25
238  * att_put_uuid(info->uuid, &atval[0]);*/
239
240         a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
241                                                 atval, info->uuid.type / 8);
242
243         if (a == NULL) {
244                 return FALSE;
245         }
246
247         for (l = info->callbacks; l != NULL; l = l->next) {
248                 struct attrib_cb *cb = l->data;
249
250                 switch (cb->event) {
251                 case ATTRIB_READ:
252                         a->read_cb = cb->fn;
253                         break;
254                 case ATTRIB_WRITE:
255                         a->write_cb = cb->fn;
256                         break;
257                 }
258
259                 a->cb_user_data = cb->user_data;
260         }
261
262         if (info->value_handle != NULL)
263                 *info->value_handle = a->handle;
264
265         *handle = h;
266
267         return TRUE;
268 }
269 #endif
270
271 static gboolean add_characteristic(struct btd_adapter *adapter,
272                                 uint16_t *handle, struct gatt_info *info)
273 {
274         int read_req, write_req;
275         uint16_t h = *handle;
276         struct attribute *a;
277         bt_uuid_t bt_uuid;
278         uint8_t atval[ATT_MAX_VALUE_LEN];
279         GSList *l;
280
281         if ((info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) ||
282                                                                 !info->props) {
283                 error("Characteristic UUID or properties are missing");
284                 return FALSE;
285         }
286
287         read_req = att_read_req(info->authorization, info->authentication,
288                                                                 info->props);
289         write_req = att_write_req(info->authorization, info->authentication,
290                                                                 info->props);
291
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);
296
297                 if (!g_slist_find_custom(info->callbacks, reqs,
298                                                         find_callback)) {
299                         error("Callback for read required");
300                         return FALSE;
301                 }
302         }
303
304         if (write_req != ATT_NOT_PERMITTED) {
305                 gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
306
307                 if (!g_slist_find_custom(info->callbacks, reqs,
308                                                         find_callback)) {
309                         error("Callback for write required");
310                         return FALSE;
311                 }
312         }
313
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)
321                 return FALSE;
322
323         /* characteristic value */
324         a = attrib_db_add(adapter, h++, &info->uuid, read_req, write_req,
325                                                                 NULL, 0);
326         if (a == NULL)
327                 return FALSE;
328
329         for (l = info->callbacks; l != NULL; l = l->next) {
330                 struct attrib_cb *cb = l->data;
331
332                 switch (cb->event) {
333                 case ATTRIB_READ:
334                         a->read_cb = cb->fn;
335                         break;
336                 case ATTRIB_WRITE:
337                         a->write_cb = cb->fn;
338                         break;
339                 }
340
341                 a->cb_user_data = cb->user_data;
342         }
343
344         if (info->value_handle != NULL)
345                 *info->value_handle = a->handle;
346
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)) {
353                 uint8_t cfg_val[2];
354
355                 bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID);
356                 cfg_val[0] = 0x00;
357                 cfg_val[1] = 0x00;
358                 a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE,
359                                 ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val));
360                 if (a == NULL)
361                         return FALSE;
362
363                 if (info->ccc_handle != NULL)
364                         *info->ccc_handle = a->handle;
365         }
366 #endif
367
368         *handle = h;
369
370         return TRUE;
371 }
372
373 static void free_gatt_info(void *data)
374 {
375         struct gatt_info *info = data;
376
377         g_slist_free_full(info->callbacks, g_free);
378         g_free(info);
379 }
380
381 static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
382                                                         uint16_t end_handle)
383 {
384         uint16_t handle;
385
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.
389          */
390         for (handle = start_handle; (handle != 0 && handle <= end_handle);
391                                                                 handle++) {
392                 if (attrib_db_del(adapter, handle) < 0)
393                         error("Can't delete handle 0x%04x", handle);
394         }
395 }
396
397 #ifdef __TIZEN_PATCH__
398 static int is_gatt_connected(gconstpointer a1, gconstpointer a2)
399 {
400         const struct btd_device *dev = a1;
401
402         if (device_get_gatt_connected(dev))
403                 return 0;
404         else
405                 return -1;
406 }
407
408 bool gatt_send_noty_ind(struct btd_adapter *adapter, const bt_uuid_t *uuid,
409                                         uint8_t *value, size_t len)
410 {
411         struct attribute *a;
412         GAttrib *attrib;
413         GList *l, *connections;
414         struct btd_device *dev;
415         uint16_t desc_handle;
416
417         a = attribute_find(adapter, uuid);
418         if (!a)
419                 return FALSE;
420
421         desc_handle = a->handle + 1;
422
423         connections = (GList *)btd_adapter_get_connections(adapter);
424
425         do {
426                 l = g_list_find_custom(connections, GUINT_TO_POINTER(NULL),
427                                                         is_gatt_connected);
428                 if (l) {
429                         dev = l->data;
430                         attrib = attrib_from_device(dev);
431                         if (attrib) {
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);
437                         }
438                         connections = (GList *)g_slist_next(connections);
439                 } else
440                         break;
441         } while(l);
442
443         return TRUE;
444 }
445
446 bool gatt_update_db(struct btd_adapter *adapter, const bt_uuid_t *uuid,
447                                         uint8_t *value, size_t len)
448 {
449         struct attribute *a;
450         uint8_t status;
451
452         a = attribute_find(adapter, uuid);
453         if (!a)
454                 return FALSE;
455         status = attrib_db_update(adapter, a->handle, NULL, value, len, NULL);
456
457         if (status)
458                 return FALSE;
459
460         return TRUE;
461 }
462
463 bool gatt_add_descriptor(struct btd_adapter *adapter, uint16_t *handle,
464                                         uint16_t start_handle, gatt_option opt1, ...)
465 {
466         va_list args;
467         GSList *disc, *l;
468         uint16_t disc_handle = *handle;
469
470         va_start(args, opt1);
471         disc = parse_opts(opt1, args);
472         va_end(args);
473
474         for (l = disc; l != NULL; l = l->next) {
475                 struct gatt_info *info = l->data;
476
477                 DBG("New Descriptor: handle 0x%04x, start handle 0x%04x",
478                                                 disc_handle, start_handle);
479                 if (!add_descriptor(adapter, &disc_handle, info)) {
480                         goto fail;
481                 }
482         }
483
484         g_slist_free_full(disc, free_gatt_info);
485         *handle = disc_handle;
486
487         return TRUE;
488
489 fail:
490         g_slist_free_full(disc, free_gatt_info);
491         return FALSE;
492 }
493
494 bool gatt_add_characteristic(struct btd_adapter *adapter,
495                 uint16_t *handle, uint16_t start_handle,
496                 gatt_option opt1, ...)
497 {
498         va_list args;
499         GSList *chrs, *l;
500         uint16_t char_handle = *handle;
501
502         va_start(args, opt1);
503         chrs = parse_opts(opt1, args);
504         va_end(args);
505
506         for (l = chrs; l != NULL; l = l->next) {
507                 struct gatt_info *info = l->data;
508
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,
513                                                 char_handle - 1);
514                         goto fail;
515                 }
516         }
517
518         g_slist_free_full(chrs, free_gatt_info);
519         *handle = char_handle;
520
521         return TRUE;
522
523 fail:
524         g_slist_free_full(chrs, free_gatt_info);
525         return FALSE;
526 }
527
528 void attrib_remove_service(struct btd_adapter *adapter, uint16_t start_handle,
529                                                         uint16_t end_handle)
530 {
531         DBG("gatt_remove_service");
532         service_attr_del(adapter, start_handle, end_handle);
533 }
534
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)
538 {
539         char uuidstr[MAX_LEN_UUID_STR];
540         uint16_t handle, h;
541
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);
545                 return FALSE;
546         }
547
548         handle = attrib_db_find_avail(adapter, svc_uuid, size);
549         if (handle == 0) {
550                 error("Not enough free handles to register service");
551                 goto fail;
552         }
553
554         DBG("New service: handle 0x%04x, UUID %s, %d attributes",
555                                                 handle, uuidstr, size);
556
557         /* service declaration */
558         h = handle;
559         *start_handle = handle;
560         if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
561                 goto fail;
562
563         return h;
564
565 fail:
566         return 0;
567 }
568 #endif
569
570 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
571                                 bt_uuid_t *svc_uuid, gatt_option opt1, ...)
572 {
573         char uuidstr[MAX_LEN_UUID_STR];
574         uint16_t start_handle, h;
575         unsigned int size;
576         va_list args;
577         GSList *chrs, *l;
578
579         bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
580
581         if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
582                 error("Invalid service uuid: %s", uuidstr);
583                 return FALSE;
584         }
585
586         va_start(args, opt1);
587         chrs = parse_opts(opt1, args);
588         va_end(args);
589
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;
594         }
595
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");
599                 goto fail;
600         }
601
602         DBG("New service: handle 0x%04x, UUID %s, %d attributes",
603                                                 start_handle, uuidstr, size);
604
605         /* service declaration */
606         h = start_handle;
607         if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
608                 goto fail;
609
610         for (l = chrs; l != NULL; l = l->next) {
611                 struct gatt_info *info = l->data;
612
613                 DBG("New characteristic: handle 0x%04x", h);
614                 if (!add_characteristic(adapter, &h, info)) {
615                         service_attr_del(adapter, start_handle, h - 1);
616                         goto fail;
617                 }
618         }
619
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);
623
624         return TRUE;
625
626 fail:
627         g_slist_free_full(chrs, free_gatt_info);
628         return FALSE;
629 }
630
631 #if 0
632 guint gatt_char_value_notify(GAttrib *attrib, uint16_t handle, uint8_t *value,
633                                         int vlen, GAttribResultFunc func,       gpointer user_data)
634 {
635         size_t buflen;
636         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
637         guint16 plen;
638
639         plen = enc_notification(handle, value, vlen, buf, buflen);
640         if (plen == 0)
641                 return 0;
642
643         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
644 }
645
646 guint gatt_char_value_indicate(GAttrib *attrib, uint16_t handle, uint8_t *value,
647                                         int vlen, GAttribResultFunc func,       gpointer user_data)
648 {
649         size_t buflen;
650         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
651         guint16 plen;
652
653         plen = enc_indication(handle, value, vlen, buf, buflen);
654         if (plen == 0)
655                 return 0;
656
657         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
658 }
659 #endif