Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / android / scpp.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2012  Nordic Semiconductor Inc.
6  *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
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 <stdbool.h>
30 #include <errno.h>
31
32 #include <glib.h>
33
34 #include "src/log.h"
35
36 #include "lib/bluetooth.h"
37 #include "lib/sdp.h"
38 #include "lib/uuid.h"
39
40 #include "src/shared/util.h"
41 #include "src/shared/queue.h"
42
43 #include "attrib/att.h"
44 #include "attrib/gattrib.h"
45 #include "attrib/gatt.h"
46
47 #include "android/scpp.h"
48
49 #define SCAN_INTERVAL_WIN_UUID          0x2A4F
50 #define SCAN_REFRESH_UUID               0x2A31
51
52 #define SCAN_INTERVAL           0x0060
53 #define SCAN_WINDOW             0x0030
54 #define SERVER_REQUIRES_REFRESH 0x00
55
56 struct bt_scpp {
57         int ref_count;
58         GAttrib *attrib;
59         struct gatt_primary *primary;
60         uint16_t interval;
61         uint16_t window;
62         uint16_t iwhandle;
63         uint16_t refresh_handle;
64         guint refresh_cb_id;
65         struct queue *gatt_op;
66 };
67
68 static void discover_char(struct bt_scpp *scpp, GAttrib *attrib,
69                                                 uint16_t start, uint16_t end,
70                                                 bt_uuid_t *uuid, gatt_cb_t func,
71                                                 gpointer user_data)
72 {
73         unsigned int id;
74
75         id = gatt_discover_char(attrib, start, end, uuid, func, user_data);
76
77         if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
78                 return;
79
80         error("scpp: Could not discover characteristic");
81         g_attrib_cancel(attrib, id);
82 }
83
84 static void discover_desc(struct bt_scpp *scpp, GAttrib *attrib,
85                                 uint16_t start, uint16_t end, bt_uuid_t *uuid,
86                                 gatt_cb_t func, gpointer user_data)
87 {
88         unsigned int id;
89
90         id = gatt_discover_desc(attrib, start, end, uuid, func, user_data);
91
92         if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
93                 return;
94
95         error("scpp: Could not discover descriptor");
96         g_attrib_cancel(attrib, id);
97 }
98
99 static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
100                                         const uint8_t *value, size_t vlen,
101                                         GAttribResultFunc func,
102                                         gpointer user_data)
103 {
104         unsigned int id;
105
106         id = gatt_write_char(attrib, handle, value, vlen, func, user_data);
107
108         if (queue_push_head(scan->gatt_op, UINT_TO_PTR(id)))
109                 return;
110
111         error("scpp: Could not read char");
112         g_attrib_cancel(attrib, id);
113 }
114
115 static void scpp_free(struct bt_scpp *scan)
116 {
117         bt_scpp_detach(scan);
118
119         g_free(scan->primary);
120         queue_destroy(scan->gatt_op, NULL); /* cleared in bt_scpp_detach */
121         g_free(scan);
122 }
123
124 struct bt_scpp *bt_scpp_new(void *primary)
125 {
126         struct bt_scpp *scan;
127
128         scan = g_try_new0(struct bt_scpp, 1);
129         if (!scan)
130                 return NULL;
131
132         scan->interval = SCAN_INTERVAL;
133         scan->window = SCAN_WINDOW;
134
135         scan->gatt_op = queue_new();
136         if (!scan->gatt_op) {
137                 scpp_free(scan);
138                 return NULL;
139         }
140
141         if (primary)
142                 scan->primary = g_memdup(primary, sizeof(*scan->primary));
143
144         return bt_scpp_ref(scan);
145 }
146
147 struct bt_scpp *bt_scpp_ref(struct bt_scpp *scan)
148 {
149         if (!scan)
150                 return NULL;
151
152         __sync_fetch_and_add(&scan->ref_count, 1);
153
154         return scan;
155 }
156
157 void bt_scpp_unref(struct bt_scpp *scan)
158 {
159         if (!scan)
160                 return;
161
162         if (__sync_sub_and_fetch(&scan->ref_count, 1))
163                 return;
164
165         scpp_free(scan);
166 }
167
168 static void write_scan_params(GAttrib *attrib, uint16_t handle,
169                                         uint16_t interval, uint16_t window)
170 {
171         uint8_t value[4];
172
173         put_le16(interval, &value[0]);
174         put_le16(window, &value[2]);
175
176         gatt_write_cmd(attrib, handle, value, sizeof(value), NULL, NULL);
177 }
178
179 static void refresh_value_cb(const uint8_t *pdu, uint16_t len,
180                                                 gpointer user_data)
181 {
182         struct bt_scpp *scan = user_data;
183
184         DBG("Server requires refresh: %d", pdu[3]);
185
186         if (pdu[3] == SERVER_REQUIRES_REFRESH)
187                 write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
188                                                                 scan->window);
189 }
190
191 static void ccc_written_cb(guint8 status, const guint8 *pdu,
192                                         guint16 plen, gpointer user_data)
193 {
194         struct bt_scpp *scan = user_data;
195
196         if (status != 0) {
197                 error("Write Scan Refresh CCC failed: %s",
198                                                 att_ecode2str(status));
199                 return;
200         }
201
202         DBG("Scan Refresh: notification enabled");
203
204         scan->refresh_cb_id = g_attrib_register(scan->attrib,
205                                 ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
206                                 refresh_value_cb, scan, NULL);
207 }
208
209 static void write_ccc(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
210                                                                 void *user_data)
211 {
212         uint8_t value[2];
213
214         put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
215
216         write_char(scan, attrib, handle, value, sizeof(value), ccc_written_cb,
217                                                                 user_data);
218 }
219
220 static void discover_descriptor_cb(uint8_t status, GSList *descs,
221                                                                 void *user_data)
222 {
223         struct bt_scpp *scan = user_data;
224         struct gatt_desc *desc;
225
226         if (status != 0) {
227                 error("Discover descriptors failed: %s", att_ecode2str(status));
228                 return;
229         }
230
231         /* There will be only one descriptor on list and it will be CCC */
232         desc = descs->data;
233
234         write_ccc(scan, scan->attrib, desc->handle, scan);
235 }
236
237 static void refresh_discovered_cb(uint8_t status, GSList *chars,
238                                                                 void *user_data)
239 {
240         struct bt_scpp *scan = user_data;
241         struct gatt_char *chr;
242         uint16_t start, end;
243         bt_uuid_t uuid;
244
245         if (status) {
246                 error("Scan Refresh %s", att_ecode2str(status));
247                 return;
248         }
249
250         if (!chars) {
251                 DBG("Scan Refresh not supported");
252                 return;
253         }
254
255         chr = chars->data;
256
257         DBG("Scan Refresh handle: 0x%04x", chr->value_handle);
258
259         start = chr->value_handle + 1;
260         end = scan->primary->range.end;
261
262         if (start > end)
263                 return;
264
265         scan->refresh_handle = chr->value_handle;
266
267         bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
268
269         discover_desc(scan, scan->attrib, start, end, &uuid,
270                                         discover_descriptor_cb, user_data);
271 }
272
273 static void iwin_discovered_cb(uint8_t status, GSList *chars, void *user_data)
274 {
275         struct bt_scpp *scan = user_data;
276         struct gatt_char *chr;
277
278         if (status) {
279                 error("Discover Scan Interval Window: %s",
280                                                 att_ecode2str(status));
281                 return;
282         }
283
284         chr = chars->data;
285         scan->iwhandle = chr->value_handle;
286
287         DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
288
289         write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
290                                                                 scan->window);
291 }
292
293 bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
294 {
295         bt_uuid_t iwin_uuid, refresh_uuid;
296
297         if (!scan || scan->attrib || !scan->primary)
298                 return false;
299
300         scan->attrib = g_attrib_ref(attrib);
301
302         if (scan->iwhandle)
303                 write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
304                                                                 scan->window);
305         else {
306                 bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
307                 discover_char(scan, scan->attrib, scan->primary->range.start,
308                                         scan->primary->range.end, &iwin_uuid,
309                                         iwin_discovered_cb, scan);
310         }
311
312         if (scan->refresh_handle)
313                 scan->refresh_cb_id = g_attrib_register(scan->attrib,
314                                 ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
315                                 refresh_value_cb, scan, NULL);
316         else {
317                 bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
318                 discover_char(scan, scan->attrib, scan->primary->range.start,
319                                         scan->primary->range.end, &refresh_uuid,
320                                         refresh_discovered_cb, scan);
321         }
322
323         return true;
324 }
325
326 static void cancel_gatt_req(void *data, void *user_data)
327 {
328         unsigned int id = PTR_TO_UINT(data);
329         struct bt_scpp *scan = user_data;
330
331         g_attrib_cancel(scan->attrib, id);
332 }
333
334 void bt_scpp_detach(struct bt_scpp *scan)
335 {
336         if (!scan || !scan->attrib)
337                 return;
338
339         if (scan->refresh_cb_id > 0) {
340                 g_attrib_unregister(scan->attrib, scan->refresh_cb_id);
341                 scan->refresh_cb_id = 0;
342         }
343
344         queue_foreach(scan->gatt_op, cancel_gatt_req, scan);
345         g_attrib_unref(scan->attrib);
346         scan->attrib = NULL;
347 }
348
349 bool bt_scpp_set_interval(struct bt_scpp *scan, uint16_t value)
350 {
351         if (!scan)
352                 return false;
353
354         /* TODO: Check valid range */
355
356         scan->interval = value;
357
358         return true;
359 }
360
361 bool bt_scpp_set_window(struct bt_scpp *scan, uint16_t value)
362 {
363         if (!scan)
364                 return false;
365
366         /* TODO: Check valid range */
367
368         scan->window = value;
369
370         return true;
371 }