Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / profiles / scanparam / scan.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 "lib/bluetooth.h"
33 #include "lib/sdp.h"
34 #include "lib/uuid.h"
35
36 #include "src/log.h"
37 #include "src/plugin.h"
38 #include "src/adapter.h"
39 #include "src/device.h"
40 #include "src/profile.h"
41 #include "src/service.h"
42 #include "src/shared/util.h"
43 #include "src/shared/att.h"
44 #include "src/shared/queue.h"
45 #include "src/shared/gatt-db.h"
46 #include "src/shared/gatt-client.h"
47 #include "attrib/att.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 scan {
57         struct btd_device *device;
58         struct gatt_db *db;
59         struct bt_gatt_client *client;
60         struct gatt_db_attribute *attr;
61         uint16_t iwhandle;
62         guint refresh_cb_id;
63 };
64
65 static GSList *devices;
66
67 static void scan_free(struct scan *scan)
68 {
69         bt_gatt_client_unregister_notify(scan->client, scan->refresh_cb_id);
70         gatt_db_unref(scan->db);
71         bt_gatt_client_unref(scan->client);
72         btd_device_unref(scan->device);
73         g_free(scan);
74 }
75
76 static int cmp_device(gconstpointer a, gconstpointer b)
77 {
78         const struct scan *scan = a;
79         const struct btd_device *device = b;
80
81         return scan->device == device ? 0 : -1;
82 }
83
84 static void write_scan_params(struct scan *scan)
85 {
86         uint8_t value[4];
87
88         put_le16(SCAN_INTERVAL, &value[0]);
89         put_le16(SCAN_WINDOW, &value[2]);
90
91         bt_gatt_client_write_without_response(scan->client, scan->iwhandle,
92                                                 false, value, sizeof(value));
93 }
94
95 static void refresh_value_cb(uint16_t value_handle, const uint8_t *value,
96                                         uint16_t length, void *user_data)
97 {
98         struct scan *scan = user_data;
99
100         DBG("Server requires refresh: %d", value[3]);
101
102         if (value[3] == SERVER_REQUIRES_REFRESH)
103                 write_scan_params(scan);
104 }
105
106 static void refresh_ccc_written_cb(uint16_t att_ecode, void *user_data)
107 {
108         if (att_ecode != 0) {
109                 error("Scan Refresh: notifications not enabled %s",
110                                                 att_ecode2str(att_ecode));
111                 return;
112         }
113
114         DBG("Scan Refresh: notification enabled");
115 }
116
117 static void handle_refresh(struct scan *scan, uint16_t value_handle)
118 {
119         DBG("Scan Refresh handle: 0x%04x", value_handle);
120
121         scan->refresh_cb_id = bt_gatt_client_register_notify(scan->client,
122                                         value_handle, refresh_ccc_written_cb,
123                                                 refresh_value_cb, scan, NULL);
124 }
125
126 static void handle_iwin(struct scan *scan, uint16_t value_handle)
127 {
128         scan->iwhandle = value_handle;
129
130         DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
131
132         write_scan_params(scan);
133 }
134
135 static void handle_characteristic(struct gatt_db_attribute *attr,
136                                                                 void *user_data)
137 {
138         struct scan *scan = user_data;
139         uint16_t value_handle;
140         bt_uuid_t uuid, scan_interval_wind_uuid, scan_refresh_uuid;
141
142         if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL,
143                                                                 &uuid)) {
144                 error("Failed to obtain characteristic data");
145                 return;
146         }
147
148         bt_uuid16_create(&scan_interval_wind_uuid, SCAN_INTERVAL_WIN_UUID);
149         bt_uuid16_create(&scan_refresh_uuid, SCAN_REFRESH_UUID);
150
151         if (bt_uuid_cmp(&scan_interval_wind_uuid, &uuid) == 0)
152                 handle_iwin(scan, value_handle);
153         else if (bt_uuid_cmp(&scan_refresh_uuid, &uuid) == 0)
154                 handle_refresh(scan, value_handle);
155         else {
156                 char uuid_str[MAX_LEN_UUID_STR];
157
158                 bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
159                 DBG("Unsupported characteristic: %s", uuid_str);
160         }
161 }
162
163 static void foreach_scan_param_service(struct gatt_db_attribute *attr,
164                                                                 void *user_data)
165 {
166         struct scan *scan = user_data;
167
168         if (scan->attr) {
169                 error("More than one scan params service exists for this "
170                                                                 "device");
171                 return;
172         }
173
174         scan->attr = attr;
175         gatt_db_service_foreach_char(scan->attr, handle_characteristic, scan);
176 }
177
178 static int scan_param_accept(struct btd_service *service)
179 {
180         struct btd_device *device = btd_service_get_device(service);
181         struct gatt_db *db = btd_device_get_gatt_db(device);
182         struct bt_gatt_client *client = btd_device_get_gatt_client(device);
183         bt_uuid_t scan_parameters_uuid;
184         struct scan *scan;
185         GSList *l;
186         char addr[18];
187
188         ba2str(device_get_address(device), addr);
189         DBG("Scan Parameters Client Driver profile accept (%s)", addr);
190
191         l = g_slist_find_custom(devices, device, cmp_device);
192         if (!l) {
193                 error("Scan Parameters service not handled by profile");
194                 return -1;
195         }
196
197         scan = l->data;
198
199         /* Clean-up any old client/db and acquire the new ones */
200         scan->attr = NULL;
201         gatt_db_unref(scan->db);
202         bt_gatt_client_unref(scan->client);
203
204
205         scan->db = gatt_db_ref(db);
206         scan->client = bt_gatt_client_ref(client);
207
208         bt_string_to_uuid(&scan_parameters_uuid, SCAN_PARAMETERS_UUID);
209         gatt_db_foreach_service(db, &scan_parameters_uuid,
210                                         foreach_scan_param_service, scan);
211
212         return 0;
213 }
214
215 static void scan_param_remove(struct btd_service *service)
216 {
217         struct btd_device *device = btd_service_get_device(service);
218         struct scan *scan;
219         GSList *l;
220         char addr[18];
221
222         ba2str(device_get_address(device), addr);
223         DBG("GAP profile remove (%s)", addr);
224
225         l = g_slist_find_custom(devices, device, cmp_device);
226         if (!l) {
227                 error("GAP service not handled by profile");
228                 return;
229         }
230
231         scan = l->data;
232
233         devices = g_slist_remove(devices, scan);
234         scan_free(scan);
235 }
236
237 static int scan_param_probe(struct btd_service *service)
238 {
239         struct btd_device *device = btd_service_get_device(service);
240         struct scan *scan;
241         GSList *l;
242         char addr[18];
243
244         ba2str(device_get_address(device), addr);
245         DBG("Scan Parameters Client Driver profile probe (%s)", addr);
246
247         /* Ignore, if we were probed for this device already */
248         l = g_slist_find_custom(devices, device, cmp_device);
249         if (l) {
250                 error("Profile probed twice for the same device!");
251                 return -1;
252         }
253
254         scan = g_new0(struct scan, 1);
255         if (!scan)
256                 return -1;
257
258         scan->device = btd_device_ref(device);
259         devices = g_slist_append(devices, scan);
260         return 0;
261 }
262
263 static struct btd_profile scan_profile = {
264         .name = "Scan Parameters Client Driver",
265         .remote_uuid = SCAN_PARAMETERS_UUID,
266         .device_probe = scan_param_probe,
267         .device_remove = scan_param_remove,
268         .accept = scan_param_accept,
269 };
270
271 static int scan_param_init(void)
272 {
273         return btd_profile_register(&scan_profile);
274 }
275
276 static void scan_param_exit(void)
277 {
278         btd_profile_unregister(&scan_profile);
279 }
280
281 BLUETOOTH_PLUGIN_DEFINE(scanparam, VERSION,
282                         BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
283                         scan_param_init, scan_param_exit)