Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / attrib / gatt.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2010  Nokia Corporation
6  *  Copyright (C) 2010  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 <stdint.h>
30 #include <stdlib.h>
31
32 #include <glib.h>
33
34 #include "lib/sdp.h"
35 #include "lib/sdp_lib.h"
36 #include "lib/uuid.h"
37
38 #include "src/shared/util.h"
39 #include "att.h"
40 #include "gattrib.h"
41 #include "gatt.h"
42
43 struct discover_primary {
44         int ref;
45         GAttrib *attrib;
46         unsigned int id;
47         bt_uuid_t uuid;
48         uint16_t start;
49         GSList *primaries;
50         gatt_cb_t cb;
51         void *user_data;
52 };
53
54 /* Used for the Included Services Discovery (ISD) procedure */
55 struct included_discovery {
56         GAttrib         *attrib;
57         unsigned int    id;
58         int             refs;
59         int             err;
60         uint16_t        start_handle;
61         uint16_t        end_handle;
62         GSList          *includes;
63         gatt_cb_t       cb;
64         void            *user_data;
65 };
66
67 struct included_uuid_query {
68         struct included_discovery       *isd;
69         struct gatt_included            *included;
70 };
71
72 struct discover_char {
73         int ref;
74         GAttrib *attrib;
75         unsigned int id;
76         bt_uuid_t *uuid;
77         uint16_t end;
78         uint16_t start;
79         GSList *characteristics;
80         gatt_cb_t cb;
81         void *user_data;
82 };
83
84 struct discover_desc {
85         int ref;
86         GAttrib *attrib;
87         unsigned int id;
88         bt_uuid_t *uuid;
89         uint16_t start;
90         uint16_t end;
91         GSList *descriptors;
92         gatt_cb_t cb;
93         void *user_data;
94 };
95
96 static void discover_primary_unref(void *data)
97 {
98         struct discover_primary *dp = data;
99
100         dp->ref--;
101
102         if (dp->ref > 0)
103                 return;
104
105         g_slist_free_full(dp->primaries, g_free);
106         g_attrib_unref(dp->attrib);
107         g_free(dp);
108 }
109
110 static struct discover_primary *discover_primary_ref(
111                                                 struct discover_primary *dp)
112 {
113         dp->ref++;
114
115         return dp;
116 }
117
118 static struct included_discovery *isd_ref(struct included_discovery *isd)
119 {
120         __sync_fetch_and_add(&isd->refs, 1);
121
122         return isd;
123 }
124
125 static void isd_unref(struct included_discovery *isd)
126 {
127         if (__sync_sub_and_fetch(&isd->refs, 1) > 0)
128                 return;
129
130         if (isd->err)
131                 isd->cb(isd->err, NULL, isd->user_data);
132         else
133                 isd->cb(isd->err, isd->includes, isd->user_data);
134
135         g_slist_free_full(isd->includes, g_free);
136         g_attrib_unref(isd->attrib);
137         g_free(isd);
138 }
139
140 static void discover_char_unref(void *data)
141 {
142         struct discover_char *dc = data;
143
144         dc->ref--;
145
146         if (dc->ref > 0)
147                 return;
148
149         g_slist_free_full(dc->characteristics, g_free);
150         g_attrib_unref(dc->attrib);
151         g_free(dc->uuid);
152         g_free(dc);
153 }
154
155 static struct discover_char *discover_char_ref(struct discover_char *dc)
156 {
157         dc->ref++;
158
159         return dc;
160 }
161
162 static void discover_desc_unref(void *data)
163 {
164         struct discover_desc *dd = data;
165
166         dd->ref--;
167
168         if (dd->ref > 0)
169                 return;
170
171         g_slist_free_full(dd->descriptors, g_free);
172         g_attrib_unref(dd->attrib);
173         g_free(dd->uuid);
174         g_free(dd);
175 }
176
177 static struct discover_desc *discover_desc_ref(struct discover_desc *dd)
178 {
179         dd->ref++;
180
181         return dd;
182 }
183
184 static void put_uuid_le(const bt_uuid_t *uuid, void *dst)
185 {
186         if (uuid->type == BT_UUID16)
187                 put_le16(uuid->value.u16, dst);
188 #ifdef __TIZEN_PATCH__
189         else if (uuid->type == BT_UUID32)
190                 put_le32(uuid->value.u32, dst);
191 #endif
192         else
193                 /* Convert from 128-bit BE to LE */
194                 bswap_128(&uuid->value.u128, dst);
195 }
196
197 static void get_uuid128(uint8_t type, const void *val, bt_uuid_t *uuid)
198 {
199         if (type == BT_UUID16) {
200                 bt_uuid_t uuid16;
201
202                 bt_uuid16_create(&uuid16, get_le16(val));
203                 bt_uuid_to_uuid128(&uuid16, uuid);
204 #ifdef __TIZEN_PATCH__
205         } else if (type == BT_UUID32) {
206                 bt_uuid_t uuid32;
207
208                 bt_uuid32_create(&uuid32, get_le32(val));
209                 bt_uuid_to_uuid128(&uuid32, uuid);
210 #endif
211         } else {
212                 uint128_t u128;
213
214                 /* Convert from 128-bit LE to BE */
215                 bswap_128(val, &u128);
216                 bt_uuid128_create(uuid, u128);
217         }
218 }
219
220 static guint16 encode_discover_primary(uint16_t start, uint16_t end,
221                                 bt_uuid_t *uuid, uint8_t *pdu, size_t len)
222 {
223         bt_uuid_t prim;
224         guint16 plen;
225
226         bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID);
227
228         if (uuid == NULL) {
229                 /* Discover all primary services */
230                 plen = enc_read_by_grp_req(start, end, &prim, pdu, len);
231         } else {
232                 uint8_t value[16];
233                 size_t vlen;
234
235                 /* Discover primary service by service UUID */
236                 put_uuid_le(uuid, value);
237                 vlen = bt_uuid_len(uuid);
238
239                 plen = enc_find_by_type_req(start, end, &prim, value, vlen,
240                                                                 pdu, len);
241         }
242
243         return plen;
244 }
245
246 static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
247                                         guint16 iplen, gpointer user_data)
248
249 {
250         struct discover_primary *dp = user_data;
251         GSList *ranges, *last;
252         struct att_range *range;
253         uint8_t *buf;
254         guint16 oplen;
255         int err = 0;
256         size_t buflen;
257
258         if (status) {
259                 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
260                 goto done;
261         }
262
263         ranges = dec_find_by_type_resp(ipdu, iplen);
264         if (ranges == NULL)
265                 goto done;
266
267         dp->primaries = g_slist_concat(dp->primaries, ranges);
268
269         last = g_slist_last(ranges);
270         range = last->data;
271
272         if (range->end == 0xffff)
273                 goto done;
274
275         /*
276          * If last handle is lower from previous start handle then it is smth
277          * wrong. Let's stop search, otherwise we might enter infinite loop.
278          */
279         if (range->end < dp->start) {
280                 err = ATT_ECODE_UNLIKELY;
281                 goto done;
282         }
283
284         dp->start = range->end + 1;
285
286         buf = g_attrib_get_buffer(dp->attrib, &buflen);
287         oplen = encode_discover_primary(dp->start, 0xffff, &dp->uuid,
288                                                                 buf, buflen);
289
290         if (oplen == 0)
291                 goto done;
292
293         g_attrib_send(dp->attrib, dp->id, buf, oplen, primary_by_uuid_cb,
294                         discover_primary_ref(dp), discover_primary_unref);
295         return;
296
297 done:
298         dp->cb(err, dp->primaries, dp->user_data);
299 }
300
301 static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
302                                                         gpointer user_data)
303 {
304         struct discover_primary *dp = user_data;
305         struct att_data_list *list;
306         unsigned int i, err;
307         uint16_t start, end;
308         uint8_t type;
309
310         if (status) {
311                 err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
312                 goto done;
313         }
314
315         list = dec_read_by_grp_resp(ipdu, iplen);
316         if (list == NULL) {
317                 err = ATT_ECODE_IO;
318                 goto done;
319         }
320
321         if (list->len == 6)
322                 type = BT_UUID16;
323         else if (list->len == 20)
324                 type = BT_UUID128;
325         else {
326                 att_data_list_free(list);
327                 err = ATT_ECODE_INVALID_PDU;
328                 goto done;
329         }
330
331         for (i = 0, end = 0; i < list->num; i++) {
332                 const uint8_t *data = list->data[i];
333                 struct gatt_primary *primary;
334                 bt_uuid_t uuid128;
335
336                 start = get_le16(&data[0]);
337                 end = get_le16(&data[2]);
338
339                 get_uuid128(type, &data[4], &uuid128);
340
341                 primary = g_try_new0(struct gatt_primary, 1);
342                 if (!primary) {
343                         att_data_list_free(list);
344                         err = ATT_ECODE_INSUFF_RESOURCES;
345                         goto done;
346                 }
347                 primary->range.start = start;
348                 primary->range.end = end;
349                 bt_uuid_to_string(&uuid128, primary->uuid, sizeof(primary->uuid));
350                 dp->primaries = g_slist_append(dp->primaries, primary);
351         }
352
353         att_data_list_free(list);
354         err = 0;
355
356         /*
357          * If last handle is lower from previous start handle then it is smth
358          * wrong. Let's stop search, otherwise we might enter infinite loop.
359          */
360         if (end < dp->start) {
361                 err = ATT_ECODE_UNLIKELY;
362                 goto done;
363         }
364
365         dp->start = end + 1;
366
367         if (end != 0xffff) {
368                 size_t buflen;
369                 uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen);
370                 guint16 oplen = encode_discover_primary(dp->start, 0xffff, NULL,
371                                                                 buf, buflen);
372
373
374                 g_attrib_send(dp->attrib, dp->id, buf, oplen, primary_all_cb,
375                                                 discover_primary_ref(dp),
376                                                 discover_primary_unref);
377
378                 return;
379         }
380
381 done:
382         dp->cb(err, dp->primaries, dp->user_data);
383 }
384
385 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
386                                                         gpointer user_data)
387 {
388         struct discover_primary *dp;
389         size_t buflen;
390         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
391         GAttribResultFunc cb;
392         guint16 plen;
393
394         plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen);
395         if (plen == 0)
396                 return 0;
397
398         dp = g_try_new0(struct discover_primary, 1);
399         if (dp == NULL)
400                 return 0;
401
402         dp->attrib = g_attrib_ref(attrib);
403         dp->cb = func;
404         dp->user_data = user_data;
405         dp->start = 0x0001;
406
407         if (uuid) {
408                 dp->uuid = *uuid;
409                 cb = primary_by_uuid_cb;
410         } else
411                 cb = primary_all_cb;
412
413         dp->id = g_attrib_send(attrib, 0, buf, plen, cb,
414                                         discover_primary_ref(dp),
415                                         discover_primary_unref);
416
417         return dp->id;
418 }
419
420 static void resolve_included_uuid_cb(uint8_t status, const uint8_t *pdu,
421                                         uint16_t len, gpointer user_data)
422 {
423         struct included_uuid_query *query = user_data;
424         struct included_discovery *isd = query->isd;
425         struct gatt_included *incl = query->included;
426         unsigned int err = status;
427         bt_uuid_t uuid128;
428         size_t buflen;
429         uint8_t *buf;
430
431         if (err)
432                 goto done;
433
434         buf = g_attrib_get_buffer(isd->attrib, &buflen);
435         if (dec_read_resp(pdu, len, buf, buflen) != 16) {
436                 err = ATT_ECODE_IO;
437                 goto done;
438         }
439
440         get_uuid128(BT_UUID128, buf, &uuid128);
441
442         bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
443         isd->includes = g_slist_append(isd->includes, incl);
444         query->included = NULL;
445
446 done:
447         if (isd->err == 0)
448                 isd->err = err;
449 }
450
451 static void inc_query_free(void *data)
452 {
453         struct included_uuid_query *query = data;
454
455         isd_unref(query->isd);
456         g_free(query->included);
457         g_free(query);
458 }
459
460 static guint resolve_included_uuid(struct included_discovery *isd,
461                                         struct gatt_included *incl)
462 {
463         struct included_uuid_query *query;
464         size_t buflen;
465         uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
466         guint16 oplen = enc_read_req(incl->range.start, buf, buflen);
467
468         query = g_new0(struct included_uuid_query, 1);
469         query->isd = isd_ref(isd);
470         query->included = incl;
471
472         return g_attrib_send(isd->attrib, query->isd->id, buf, oplen,
473                                 resolve_included_uuid_cb, query,
474                                 inc_query_free);
475 }
476
477 static struct gatt_included *included_from_buf(const uint8_t *buf, gsize len)
478 {
479         struct gatt_included *incl = g_new0(struct gatt_included, 1);
480
481         incl->handle = get_le16(&buf[0]);
482         incl->range.start = get_le16(&buf[2]);
483         incl->range.end = get_le16(&buf[4]);
484
485         if (len == 8) {
486                 bt_uuid_t uuid128;
487
488                 get_uuid128(BT_UUID16, &buf[6], &uuid128);
489                 bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
490         }
491
492         return incl;
493 }
494
495 static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
496                                                         gpointer user_data);
497
498 static guint find_included(struct included_discovery *isd, uint16_t start)
499 {
500         bt_uuid_t uuid;
501         size_t buflen;
502         uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
503         guint16 oplen;
504
505         bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
506         oplen = enc_read_by_type_req(start, isd->end_handle, &uuid,
507                                                         buf, buflen);
508
509         /* If id != 0 it means we are in the middle of include search */
510         if (isd->id)
511                 return g_attrib_send(isd->attrib, isd->id, buf, oplen,
512                                 find_included_cb, isd_ref(isd),
513                                 (GDestroyNotify) isd_unref);
514
515         /* This is first call from the gattrib user */
516         isd->id = g_attrib_send(isd->attrib, 0, buf, oplen, find_included_cb,
517                                 isd_ref(isd), (GDestroyNotify) isd_unref);
518
519         return isd->id;
520 }
521
522 static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
523                                                         gpointer user_data)
524 {
525         struct included_discovery *isd = user_data;
526         uint16_t last_handle = isd->end_handle;
527         unsigned int err = status;
528         struct att_data_list *list;
529         int i;
530
531         if (err == ATT_ECODE_ATTR_NOT_FOUND)
532                 err = 0;
533
534         if (status)
535                 goto done;
536
537         list = dec_read_by_type_resp(pdu, len);
538         if (list == NULL) {
539                 err = ATT_ECODE_IO;
540                 goto done;
541         }
542
543         if (list->len != 6 && list->len != 8) {
544                 err = ATT_ECODE_IO;
545                 att_data_list_free(list);
546                 goto done;
547         }
548
549         for (i = 0; i < list->num; i++) {
550                 struct gatt_included *incl;
551
552                 incl = included_from_buf(list->data[i], list->len);
553                 last_handle = incl->handle;
554
555                 /* 128 bit UUID, needs resolving */
556                 if (list->len == 6) {
557                         resolve_included_uuid(isd, incl);
558                         continue;
559                 }
560
561                 isd->includes = g_slist_append(isd->includes, incl);
562         }
563
564         att_data_list_free(list);
565
566         /*
567          * If last handle is lower from previous start handle then it is smth
568          * wrong. Let's stop search, otherwise we might enter infinite loop.
569          */
570         if (last_handle < isd->start_handle) {
571                 isd->err = ATT_ECODE_UNLIKELY;
572                 goto done;
573         }
574
575         isd->start_handle = last_handle + 1;
576
577         if (last_handle < isd->end_handle)
578                 find_included(isd, isd->start_handle);
579
580 done:
581         if (isd->err == 0)
582                 isd->err = err;
583 }
584
585 unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
586                                         gatt_cb_t func, gpointer user_data)
587 {
588         struct included_discovery *isd;
589
590         isd = g_new0(struct included_discovery, 1);
591         isd->attrib = g_attrib_ref(attrib);
592         isd->start_handle = start;
593         isd->end_handle = end;
594         isd->cb = func;
595         isd->user_data = user_data;
596
597         return find_included(isd, start);
598 }
599
600 static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
601                                                         gpointer user_data)
602 {
603         struct discover_char *dc = user_data;
604         struct att_data_list *list;
605         unsigned int i, err = 0;
606         uint16_t last = 0;
607         uint8_t type;
608
609         /* We have all the characteristic now, lets send it up */
610         if (status == ATT_ECODE_ATTR_NOT_FOUND) {
611                 err = dc->characteristics ? 0 : status;
612                 goto done;
613         }
614
615         if (status) {
616                 err = status;
617                 goto done;
618         }
619
620         list = dec_read_by_type_resp(ipdu, iplen);
621         if (list == NULL) {
622                 err = ATT_ECODE_IO;
623                 goto done;
624         }
625
626         if (list->len == 7)
627                 type = BT_UUID16;
628         else
629                 type = BT_UUID128;
630
631         for (i = 0; i < list->num; i++) {
632                 uint8_t *value = list->data[i];
633                 struct gatt_char *chars;
634                 bt_uuid_t uuid128;
635
636                 last = get_le16(value);
637
638                 get_uuid128(type, &value[5], &uuid128);
639
640                 if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid128))
641                         continue;
642
643                 chars = g_try_new0(struct gatt_char, 1);
644                 if (!chars) {
645                         att_data_list_free(list);
646                         err = ATT_ECODE_INSUFF_RESOURCES;
647                         goto done;
648                 }
649
650                 chars->handle = last;
651                 chars->properties = value[2];
652                 chars->value_handle = get_le16(&value[3]);
653                 bt_uuid_to_string(&uuid128, chars->uuid, sizeof(chars->uuid));
654                 dc->characteristics = g_slist_append(dc->characteristics,
655                                                                         chars);
656         }
657
658         att_data_list_free(list);
659
660         /*
661          * If last handle is lower from previous start handle then it is smth
662          * wrong. Let's stop search, otherwise we might enter infinite loop.
663          */
664         if (last < dc->start) {
665                 err = ATT_ECODE_UNLIKELY;
666                 goto done;
667         }
668
669         dc->start = last + 1;
670
671         if (last != 0 && (dc->start < dc->end)) {
672                 bt_uuid_t uuid;
673                 guint16 oplen;
674                 size_t buflen;
675                 uint8_t *buf;
676
677                 buf = g_attrib_get_buffer(dc->attrib, &buflen);
678
679                 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
680
681                 oplen = enc_read_by_type_req(dc->start, dc->end, &uuid, buf,
682                                                                         buflen);
683
684                 if (oplen == 0)
685                         return;
686
687                 g_attrib_send(dc->attrib, dc->id, buf, oplen,
688                                 char_discovered_cb, discover_char_ref(dc),
689                                 discover_char_unref);
690
691                 return;
692         }
693
694 done:
695         dc->cb(err, dc->characteristics, dc->user_data);
696 }
697
698 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
699                                                 bt_uuid_t *uuid, gatt_cb_t func,
700                                                 gpointer user_data)
701 {
702         size_t buflen;
703         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
704         struct discover_char *dc;
705         bt_uuid_t type_uuid;
706         guint16 plen;
707
708         bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID);
709
710         plen = enc_read_by_type_req(start, end, &type_uuid, buf, buflen);
711         if (plen == 0)
712                 return 0;
713
714         dc = g_try_new0(struct discover_char, 1);
715         if (dc == NULL)
716                 return 0;
717
718         dc->attrib = g_attrib_ref(attrib);
719         dc->cb = func;
720         dc->user_data = user_data;
721         dc->end = end;
722         dc->start = start;
723         dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
724
725         dc->id = g_attrib_send(attrib, 0, buf, plen, char_discovered_cb,
726                                 discover_char_ref(dc), discover_char_unref);
727
728         return dc->id;
729 }
730
731 guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
732                                         bt_uuid_t *uuid, GAttribResultFunc func,
733                                         gpointer user_data)
734 {
735         size_t buflen;
736         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
737         guint16 plen;
738
739         plen = enc_read_by_type_req(start, end, uuid, buf, buflen);
740         if (plen == 0)
741                 return 0;
742
743         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
744 }
745
746 struct read_long_data {
747         GAttrib *attrib;
748         GAttribResultFunc func;
749         gpointer user_data;
750         guint8 *buffer;
751         guint16 size;
752         guint16 handle;
753         guint id;
754         int ref;
755 };
756
757 static void read_long_destroy(gpointer user_data)
758 {
759         struct read_long_data *long_read = user_data;
760
761         if (__sync_sub_and_fetch(&long_read->ref, 1) > 0)
762                 return;
763
764         g_attrib_unref(long_read->attrib);
765
766         if (long_read->buffer != NULL)
767                 g_free(long_read->buffer);
768
769         g_free(long_read);
770 }
771
772 static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
773                                                         gpointer user_data)
774 {
775         struct read_long_data *long_read = user_data;
776         uint8_t *buf;
777         size_t buflen;
778         guint8 *tmp;
779         guint16 plen;
780         guint id;
781
782         if (status != 0 || rlen == 1) {
783                 status = 0;
784                 goto done;
785         }
786
787         tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1);
788
789         if (tmp == NULL) {
790                 status = ATT_ECODE_INSUFF_RESOURCES;
791                 goto done;
792         }
793
794         memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1);
795         long_read->buffer = tmp;
796         long_read->size += rlen - 1;
797
798         buf = g_attrib_get_buffer(long_read->attrib, &buflen);
799         if (rlen < buflen)
800                 goto done;
801
802         plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
803                                                                 buf, buflen);
804         id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
805                                 read_blob_helper, long_read, read_long_destroy);
806
807         if (id != 0) {
808                 __sync_fetch_and_add(&long_read->ref, 1);
809                 return;
810         }
811
812         status = ATT_ECODE_IO;
813
814 done:
815         long_read->func(status, long_read->buffer, long_read->size,
816                                                         long_read->user_data);
817 }
818
819 static void read_char_helper(guint8 status, const guint8 *rpdu,
820                                         guint16 rlen, gpointer user_data)
821 {
822         struct read_long_data *long_read = user_data;
823         size_t buflen;
824         uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen);
825         guint16 plen;
826         guint id;
827
828         if (status != 0 || rlen < buflen)
829                 goto done;
830
831         long_read->buffer = g_malloc(rlen);
832         if (long_read->buffer == NULL) {
833                 status = ATT_ECODE_INSUFF_RESOURCES;
834                 goto done;
835         }
836
837         memcpy(long_read->buffer, rpdu, rlen);
838         long_read->size = rlen;
839
840         plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
841
842         id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
843                                 read_blob_helper, long_read, read_long_destroy);
844         if (id != 0) {
845                 __sync_fetch_and_add(&long_read->ref, 1);
846                 return;
847         }
848
849         status = ATT_ECODE_IO;
850
851 done:
852         long_read->func(status, rpdu, rlen, long_read->user_data);
853 }
854
855 #ifdef __TIZEN_PATCH__
856 guint gatt_read_char_by_offset(GAttrib *attrib, uint16_t handle, uint16_t offset,
857                                 GAttribResultFunc func, gpointer user_data)
858 {
859         uint8_t *buf;
860         size_t buflen;
861         guint16 plen;
862         guint id;
863         struct read_long_data *long_read;
864
865         long_read = g_try_new0(struct read_long_data, 1);
866
867         if (long_read == NULL)
868                 return 0;
869
870         long_read->attrib = attrib;
871         long_read->func = func;
872         long_read->user_data = user_data;
873         long_read->handle = handle;
874
875         buf = g_attrib_get_buffer(attrib, &buflen);
876         if (offset > 0)
877                 plen = enc_read_blob_req(handle, offset, buf, buflen);
878         else
879                 plen = enc_read_req(handle, buf, buflen);
880
881         id = g_attrib_send(attrib, 0, buf, plen, read_char_helper,
882                                                 long_read, read_long_destroy);
883         if (id == 0)
884                 g_free(long_read);
885         else {
886                 __sync_fetch_and_add(&long_read->ref, 1);
887                 long_read->id = id;
888         }
889
890         return id;
891 }
892 #endif
893
894 guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
895                                                         gpointer user_data)
896 {
897         uint8_t *buf;
898         size_t buflen;
899         guint16 plen;
900         guint id;
901         struct read_long_data *long_read;
902
903         long_read = g_try_new0(struct read_long_data, 1);
904
905         if (long_read == NULL)
906                 return 0;
907
908         long_read->attrib = g_attrib_ref(attrib);
909         long_read->func = func;
910         long_read->user_data = user_data;
911         long_read->handle = handle;
912
913         buf = g_attrib_get_buffer(attrib, &buflen);
914         plen = enc_read_req(handle, buf, buflen);
915         id = g_attrib_send(attrib, 0, buf, plen, read_char_helper,
916                                                 long_read, read_long_destroy);
917         if (id == 0) {
918                 g_attrib_unref(long_read->attrib);
919                 g_free(long_read);
920         } else {
921                 __sync_fetch_and_add(&long_read->ref, 1);
922                 long_read->id = id;
923         }
924
925         return id;
926 }
927
928 struct write_long_data {
929         GAttrib *attrib;
930         GAttribResultFunc func;
931         gpointer user_data;
932         guint16 handle;
933         uint16_t offset;
934         uint8_t *value;
935         size_t vlen;
936 };
937
938 static guint execute_write(GAttrib *attrib, uint8_t flags,
939                                 GAttribResultFunc func, gpointer user_data)
940 {
941         uint8_t *buf;
942         size_t buflen;
943         guint16 plen;
944
945         buf = g_attrib_get_buffer(attrib, &buflen);
946         plen = enc_exec_write_req(flags, buf, buflen);
947         if (plen == 0)
948                 return 0;
949
950         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
951 }
952
953 static guint prepare_write(struct write_long_data *long_write);
954
955 static void prepare_write_cb(guint8 status, const guint8 *rpdu, guint16 rlen,
956                                                         gpointer user_data)
957 {
958         struct write_long_data *long_write = user_data;
959
960         if (status != 0) {
961                 long_write->func(status, rpdu, rlen, long_write->user_data);
962                 return;
963         }
964
965         /* Skip Prepare Write Response PDU header (5 bytes) */
966         long_write->offset += rlen - 5;
967
968         if (long_write->offset == long_write->vlen) {
969                 execute_write(long_write->attrib, ATT_WRITE_ALL_PREP_WRITES,
970                                 long_write->func, long_write->user_data);
971                 g_free(long_write->value);
972                 g_free(long_write);
973
974                 return;
975         }
976
977         prepare_write(long_write);
978 }
979
980 static guint prepare_write(struct write_long_data *long_write)
981 {
982         GAttrib *attrib = long_write->attrib;
983         uint16_t handle = long_write->handle;
984         uint16_t offset = long_write->offset;
985         uint8_t *buf, *value = long_write->value + offset;
986         size_t buflen, vlen = long_write->vlen - offset;
987         guint16 plen;
988
989         buf = g_attrib_get_buffer(attrib, &buflen);
990
991         plen = enc_prep_write_req(handle, offset, value, vlen, buf, buflen);
992         if (plen == 0)
993                 return 0;
994
995         return g_attrib_send(attrib, 0, buf, plen, prepare_write_cb, long_write,
996                                                                         NULL);
997 }
998
999 guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value,
1000                         size_t vlen, GAttribResultFunc func, gpointer user_data)
1001 {
1002         uint8_t *buf;
1003         size_t buflen;
1004         struct write_long_data *long_write;
1005
1006         buf = g_attrib_get_buffer(attrib, &buflen);
1007
1008         /* Use Write Request if payload fits on a single transfer, including 3
1009          * bytes for the header. */
1010         if (vlen <= buflen - 3) {
1011                 uint16_t plen;
1012
1013                 plen = enc_write_req(handle, value, vlen, buf, buflen);
1014                 if (plen == 0)
1015                         return 0;
1016
1017                 return g_attrib_send(attrib, 0, buf, plen, func, user_data,
1018                                                                         NULL);
1019         }
1020
1021         /* Write Long Characteristic Values */
1022         long_write = g_try_new0(struct write_long_data, 1);
1023         if (long_write == NULL)
1024                 return 0;
1025
1026         long_write->attrib = attrib;
1027         long_write->func = func;
1028         long_write->user_data = user_data;
1029         long_write->handle = handle;
1030         long_write->value = g_memdup(value, vlen);
1031         long_write->vlen = vlen;
1032
1033         return prepare_write(long_write);
1034 }
1035
1036 guint gatt_execute_write(GAttrib *attrib, uint8_t flags,
1037                                 GAttribResultFunc func, gpointer user_data)
1038 {
1039         return execute_write(attrib, flags, func, user_data);
1040 }
1041
1042 guint gatt_reliable_write_char(GAttrib *attrib, uint16_t handle,
1043                                         const uint8_t *value, size_t vlen,
1044                                         GAttribResultFunc func,
1045                                         gpointer user_data)
1046 {
1047         uint8_t *buf;
1048         guint16 plen;
1049         size_t buflen;
1050
1051         buf = g_attrib_get_buffer(attrib, &buflen);
1052
1053         plen = enc_prep_write_req(handle, 0, value, vlen, buf, buflen);
1054         if (!plen)
1055                 return 0;
1056
1057         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
1058 }
1059
1060 guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
1061                                                         gpointer user_data)
1062 {
1063         uint8_t *buf;
1064         size_t buflen;
1065         guint16 plen;
1066
1067         buf = g_attrib_get_buffer(attrib, &buflen);
1068         plen = enc_mtu_req(mtu, buf, buflen);
1069         return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
1070 }
1071
1072 static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
1073                                         guint16 iplen, gpointer user_data)
1074 {
1075         struct discover_desc *dd = user_data;
1076         struct att_data_list *list;
1077         unsigned int i, err = 0;
1078         guint8 format;
1079         uint16_t last = 0xffff;
1080         uint8_t type;
1081         gboolean uuid_found = FALSE;
1082
1083         if (status == ATT_ECODE_ATTR_NOT_FOUND) {
1084                 err = dd->descriptors ? 0 : status;
1085                 goto done;
1086         }
1087
1088         if (status) {
1089                 err = status;
1090                 goto done;
1091         }
1092
1093         list = dec_find_info_resp(ipdu, iplen, &format);
1094         if (!list) {
1095                 err = ATT_ECODE_IO;
1096                 goto done;
1097         }
1098
1099         if (format == ATT_FIND_INFO_RESP_FMT_16BIT)
1100                 type = BT_UUID16;
1101         else
1102                 type = BT_UUID128;
1103
1104         for (i = 0; i < list->num; i++) {
1105                 uint8_t *value = list->data[i];
1106                 struct gatt_desc *desc;
1107                 bt_uuid_t uuid128;
1108
1109                 last = get_le16(value);
1110
1111                 get_uuid128(type, &value[2], &uuid128);
1112
1113                 if (dd->uuid) {
1114                         if (bt_uuid_cmp(dd->uuid, &uuid128))
1115                                 continue;
1116                         else
1117                                 uuid_found = TRUE;
1118                 }
1119
1120                 desc = g_try_new0(struct gatt_desc, 1);
1121                 if (!desc) {
1122                         att_data_list_free(list);
1123                         err = ATT_ECODE_INSUFF_RESOURCES;
1124                         goto done;
1125                 }
1126
1127                 bt_uuid_to_string(&uuid128, desc->uuid, sizeof(desc->uuid));
1128                 desc->handle = last;
1129
1130                 if (type == BT_UUID16)
1131                         desc->uuid16 = get_le16(&value[2]);
1132
1133                 dd->descriptors = g_slist_append(dd->descriptors, desc);
1134
1135                 if (uuid_found)
1136                         break;
1137         }
1138
1139         att_data_list_free(list);
1140
1141         /*
1142          * If last handle is lower from previous start handle then it is smth
1143          * wrong. Let's stop search, otherwise we might enter infinite loop.
1144          */
1145         if (last < dd->start) {
1146                 err = ATT_ECODE_UNLIKELY;
1147                 goto done;
1148         }
1149
1150         dd->start = last + 1;
1151
1152         if (last < dd->end && !uuid_found) {
1153                 guint16 oplen;
1154                 size_t buflen;
1155                 uint8_t *buf;
1156
1157                 buf = g_attrib_get_buffer(dd->attrib, &buflen);
1158
1159                 oplen = enc_find_info_req(dd->start, dd->end, buf, buflen);
1160                 if (oplen == 0)
1161                         return;
1162
1163                 g_attrib_send(dd->attrib, dd->id, buf, oplen,
1164                                 desc_discovered_cb, discover_desc_ref(dd),
1165                                 discover_desc_unref);
1166
1167                 return;
1168         }
1169
1170 done:
1171         dd->cb(err, dd->descriptors, dd->user_data);
1172 }
1173
1174 guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
1175                                                 bt_uuid_t *uuid, gatt_cb_t func,
1176                                                 gpointer user_data)
1177 {
1178         size_t buflen;
1179         uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
1180         struct discover_desc *dd;
1181         guint16 plen;
1182
1183         plen = enc_find_info_req(start, end, buf, buflen);
1184         if (plen == 0)
1185                 return 0;
1186
1187         dd = g_try_new0(struct discover_desc, 1);
1188         if (dd == NULL)
1189                 return 0;
1190
1191         dd->attrib = g_attrib_ref(attrib);
1192         dd->cb = func;
1193         dd->user_data = user_data;
1194         dd->start = start;
1195         dd->end = end;
1196         dd->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
1197
1198         dd->id = g_attrib_send(attrib, 0, buf, plen, desc_discovered_cb,
1199                                 discover_desc_ref(dd), discover_desc_unref);
1200
1201         return dd->id;
1202 }
1203
1204 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
1205                         int vlen, GDestroyNotify notify, gpointer user_data)
1206 {
1207         uint8_t *buf;
1208         size_t buflen;
1209         guint16 plen;
1210
1211         buf = g_attrib_get_buffer(attrib, &buflen);
1212         plen = enc_write_cmd(handle, value, vlen, buf, buflen);
1213         return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
1214 }
1215
1216 guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
1217                                                 const uint8_t *value, int vlen,
1218                                                 struct bt_crypto *crypto,
1219                                                 const uint8_t csrk[16],
1220                                                 uint32_t sign_cnt,
1221                                                 GDestroyNotify notify,
1222                                                 gpointer user_data)
1223 {
1224         uint8_t *buf;
1225         size_t buflen;
1226         guint16 plen;
1227
1228         buf = g_attrib_get_buffer(attrib, &buflen);
1229         plen = enc_signed_write_cmd(handle, value, vlen, crypto, csrk, sign_cnt,
1230                                                                 buf, buflen);
1231         if (plen == 0)
1232                 return 0;
1233
1234         return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
1235 }
1236
1237 static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
1238 {
1239         sdp_list_t *list;
1240         uuid_t proto;
1241
1242         sdp_uuid16_create(&proto, ATT_UUID);
1243
1244         for (list = proto_list; list; list = list->next) {
1245                 sdp_list_t *p;
1246                 for (p = list->data; p; p = p->next) {
1247                         sdp_data_t *seq = p->data;
1248                         if (seq && seq->dtd == SDP_UUID16 &&
1249                                 sdp_uuid16_cmp(&proto, &seq->val.uuid) == 0)
1250                                 return seq->next;
1251                 }
1252         }
1253
1254         return NULL;
1255 }
1256
1257 static gboolean parse_proto_params(sdp_list_t *proto_list, uint16_t *psm,
1258                                                 uint16_t *start, uint16_t *end)
1259 {
1260         sdp_data_t *seq1, *seq2;
1261
1262         if (psm)
1263                 *psm = sdp_get_proto_port(proto_list, L2CAP_UUID);
1264
1265         /* Getting start and end handle */
1266         seq1 = proto_seq_find(proto_list);
1267         if (!seq1 || seq1->dtd != SDP_UINT16)
1268                 return FALSE;
1269
1270         seq2 = seq1->next;
1271         if (!seq2 || seq2->dtd != SDP_UINT16)
1272                 return FALSE;
1273
1274         if (start)
1275                 *start = seq1->val.uint16;
1276
1277         if (end)
1278                 *end = seq2->val.uint16;
1279
1280         return TRUE;
1281 }
1282
1283 gboolean gatt_parse_record(const sdp_record_t *rec,
1284                                         uuid_t *prim_uuid, uint16_t *psm,
1285                                         uint16_t *start, uint16_t *end)
1286 {
1287         sdp_list_t *list;
1288         uuid_t uuid;
1289         gboolean ret;
1290
1291         if (sdp_get_service_classes(rec, &list) < 0)
1292                 return FALSE;
1293
1294         memcpy(&uuid, list->data, sizeof(uuid));
1295         sdp_list_free(list, free);
1296
1297         if (sdp_get_access_protos(rec, &list) < 0)
1298                 return FALSE;
1299
1300         ret = parse_proto_params(list, psm, start, end);
1301
1302         sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL);
1303         sdp_list_free(list, NULL);
1304
1305         /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */
1306         if (ret && prim_uuid)
1307                 memcpy(prim_uuid, &uuid, sizeof(uuid_t));
1308
1309         return ret;
1310 }