Upgrade bluez5_37 :Merge the code from private
[platform/upstream/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 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #include "lib/bluetooth.h"
37
38 #include "btio/btio.h"
39 #include "src/log.h"
40 #include "src/shared/util.h"
41 #include "src/shared/att.h"
42 #include "src/shared/queue.h"
43 #include "attrib/gattrib.h"
44
45 struct _GAttrib {
46         int ref_count;
47         struct bt_att *att;
48         GIOChannel *io;
49         GDestroyNotify destroy;
50         gpointer destroy_user_data;
51         struct queue *callbacks;
52         uint8_t *buf;
53         int buflen;
54         struct queue *track_ids;
55 };
56
57 struct id_pair {
58         unsigned int org_id;
59         unsigned int pend_id;
60 };
61
62 struct attrib_callbacks {
63         struct id_pair *id;
64         GAttribResultFunc result_func;
65         GAttribNotifyFunc notify_func;
66         GDestroyNotify destroy_func;
67         gpointer user_data;
68         GAttrib *parent;
69         uint16_t notify_handle;
70 };
71
72 static bool find_with_org_id(const void *data, const void *user_data)
73 {
74         const struct id_pair *p = data;
75         unsigned int orig_id = PTR_TO_UINT(user_data);
76
77         return (p->org_id == orig_id);
78 }
79
80 static struct id_pair *store_id(GAttrib *attrib, unsigned int org_id,
81                                                         unsigned int pend_id)
82 {
83         struct id_pair *t;
84
85         t = new0(struct id_pair, 1);
86         if (!t)
87                 return NULL;
88
89         t->org_id = org_id;
90         t->pend_id = pend_id;
91
92         if (queue_push_tail(attrib->track_ids, t))
93                 return t;
94
95         return NULL;
96 }
97
98 GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed)
99 {
100         gint fd;
101         GAttrib *attr;
102
103         if (!io)
104                 return NULL;
105
106         fd = g_io_channel_unix_get_fd(io);
107         attr = new0(GAttrib, 1);
108         if (!attr)
109                 return NULL;
110
111         g_io_channel_ref(io);
112         attr->io = io;
113
114         attr->att = bt_att_new(fd, ext_signed);
115         if (!attr->att)
116                 goto fail;
117
118         bt_att_set_close_on_unref(attr->att, true);
119         g_io_channel_set_close_on_unref(io, FALSE);
120
121         if (!bt_att_set_mtu(attr->att, mtu))
122                 goto fail;
123
124         attr->buf = malloc0(mtu);
125         attr->buflen = mtu;
126         if (!attr->buf)
127                 goto fail;
128
129         attr->callbacks = queue_new();
130         if (!attr->callbacks)
131                 goto fail;
132
133         attr->track_ids = queue_new();
134         if (!attr->track_ids)
135                 goto fail;
136
137         return g_attrib_ref(attr);
138
139 fail:
140         free(attr->buf);
141         bt_att_unref(attr->att);
142         g_io_channel_unref(io);
143         free(attr);
144         return NULL;
145 }
146
147 GAttrib *g_attrib_ref(GAttrib *attrib)
148 {
149         if (!attrib)
150                 return NULL;
151
152         __sync_fetch_and_add(&attrib->ref_count, 1);
153
154         DBG("%p: g_attrib_ref=%d ", attrib, attrib->ref_count);
155
156         return attrib;
157 }
158
159 static void attrib_callbacks_destroy(void *data)
160 {
161         struct attrib_callbacks *cb = data;
162
163         if (cb->destroy_func)
164                 cb->destroy_func(cb->user_data);
165
166         if (queue_remove(cb->parent->track_ids, cb->id))
167                 free(cb->id);
168
169         free(data);
170 }
171
172 static void attrib_callbacks_remove(void *data)
173 {
174         struct attrib_callbacks *cb = data;
175
176         if (!data || !queue_remove(cb->parent->callbacks, data))
177                 return;
178
179         attrib_callbacks_destroy(data);
180 }
181
182 void g_attrib_unref(GAttrib *attrib)
183 {
184         if (!attrib)
185                 return;
186
187         DBG("%p: g_attrib_unref=%d ", attrib, attrib->ref_count - 1);
188
189         if (__sync_sub_and_fetch(&attrib->ref_count, 1))
190                 return;
191
192         if (attrib->destroy)
193                 attrib->destroy(attrib->destroy_user_data);
194
195         bt_att_unref(attrib->att);
196
197         queue_destroy(attrib->callbacks, attrib_callbacks_destroy);
198         queue_destroy(attrib->track_ids, free);
199
200         free(attrib->buf);
201
202         g_io_channel_unref(attrib->io);
203
204         free(attrib);
205 }
206
207 GIOChannel *g_attrib_get_channel(GAttrib *attrib)
208 {
209         if (!attrib)
210                 return NULL;
211
212         return attrib->io;
213 }
214
215 struct bt_att *g_attrib_get_att(GAttrib *attrib)
216 {
217         if (!attrib)
218                 return NULL;
219
220         return attrib->att;
221 }
222
223 gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy,
224                                                         gpointer user_data)
225 {
226         if (!attrib)
227                 return FALSE;
228
229         attrib->destroy = destroy;
230         attrib->destroy_user_data = user_data;
231
232         return TRUE;
233 }
234
235
236 static uint8_t *construct_full_pdu(uint8_t opcode, const void *pdu,
237                                                                 uint16_t length)
238 {
239         uint8_t *buf = malloc0(length + 1);
240
241         if (!buf)
242                 return NULL;
243
244         buf[0] = opcode;
245         memcpy(buf + 1, pdu, length);
246
247         return buf;
248 }
249
250 static void attrib_callback_result(uint8_t opcode, const void *pdu,
251                                         uint16_t length, void *user_data)
252 {
253         uint8_t *buf;
254         struct attrib_callbacks *cb = user_data;
255         guint8 status = 0;
256
257         if (!cb)
258                 return;
259
260         buf = construct_full_pdu(opcode, pdu, length);
261         if (!buf)
262                 return;
263
264         if (opcode == BT_ATT_OP_ERROR_RSP) {
265                 /* Error code is the third byte of the PDU data */
266                 if (length < 4)
267                         status = BT_ATT_ERROR_UNLIKELY;
268                 else
269                         status = ((guint8 *)pdu)[3];
270         }
271
272         if (cb->result_func)
273                 cb->result_func(status, buf, length + 1, cb->user_data);
274
275         free(buf);
276 }
277
278 static void attrib_callback_notify(uint8_t opcode, const void *pdu,
279                                         uint16_t length, void *user_data)
280 {
281         uint8_t *buf;
282         struct attrib_callbacks *cb = user_data;
283
284         if (!cb || !cb->notify_func)
285                 return;
286
287         if (cb->notify_handle != GATTRIB_ALL_HANDLES && length < 2)
288                 return;
289
290         if (cb->notify_handle != GATTRIB_ALL_HANDLES &&
291                                         cb->notify_handle != get_le16(pdu))
292                 return;
293
294         buf = construct_full_pdu(opcode, pdu, length);
295         if (!buf)
296                 return;
297
298         cb->notify_func(buf, length + 1, cb->user_data);
299
300         free(buf);
301 }
302
303 guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
304                                 GAttribResultFunc func, gpointer user_data,
305                                 GDestroyNotify notify)
306 {
307         struct attrib_callbacks *cb = NULL;
308         bt_att_response_func_t response_cb = NULL;
309         bt_att_destroy_func_t destroy_cb = NULL;
310         unsigned int pend_id;
311
312         if (!attrib)
313                 return 0;
314
315         if (!pdu || !len)
316                 return 0;
317
318         if (func || notify) {
319                 cb = new0(struct attrib_callbacks, 1);
320                 if (!cb)
321                         return 0;
322                 cb->result_func = func;
323                 cb->user_data = user_data;
324                 cb->destroy_func = notify;
325                 cb->parent = attrib;
326                 queue_push_head(attrib->callbacks, cb);
327                 response_cb = attrib_callback_result;
328                 destroy_cb = attrib_callbacks_remove;
329
330         }
331
332         pend_id = bt_att_send(attrib->att, pdu[0], (void *) pdu + 1, len - 1,
333                                                 response_cb, cb, destroy_cb);
334
335         /*
336          * We store here pair as it is easier to handle it in response and in
337          * case where user request us to use specific id request - see below.
338          */
339         if (id == 0)
340                 id = pend_id;
341
342         /*
343          * If user what us to use given id, lets keep track on that so we give
344          * user a possibility to cancel ongoing request.
345          */
346         if (cb)
347                 cb->id = store_id(attrib, id, pend_id);
348
349         return id;
350 }
351
352 gboolean g_attrib_cancel(GAttrib *attrib, guint id)
353 {
354         struct id_pair *p;
355
356         if (!attrib)
357                 return FALSE;
358
359         /*
360          * If request belongs to gattrib and is not yet done it has to be on
361          * the tracking id queue
362          *
363          * FIXME: It can happen that on the queue there is id_pair with
364          * given id which was provided by the user. In the same time it might
365          * happen that other attrib user got dynamic allocated req_id with same
366          * value as the one provided by the other user.
367          * In such case there are two clients having same request id and in
368          * this point of time we don't know which one calls cancel. For
369          * now we cancel request in which id was specified by the user.
370          */
371         p = queue_remove_if(attrib->track_ids, find_with_org_id,
372                                                         UINT_TO_PTR(id));
373         if (!p)
374                 return FALSE;
375
376         id = p->pend_id;
377         free(p);
378
379         return bt_att_cancel(attrib->att, id);
380 }
381
382 static void cancel_request(void *data, void *user_data)
383 {
384         struct id_pair *p = data;
385         GAttrib *attrib = user_data;
386
387         bt_att_cancel(attrib->att, p->pend_id);
388 }
389
390 gboolean g_attrib_cancel_all(GAttrib *attrib)
391 {
392         if (!attrib)
393                 return FALSE;
394
395         /* Cancel only request which belongs to gattrib */
396         queue_foreach(attrib->track_ids, cancel_request, attrib);
397         queue_remove_all(attrib->track_ids, NULL, NULL, free);
398
399         return TRUE;
400 }
401
402 guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
403                                 GAttribNotifyFunc func, gpointer user_data,
404                                 GDestroyNotify notify)
405 {
406         struct attrib_callbacks *cb = NULL;
407
408         if (!attrib)
409                 return 0;
410
411         if (func || notify) {
412                 cb = new0(struct attrib_callbacks, 1);
413                 if (!cb)
414                         return 0;
415                 cb->notify_func = func;
416                 cb->notify_handle = handle;
417                 cb->user_data = user_data;
418                 cb->destroy_func = notify;
419                 cb->parent = attrib;
420                 queue_push_head(attrib->callbacks, cb);
421         }
422
423         if (opcode == GATTRIB_ALL_REQS)
424                 opcode = BT_ATT_ALL_REQUESTS;
425
426         return bt_att_register(attrib->att, opcode, attrib_callback_notify,
427                                                 cb, attrib_callbacks_remove);
428 }
429
430 uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
431 {
432         uint16_t mtu;
433
434         if (!attrib || !len)
435                 return NULL;
436
437         mtu = bt_att_get_mtu(attrib->att);
438
439         /*
440          * Clients of this expect a buffer to use.
441          *
442          * Pdu encoding in shared/att verifies if whole buffer fits the mtu,
443          * thus we should set the buflen also when mtu is reduced. But we
444          * need to reallocate the buffer only if mtu is larger.
445          */
446         if (mtu > attrib->buflen)
447                 attrib->buf = g_realloc(attrib->buf, mtu);
448
449         attrib->buflen = mtu;
450         *len = attrib->buflen;
451         return attrib->buf;
452 }
453
454 gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
455 {
456         if (!attrib)
457                 return FALSE;
458
459         /*
460          * Clients of this expect a buffer to use.
461          *
462          * Pdu encoding in sharred/att verifies if whole buffer fits the mtu,
463          * thus we should set the buflen also when mtu is reduced. But we
464          * need to reallocate the buffer only if mtu is larger.
465          */
466         if (mtu > attrib->buflen)
467                 attrib->buf = g_realloc(attrib->buf, mtu);
468
469         attrib->buflen = mtu;
470
471         return bt_att_set_mtu(attrib->att, mtu);
472 }
473
474 gboolean g_attrib_unregister(GAttrib *attrib, guint id)
475 {
476         if (!attrib)
477                 return FALSE;
478
479         return bt_att_unregister(attrib->att, id);
480 }
481
482 gboolean g_attrib_unregister_all(GAttrib *attrib)
483 {
484         if (!attrib)
485                 return false;
486
487         return bt_att_unregister_all(attrib->att);
488 }