Fix build break for rpm
[framework/connectivity/bluez.git] / attrib / gattrib.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 #include <stdint.h>
26 #include <string.h>
27 #include <glib.h>
28
29 #include <stdio.h>
30
31 #include <bluetooth/bluetooth.h>
32 #include <bluetooth/uuid.h>
33
34 #include "log.h"
35 #include "att.h"
36 #include "btio.h"
37 #include "gattrib.h"
38
39 #define GATT_TIMEOUT 30
40
41 struct _GAttrib {
42         GIOChannel *io;
43         gint refs;
44         uint8_t *buf;
45         int buflen;
46         guint read_watch;
47         guint write_watch;
48         guint timeout_watch;
49         GQueue *requests;
50         GQueue *responses;
51         GSList *events;
52         guint next_cmd_id;
53         GDestroyNotify destroy;
54         gpointer destroy_user_data;
55         gboolean stale;
56 };
57
58 struct command {
59         guint id;
60         guint8 opcode;
61         guint8 *pdu;
62         guint16 len;
63         guint8 expected;
64         gboolean sent;
65         GAttribResultFunc func;
66         gpointer user_data;
67         GDestroyNotify notify;
68 };
69
70 struct event {
71         guint id;
72         guint8 expected;
73         GAttribNotifyFunc func;
74         gpointer user_data;
75         GDestroyNotify notify;
76 };
77
78 static guint8 opcode2expected(guint8 opcode)
79 {
80         switch (opcode) {
81         case ATT_OP_MTU_REQ:
82                 return ATT_OP_MTU_RESP;
83
84         case ATT_OP_FIND_INFO_REQ:
85                 return ATT_OP_FIND_INFO_RESP;
86
87         case ATT_OP_FIND_BY_TYPE_REQ:
88                 return ATT_OP_FIND_BY_TYPE_RESP;
89
90         case ATT_OP_READ_BY_TYPE_REQ:
91                 return ATT_OP_READ_BY_TYPE_RESP;
92
93         case ATT_OP_READ_REQ:
94                 return ATT_OP_READ_RESP;
95
96         case ATT_OP_READ_BLOB_REQ:
97                 return ATT_OP_READ_BLOB_RESP;
98
99         case ATT_OP_READ_MULTI_REQ:
100                 return ATT_OP_READ_MULTI_RESP;
101
102         case ATT_OP_READ_BY_GROUP_REQ:
103                 return ATT_OP_READ_BY_GROUP_RESP;
104
105         case ATT_OP_WRITE_REQ:
106                 return ATT_OP_WRITE_RESP;
107
108         case ATT_OP_PREP_WRITE_REQ:
109                 return ATT_OP_PREP_WRITE_RESP;
110
111         case ATT_OP_EXEC_WRITE_REQ:
112                 return ATT_OP_EXEC_WRITE_RESP;
113
114         case ATT_OP_HANDLE_IND:
115                 return ATT_OP_HANDLE_CNF;
116         }
117
118         return 0;
119 }
120
121 static gboolean is_response(guint8 opcode)
122 {
123         switch (opcode) {
124         case ATT_OP_ERROR:
125         case ATT_OP_MTU_RESP:
126         case ATT_OP_FIND_INFO_RESP:
127         case ATT_OP_FIND_BY_TYPE_RESP:
128         case ATT_OP_READ_BY_TYPE_RESP:
129         case ATT_OP_READ_RESP:
130         case ATT_OP_READ_BLOB_RESP:
131         case ATT_OP_READ_MULTI_RESP:
132         case ATT_OP_READ_BY_GROUP_RESP:
133         case ATT_OP_WRITE_RESP:
134         case ATT_OP_PREP_WRITE_RESP:
135         case ATT_OP_EXEC_WRITE_RESP:
136         case ATT_OP_HANDLE_CNF:
137                 return TRUE;
138         }
139
140         return FALSE;
141 }
142
143 GAttrib *g_attrib_ref(GAttrib *attrib)
144 {
145         if (!attrib)
146                 return NULL;
147
148         g_atomic_int_inc(&attrib->refs);
149
150         DBG("%p: ref=%d", attrib, attrib->refs);
151
152         return attrib;
153 }
154
155 static void command_destroy(struct command *cmd)
156 {
157         if (cmd->notify)
158                 cmd->notify(cmd->user_data);
159
160         g_free(cmd->pdu);
161         g_free(cmd);
162 }
163
164 static void event_destroy(struct event *evt)
165 {
166         if (evt->notify)
167                 evt->notify(evt->user_data);
168
169         g_free(evt);
170 }
171
172 static void attrib_destroy(GAttrib *attrib)
173 {
174         GSList *l;
175         struct command *c;
176
177         while ((c = g_queue_pop_head(attrib->requests)))
178                 command_destroy(c);
179
180         while ((c = g_queue_pop_head(attrib->responses)))
181                 command_destroy(c);
182
183         g_queue_free(attrib->requests);
184         attrib->requests = NULL;
185
186         g_queue_free(attrib->responses);
187         attrib->responses = NULL;
188
189         for (l = attrib->events; l; l = l->next)
190                 event_destroy(l->data);
191
192         g_slist_free(attrib->events);
193         attrib->events = NULL;
194
195         if (attrib->timeout_watch > 0)
196                 g_source_remove(attrib->timeout_watch);
197
198         if (attrib->write_watch > 0)
199                 g_source_remove(attrib->write_watch);
200
201         if (attrib->read_watch > 0)
202                 g_source_remove(attrib->read_watch);
203
204         if (attrib->io)
205                 g_io_channel_unref(attrib->io);
206
207         g_free(attrib->buf);
208
209         if (attrib->destroy)
210                 attrib->destroy(attrib->destroy_user_data);
211
212         g_free(attrib);
213 }
214
215 void g_attrib_unref(GAttrib *attrib)
216 {
217         gboolean ret;
218
219         if (!attrib)
220                 return;
221
222         ret = g_atomic_int_dec_and_test(&attrib->refs);
223
224         DBG("%p: ref=%d", attrib, attrib->refs);
225
226         if (ret == FALSE)
227                 return;
228
229         attrib_destroy(attrib);
230 }
231
232 GIOChannel *g_attrib_get_channel(GAttrib *attrib)
233 {
234         if (!attrib)
235                 return NULL;
236
237         return attrib->io;
238 }
239
240 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
241                 GDestroyNotify destroy, gpointer user_data)
242 {
243         if (attrib == NULL)
244                 return FALSE;
245
246         attrib->destroy = destroy;
247         attrib->destroy_user_data = user_data;
248
249         return TRUE;
250 }
251
252 static gboolean disconnect_timeout(gpointer data)
253 {
254         struct _GAttrib *attrib = data;
255         struct command *c;
256
257         g_attrib_ref(attrib);
258
259         c = g_queue_pop_head(attrib->requests);
260         if (c == NULL)
261                 goto done;
262
263         if (c->func)
264                 c->func(ATT_ECODE_TIMEOUT, NULL, 0, c->user_data);
265
266         command_destroy(c);
267
268         while ((c = g_queue_pop_head(attrib->requests))) {
269                 if (c->func)
270                         c->func(ATT_ECODE_ABORTED, NULL, 0, c->user_data);
271                 command_destroy(c);
272         }
273
274 done:
275         attrib->stale = TRUE;
276
277         g_attrib_unref(attrib);
278
279         return FALSE;
280 }
281
282 static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
283                                                                 gpointer data)
284 {
285         struct _GAttrib *attrib = data;
286         struct command *cmd;
287         GError *gerr = NULL;
288         gsize len;
289         GIOStatus iostat;
290         GQueue *queue;
291
292         if (attrib->stale)
293                 return FALSE;
294
295         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
296                 return FALSE;
297
298         queue = attrib->responses;
299         cmd = g_queue_peek_head(queue);
300         if (cmd == NULL) {
301                 queue = attrib->requests;
302                 cmd = g_queue_peek_head(queue);
303         }
304         if (cmd == NULL)
305                 return FALSE;
306
307         /*
308          * Verify that we didn't already send this command. This can only
309          * happen with elementes from attrib->requests.
310          */
311         if (cmd->sent)
312                 return FALSE;
313
314         iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
315                                                                 &len, &gerr);
316         if (iostat != G_IO_STATUS_NORMAL)
317                 return FALSE;
318
319         if (cmd->expected == 0) {
320                 g_queue_pop_head(queue);
321                 command_destroy(cmd);
322
323                 return TRUE;
324         }
325
326         cmd->sent = TRUE;
327
328         if (attrib->timeout_watch == 0)
329                 attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
330                                                 disconnect_timeout, attrib);
331
332         return FALSE;
333 }
334
335 static void destroy_sender(gpointer data)
336 {
337         struct _GAttrib *attrib = data;
338
339         attrib->write_watch = 0;
340         g_attrib_unref(attrib);
341 }
342
343 static void wake_up_sender(struct _GAttrib *attrib)
344 {
345         if (attrib->write_watch > 0)
346                 return;
347
348         attrib = g_attrib_ref(attrib);
349         attrib->write_watch = g_io_add_watch_full(attrib->io,
350                                 G_PRIORITY_DEFAULT, G_IO_OUT,
351                                 can_write_data, attrib, destroy_sender);
352 }
353
354 static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
355 {
356         struct _GAttrib *attrib = data;
357         struct command *cmd = NULL;
358         GSList *l;
359         uint8_t buf[512], status;
360         gsize len;
361         GIOStatus iostat;
362         gboolean norequests, noresponses;
363
364         if (attrib->stale)
365                 return FALSE;
366
367         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
368                 attrib->read_watch = 0;
369                 return FALSE;
370         }
371
372         memset(buf, 0, sizeof(buf));
373
374         iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf),
375                                                                 &len, NULL);
376         if (iostat != G_IO_STATUS_NORMAL) {
377                 status = ATT_ECODE_IO;
378                 goto done;
379         }
380
381         for (l = attrib->events; l; l = l->next) {
382                 struct event *evt = l->data;
383
384                 if (evt->expected == buf[0] ||
385                                 evt->expected == GATTRIB_ALL_EVENTS ||
386                                 (is_response(buf[0]) == FALSE &&
387                                                 evt->expected == GATTRIB_ALL_REQS))
388                         evt->func(buf, len, evt->user_data);
389         }
390
391         if (is_response(buf[0]) == FALSE)
392                 return TRUE;
393
394         if (attrib->timeout_watch > 0) {
395                 g_source_remove(attrib->timeout_watch);
396                 attrib->timeout_watch = 0;
397         }
398
399         cmd = g_queue_pop_head(attrib->requests);
400         if (cmd == NULL) {
401                 /* Keep the watch if we have events to report */
402                 return attrib->events != NULL;
403         }
404
405         if (buf[0] == ATT_OP_ERROR) {
406                 status = buf[4];
407                 goto done;
408         }
409
410         if (cmd->expected != buf[0]) {
411                 status = ATT_ECODE_IO;
412                 goto done;
413         }
414
415         status = 0;
416
417 done:
418         norequests = attrib->requests == NULL ||
419                         g_queue_is_empty(attrib->requests);
420         noresponses = attrib->responses == NULL ||
421                         g_queue_is_empty(attrib->responses);
422
423         if (cmd) {
424                 if (cmd->func)
425                         cmd->func(status, buf, len, cmd->user_data);
426
427                 command_destroy(cmd);
428         }
429
430         if (!norequests || !noresponses)
431                 wake_up_sender(attrib);
432
433         return TRUE;
434 }
435
436 GAttrib *g_attrib_new(GIOChannel *io)
437 {
438         struct _GAttrib *attrib;
439         uint16_t imtu;
440         uint16_t att_mtu;
441         uint16_t cid;
442         GError *gerr = NULL;
443
444         g_io_channel_set_encoding(io, NULL, NULL);
445         g_io_channel_set_buffered(io, FALSE);
446
447         bt_io_get(io, BT_IO_L2CAP, &gerr,
448                         BT_IO_OPT_IMTU, &imtu,
449                         BT_IO_OPT_CID, &cid,
450                         BT_IO_OPT_INVALID);
451
452         if (gerr) {
453                 error("%s", gerr->message);
454                 g_error_free(gerr);
455                 return NULL;
456         }
457
458         attrib = g_try_new0(struct _GAttrib, 1);
459         if (attrib == NULL)
460                 return NULL;
461
462         att_mtu = (cid == ATT_CID) ? ATT_DEFAULT_LE_MTU : imtu;
463
464         attrib->buf = g_malloc0(att_mtu);
465         attrib->buflen = att_mtu;
466
467         attrib->io = g_io_channel_ref(io);
468         attrib->requests = g_queue_new();
469         attrib->responses = g_queue_new();
470
471         attrib->read_watch = g_io_add_watch(attrib->io,
472                         G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
473                         received_data, attrib);
474
475         return g_attrib_ref(attrib);
476 }
477
478 guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
479                         const guint8 *pdu, guint16 len, GAttribResultFunc func,
480                         gpointer user_data, GDestroyNotify notify)
481 {
482         struct command *c;
483         GQueue *queue;
484
485         if (attrib->stale)
486                 return 0;
487
488         c = g_try_new0(struct command, 1);
489         if (c == NULL)
490                 return 0;
491
492         c->opcode = opcode;
493         c->expected = opcode2expected(opcode);
494         c->pdu = g_malloc(len);
495         memcpy(c->pdu, pdu, len);
496         c->len = len;
497         c->func = func;
498         c->user_data = user_data;
499         c->notify = notify;
500
501         if (is_response(opcode))
502                 queue = attrib->responses;
503         else
504                 queue = attrib->requests;
505
506         if (id) {
507                 c->id = id;
508                 if (!is_response(opcode))
509                         g_queue_push_head(queue, c);
510                 else
511                         /* Don't re-order responses even if an ID is given */
512                         g_queue_push_tail(queue, c);
513         } else {
514                 c->id = ++attrib->next_cmd_id;
515                 g_queue_push_tail(queue, c);
516         }
517
518         /*
519          * If a command was added to the queue and it was empty before, wake up
520          * the sender. If the sender was already woken up by the second queue,
521          * wake_up_sender will just return.
522          */
523         if (g_queue_get_length(queue) == 1)
524                 wake_up_sender(attrib);
525
526         return c->id;
527 }
528
529 static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
530 {
531         const struct command *cmd = a;
532         guint id = GPOINTER_TO_UINT(b);
533
534         return cmd->id - id;
535 }
536
537 gboolean g_attrib_cancel(GAttrib *attrib, guint id)
538 {
539         GList *l = NULL;
540         struct command *cmd;
541         GQueue *queue;
542
543         if (attrib == NULL)
544                 return FALSE;
545
546         queue = attrib->requests;
547         if (queue)
548                 l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
549                                         command_cmp_by_id);
550         if (l == NULL) {
551                 queue = attrib->responses;
552                 if (!queue)
553                         return FALSE;
554                 l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
555                                         command_cmp_by_id);
556         }
557
558         if (l == NULL)
559                 return FALSE;
560
561         cmd = l->data;
562
563         if (cmd == g_queue_peek_head(queue) && cmd->sent)
564                 cmd->func = NULL;
565         else {
566                 g_queue_remove(queue, cmd);
567                 command_destroy(cmd);
568         }
569
570         return TRUE;
571 }
572
573 static gboolean cancel_all_per_queue(GQueue *queue)
574 {
575         struct command *c, *head = NULL;
576         gboolean first = TRUE;
577
578         if (queue == NULL)
579                 return FALSE;
580
581         while ((c = g_queue_pop_head(queue))) {
582                 if (first && c->sent) {
583                         /* If the command was sent ignore its callback ... */
584                         c->func = NULL;
585                         head = c;
586                         continue;
587                 }
588
589                 first = FALSE;
590                 command_destroy(c);
591         }
592
593         if (head) {
594                 /* ... and put it back in the queue */
595                 g_queue_push_head(queue, head);
596         }
597
598         return TRUE;
599 }
600
601 gboolean g_attrib_cancel_all(GAttrib *attrib)
602 {
603         gboolean ret;
604
605         if (attrib == NULL)
606                 return FALSE;
607
608         ret = cancel_all_per_queue(attrib->requests);
609         ret = cancel_all_per_queue(attrib->responses) && ret;
610
611         return ret;
612 }
613
614 gboolean g_attrib_set_debug(GAttrib *attrib,
615                 GAttribDebugFunc func, gpointer user_data)
616 {
617         return TRUE;
618 }
619
620 uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len)
621 {
622         if (len == NULL)
623                 return NULL;
624
625         *len = attrib->buflen;
626
627         return attrib->buf;
628 }
629
630 gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
631 {
632         if (mtu < ATT_DEFAULT_LE_MTU)
633                 return FALSE;
634
635         attrib->buf = g_realloc(attrib->buf, mtu);
636
637         attrib->buflen = mtu;
638
639         return TRUE;
640 }
641
642 guint g_attrib_register(GAttrib *attrib, guint8 opcode,
643                                 GAttribNotifyFunc func, gpointer user_data,
644                                 GDestroyNotify notify)
645 {
646         static guint next_evt_id = 0;
647         struct event *event;
648
649         event = g_try_new0(struct event, 1);
650         if (event == NULL)
651                 return 0;
652
653         event->expected = opcode;
654         event->func = func;
655         event->user_data = user_data;
656         event->notify = notify;
657         event->id = ++next_evt_id;
658
659         attrib->events = g_slist_append(attrib->events, event);
660
661         return event->id;
662 }
663
664 static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
665 {
666         const struct event *evt = a;
667         guint id = GPOINTER_TO_UINT(b);
668
669         return evt->id - id;
670 }
671
672 gboolean g_attrib_is_encrypted(GAttrib *attrib)
673 {
674         BtIOSecLevel sec_level;
675
676         if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
677                         BT_IO_OPT_SEC_LEVEL, &sec_level,
678                         BT_IO_OPT_INVALID))
679                 return FALSE;
680
681         return sec_level > BT_IO_SEC_LOW;
682 }
683
684 gboolean g_attrib_unregister(GAttrib *attrib, guint id)
685 {
686         struct event *evt;
687         GSList *l;
688
689         l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
690                                                         event_cmp_by_id);
691         if (l == NULL)
692                 return FALSE;
693
694         evt = l->data;
695
696         attrib->events = g_slist_remove(attrib->events, evt);
697
698         if (evt->notify)
699                 evt->notify(evt->user_data);
700
701         g_free(evt);
702
703         return TRUE;
704 }
705
706 gboolean g_attrib_unregister_all(GAttrib *attrib)
707 {
708         GSList *l;
709
710         if (attrib->events == NULL)
711                 return FALSE;
712
713         for (l = attrib->events; l; l = l->next) {
714                 struct event *evt = l->data;
715
716                 if (evt->notify)
717                         evt->notify(evt->user_data);
718
719                 g_free(evt);
720         }
721
722         g_slist_free(attrib->events);
723         attrib->events = NULL;
724
725         return TRUE;
726 }