Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / peripheral / gatt.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2015  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/epoll.h>
33
34 #include "lib/bluetooth.h"
35 #include "lib/l2cap.h"
36 #include "lib/uuid.h"
37 #include "src/shared/mainloop.h"
38 #include "src/shared/util.h"
39 #include "src/shared/queue.h"
40 #include "src/shared/att.h"
41 #include "src/shared/gatt-db.h"
42 #include "src/shared/gatt-server.h"
43 #include "src/shared/gatt-client.h"
44 #include "peripheral/gatt.h"
45
46 #define ATT_CID 4
47
48 #define UUID_GAP 0x1800
49
50 struct gatt_conn {
51         struct bt_att *att;
52         struct bt_gatt_server *gatt;
53         struct bt_gatt_client *client;
54 };
55
56 static int att_fd = -1;
57 static struct queue *conn_list = NULL;
58 static struct gatt_db *gatt_db = NULL;
59 static struct gatt_db *gatt_cache = NULL;
60
61 static uint8_t static_addr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
62 static uint8_t dev_name[20];
63 static uint8_t dev_name_len = 0;
64
65 void gatt_set_static_address(uint8_t addr[6])
66 {
67         memcpy(static_addr, addr, sizeof(static_addr));
68 }
69
70 void gatt_set_device_name(uint8_t name[20], uint8_t len)
71 {
72         memcpy(dev_name, name, sizeof(dev_name));
73         dev_name_len = len;
74 }
75
76 static void gatt_conn_destroy(void *data)
77 {
78         struct gatt_conn *conn = data;
79
80         bt_gatt_client_unref(conn->client);
81         bt_gatt_server_unref(conn->gatt);
82         bt_att_unref(conn->att);
83
84         free(conn);
85 }
86
87 static void gatt_conn_disconnect(int err, void *user_data)
88 {
89         struct gatt_conn *conn = user_data;
90
91         printf("Device disconnected: %s\n", strerror(err));
92
93         queue_remove(conn_list, conn);
94         gatt_conn_destroy(conn);
95 }
96
97 static void client_ready_callback(bool success, uint8_t att_ecode,
98                                                         void *user_data)
99 {
100         printf("GATT client discovery complete\n");
101 }
102
103 static void client_service_changed_callback(uint16_t start_handle,
104                                                 uint16_t end_handle,
105                                                 void *user_data)
106 {
107         printf("GATT client service changed notification\n");
108 }
109
110 static struct gatt_conn *gatt_conn_new(int fd)
111 {
112         struct gatt_conn *conn;
113         uint16_t mtu = 0;
114
115         conn = new0(struct gatt_conn, 1);
116         if (!conn)
117                 return NULL;
118
119         conn->att = bt_att_new(fd, false);
120         if (!conn->att) {
121                 fprintf(stderr, "Failed to initialze ATT transport layer\n");
122                 free(conn);
123                 return NULL;
124         }
125
126         bt_att_set_close_on_unref(conn->att, true);
127         bt_att_register_disconnect(conn->att, gatt_conn_disconnect, conn, NULL);
128
129         bt_att_set_security(conn->att, BT_SECURITY_MEDIUM);
130
131         conn->gatt = bt_gatt_server_new(gatt_db, conn->att, mtu);
132         if (!conn->gatt) {
133                 fprintf(stderr, "Failed to create GATT server\n");
134                 bt_att_unref(conn->att);
135                 free(conn);
136                 return NULL;
137         }
138
139         conn->client = bt_gatt_client_new(gatt_cache, conn->att, mtu);
140         if (!conn->gatt) {
141                 fprintf(stderr, "Failed to create GATT client\n");
142                 bt_gatt_server_unref(conn->gatt);
143                 bt_att_unref(conn->att);
144                 free(conn);
145                 return NULL;
146         }
147
148         bt_gatt_client_set_ready_handler(conn->client,
149                                 client_ready_callback, conn, NULL);
150         bt_gatt_client_set_service_changed(conn->client,
151                                 client_service_changed_callback, conn, NULL);
152
153         return conn;
154 }
155
156 static void att_conn_callback(int fd, uint32_t events, void *user_data)
157 {
158         struct gatt_conn *conn;
159         struct sockaddr_l2 addr;
160         socklen_t addrlen;
161         int new_fd;
162
163         if (events & (EPOLLERR | EPOLLHUP)) {
164                 mainloop_remove_fd(fd);
165                 return;
166         }
167
168         memset(&addr, 0, sizeof(addr));
169         addrlen = sizeof(addr);
170
171         new_fd = accept(att_fd, (struct sockaddr *) &addr, &addrlen);
172         if (new_fd < 0) {
173                 fprintf(stderr, "Failed to accept new ATT connection: %m\n");
174                 return;
175         }
176
177         conn = gatt_conn_new(new_fd);
178         if (!conn) {
179                 fprintf(stderr, "Failed to create GATT connection\n");
180                 close(new_fd);
181                 return;
182         }
183
184         if (!queue_push_tail(conn_list, conn)) {
185                 fprintf(stderr, "Failed to add GATT connection\n");
186                 gatt_conn_destroy(conn);
187                 close(new_fd);
188         }
189
190         printf("New device connected\n");
191 }
192
193 static void gap_device_name_read(struct gatt_db_attribute *attrib,
194                                         unsigned int id, uint16_t offset,
195                                         uint8_t opcode, struct bt_att *att,
196                                         void *user_data)
197 {
198         uint8_t error;
199         const uint8_t *value;
200         size_t len;
201
202         if (offset > dev_name_len) {
203                 error = BT_ATT_ERROR_INVALID_OFFSET;
204                 value = NULL;
205                 len = dev_name_len;
206         } else {
207                 error = 0;
208                 len = dev_name_len - offset;
209                 value = len ? &dev_name[offset] : NULL;
210         }
211
212         gatt_db_attribute_read_result(attrib, id, error, value, len);
213 }
214
215 static void populate_gap_service(struct gatt_db *db)
216 {
217         struct gatt_db_attribute *service;
218         bt_uuid_t uuid;
219
220         bt_uuid16_create(&uuid, UUID_GAP);
221         service = gatt_db_add_service(db, &uuid, true, 6);
222
223         bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
224         gatt_db_service_add_characteristic(service, &uuid,
225                                         BT_ATT_PERM_READ,
226                                         BT_GATT_CHRC_PROP_READ,
227                                         gap_device_name_read, NULL, NULL);
228
229         gatt_db_service_set_active(service, true);
230 }
231
232 static void populate_devinfo_service(struct gatt_db *db)
233 {
234         struct gatt_db_attribute *service;
235         bt_uuid_t uuid;
236
237         bt_uuid16_create(&uuid, 0x180a);
238         service = gatt_db_add_service(db, &uuid, true, 17);
239
240         gatt_db_service_set_active(service, true);
241 }
242
243 void gatt_server_start(void)
244 {
245         struct sockaddr_l2 addr;
246
247         if (att_fd >= 0)
248                 return;
249
250         att_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_CLOEXEC,
251                                                         BTPROTO_L2CAP);
252         if (att_fd < 0) {
253                 fprintf(stderr, "Failed to create ATT server socket: %m\n");
254                 return;
255         }
256
257         memset(&addr, 0, sizeof(addr));
258         addr.l2_family = AF_BLUETOOTH;
259         addr.l2_cid = htobs(ATT_CID);
260         memcpy(&addr.l2_bdaddr, static_addr, 6);
261         addr.l2_bdaddr_type = BDADDR_LE_RANDOM;
262
263         if (bind(att_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
264                 fprintf(stderr, "Failed to bind ATT server socket: %m\n");
265                 close(att_fd);
266                 att_fd = -1;
267                 return;
268         }
269
270         if (listen(att_fd, 1) < 0) {
271                 fprintf(stderr, "Failed to listen on ATT server socket: %m\n");
272                 close(att_fd);
273                 att_fd = -1;
274                 return;
275         }
276
277         gatt_db = gatt_db_new();
278         if (!gatt_db) {
279                 close(att_fd);
280                 att_fd = -1;
281                 return;
282         }
283
284         populate_gap_service(gatt_db);
285         populate_devinfo_service(gatt_db);
286
287         gatt_cache = gatt_db_new();
288
289         conn_list = queue_new();
290         if (!conn_list) {
291                 gatt_db_unref(gatt_db);
292                 gatt_db = NULL;
293                 close(att_fd);
294                 att_fd = -1;
295                 return;
296         }
297
298         mainloop_add_fd(att_fd, EPOLLIN, att_conn_callback, NULL, NULL);
299 }
300
301 void gatt_server_stop(void)
302 {
303         if (att_fd < 0)
304                 return;
305
306         mainloop_remove_fd(att_fd);
307
308         queue_destroy(conn_list, gatt_conn_destroy);
309
310         gatt_db_unref(gatt_cache);
311         gatt_cache = NULL;
312
313         gatt_db_unref(gatt_db);
314         gatt_db = NULL;
315
316         close(att_fd);
317         att_fd = -1;
318 }