3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2010 Nokia Corporation
6 * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
30 #include <bluetooth/uuid.h>
38 #include "gatt-service.h"
41 #include "att-database.h"
42 #include "attrib-server.h"
44 /* FIXME: Not defined by SIG? UUID128? */
45 #define OPCODES_SUPPORTED_UUID 0xA001
46 #define BATTERY_STATE_SVC_UUID 0xA002
47 #define BATTERY_STATE_UUID 0xA003
48 #define THERM_HUMIDITY_SVC_UUID 0xA004
49 #define MANUFACTURER_SVC_UUID 0xA005
50 #define TEMPERATURE_UUID 0xA006
51 #define FMT_CELSIUS_UUID 0xA007
52 #define FMT_OUTSIDE_UUID 0xA008
53 #define RELATIVE_HUMIDITY_UUID 0xA009
54 #define FMT_PERCENT_UUID 0xA00A
55 #define BLUETOOTH_SIG_UUID 0xA00B
56 #define MANUFACTURER_NAME_UUID 0xA00C
57 #define MANUFACTURER_SERIAL_UUID 0xA00D
58 #define VENDOR_SPECIFIC_SVC_UUID 0xA00E
59 #define VENDOR_SPECIFIC_TYPE_UUID 0xA00F
60 #define FMT_KILOGRAM_UUID 0xA010
61 #define FMT_HANGING_UUID 0xA011
63 struct gatt_example_adapter {
64 struct btd_adapter *adapter;
68 static GSList *adapters = NULL;
70 static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
72 while (gadapter->sdp_handles != NULL) {
73 uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
75 attrib_free_sdp(handle);
76 gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
77 gadapter->sdp_handles->data);
80 if (gadapter->adapter != NULL)
81 btd_adapter_unref(gadapter->adapter);
86 static gint adapter_cmp(gconstpointer a, gconstpointer b)
88 const struct gatt_example_adapter *gatt_adapter = a;
89 const struct btd_adapter *adapter = b;
91 if (gatt_adapter->adapter == adapter)
97 static uint8_t battery_state_read(struct attribute *a,
98 struct btd_device *device, gpointer user_data)
100 struct btd_adapter *adapter = user_data;
104 attrib_db_update(adapter, a->handle, NULL, &value, sizeof(value), NULL);
109 static gboolean register_battery_service(struct btd_adapter *adapter)
113 bt_uuid16_create(&uuid, BATTERY_STATE_SVC_UUID);
115 return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
116 /* battery state characteristic */
117 GATT_OPT_CHR_UUID, BATTERY_STATE_UUID,
118 GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
119 ATT_CHAR_PROPER_NOTIFY,
120 GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
121 battery_state_read, adapter,
126 static void register_termometer_service(struct gatt_example_adapter *adapter,
127 const uint16_t manuf1[2], const uint16_t manuf2[2])
129 const char *desc_out_temp = "Outside Temperature";
130 const char *desc_out_hum = "Outside Relative Humidity";
131 uint16_t start_handle, h;
132 const int svc_size = 11;
138 bt_uuid16_create(&uuid, THERM_HUMIDITY_SVC_UUID);
139 start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
140 if (start_handle == 0) {
141 error("Not enough free handles to register service");
145 DBG("start_handle=0x%04x manuf1=0x%04x-0x%04x, manuf2=0x%04x-0x%04x",
146 start_handle, manuf1[0], manuf1[1], manuf2[0], manuf2[1]);
150 /* Thermometer: primary service definition */
151 bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
152 att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
153 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
156 bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
158 /* Thermometer: Include */
159 if (manuf1[0] && manuf1[1]) {
160 att_put_u16(manuf1[0], &atval[0]);
161 att_put_u16(manuf1[1], &atval[2]);
162 att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
163 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
164 ATT_NOT_PERMITTED, atval, 6);
167 /* Thermometer: Include */
168 if (manuf2[0] && manuf2[1]) {
169 att_put_u16(manuf2[0], &atval[0]);
170 att_put_u16(manuf2[1], &atval[2]);
171 att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
172 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
173 ATT_NOT_PERMITTED, atval, 6);
176 /* Thermometer: temperature characteristic */
177 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
178 atval[0] = ATT_CHAR_PROPER_READ;
179 att_put_u16(h + 1, &atval[1]);
180 att_put_u16(TEMPERATURE_UUID, &atval[3]);
181 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
184 /* Thermometer: temperature characteristic value */
185 bt_uuid16_create(&uuid, TEMPERATURE_UUID);
188 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
191 /* Thermometer: temperature characteristic format */
192 bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
195 att_put_u16(FMT_CELSIUS_UUID, &atval[2]);
197 att_put_u16(FMT_OUTSIDE_UUID, &atval[5]);
198 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
201 /* Thermometer: characteristic user description */
202 bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
203 len = strlen(desc_out_temp);
204 strncpy((char *) atval, desc_out_temp, len);
205 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
208 /* Thermometer: relative humidity characteristic */
209 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
210 atval[0] = ATT_CHAR_PROPER_READ;
211 att_put_u16(h + 1, &atval[1]);
212 att_put_u16(RELATIVE_HUMIDITY_UUID, &atval[3]);
213 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
216 /* Thermometer: relative humidity value */
217 bt_uuid16_create(&uuid, RELATIVE_HUMIDITY_UUID);
219 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
222 /* Thermometer: relative humidity characteristic format */
223 bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
226 att_put_u16(FMT_PERCENT_UUID, &atval[2]);
227 att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
228 att_put_u16(FMT_OUTSIDE_UUID, &atval[6]);
229 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
232 /* Thermometer: characteristic user description */
233 bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
234 len = strlen(desc_out_hum);
235 strncpy((char *) atval, desc_out_hum, len);
236 attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
239 g_assert(h - start_handle + 1 == svc_size);
241 /* Add an SDP record for the above service */
242 sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
245 adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
246 GUINT_TO_POINTER(sdp_handle));
249 static void register_manuf1_service(struct gatt_example_adapter *adapter,
252 const char *manufacturer_name1 = "ACME Temperature Sensor";
253 const char *serial1 = "237495-3282-A";
254 uint16_t start_handle, h;
255 const int svc_size = 5;
260 bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
261 start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
262 if (start_handle == 0) {
263 error("Not enough free handles to register service");
267 DBG("start_handle=0x%04x", start_handle);
271 /* Secondary Service: Manufacturer Service */
272 bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
273 att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
274 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
277 /* Manufacturer name characteristic definition */
278 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
279 atval[0] = ATT_CHAR_PROPER_READ;
280 att_put_u16(h + 1, &atval[1]);
281 att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
282 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
285 /* Manufacturer name characteristic value */
286 bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
287 len = strlen(manufacturer_name1);
288 strncpy((char *) atval, manufacturer_name1, len);
289 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
292 /* Manufacturer serial number characteristic */
293 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
294 atval[0] = ATT_CHAR_PROPER_READ;
295 att_put_u16(h + 1, &atval[1]);
296 att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
297 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
300 /* Manufacturer serial number characteristic value */
301 bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
302 len = strlen(serial1);
303 strncpy((char *) atval, serial1, len);
304 attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
307 g_assert(h - start_handle + 1 == svc_size);
309 range[0] = start_handle;
310 range[1] = start_handle + svc_size - 1;
313 static void register_manuf2_service(struct gatt_example_adapter *adapter,
316 const char *manufacturer_name2 = "ACME Weighing Scales";
317 const char *serial2 = "11267-2327A00239";
318 uint16_t start_handle, h;
319 const int svc_size = 5;
324 bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
325 start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
326 if (start_handle == 0) {
327 error("Not enough free handles to register service");
331 DBG("start_handle=0x%04x", start_handle);
335 /* Secondary Service: Manufacturer Service */
336 bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
337 att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
338 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
341 /* Manufacturer name characteristic definition */
342 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
343 atval[0] = ATT_CHAR_PROPER_READ;
344 att_put_u16(h + 1, &atval[1]);
345 att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
346 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
349 /* Manufacturer name attribute */
350 bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
351 len = strlen(manufacturer_name2);
352 strncpy((char *) atval, manufacturer_name2, len);
353 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
356 /* Characteristic: serial number */
357 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
358 atval[0] = ATT_CHAR_PROPER_READ;
359 att_put_u16(h + 1, &atval[1]);
360 att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
361 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
364 /* Serial number characteristic value */
365 bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
366 len = strlen(serial2);
367 strncpy((char *) atval, serial2, len);
368 attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
371 g_assert(h - start_handle + 1 == svc_size);
373 range[0] = start_handle;
374 range[1] = start_handle + svc_size - 1;
377 static void register_vendor_service(struct gatt_example_adapter *adapter,
380 uint16_t start_handle, h;
381 const int svc_size = 3;
385 bt_uuid16_create(&uuid, VENDOR_SPECIFIC_SVC_UUID);
386 start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
387 if (start_handle == 0) {
388 error("Not enough free handles to register service");
392 DBG("start_handle=0x%04x", start_handle);
396 /* Secondary Service: Vendor Specific Service */
397 bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
398 att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[0]);
399 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
402 /* Vendor Specific Type characteristic definition */
403 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
404 atval[0] = ATT_CHAR_PROPER_READ;
405 att_put_u16(h + 1, &atval[1]);
406 att_put_u16(VENDOR_SPECIFIC_TYPE_UUID, &atval[3]);
407 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
410 /* Vendor Specific Type characteristic value */
411 bt_uuid16_create(&uuid, VENDOR_SPECIFIC_TYPE_UUID);
418 attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
421 g_assert(h - start_handle + 1 == svc_size);
423 range[0] = start_handle;
424 range[1] = start_handle + svc_size - 1;
427 static void register_weight_service(struct gatt_example_adapter *adapter,
428 const uint16_t vendor[2])
430 const char *desc_weight = "Rucksack Weight";
431 const uint128_t char_weight_uuid_btorder = {
432 .data = { 0x80, 0x88, 0xF2, 0x18, 0x90, 0x2C, 0x45, 0x0B,
433 0xB6, 0xC4, 0x62, 0x89, 0x1E, 0x8C, 0x25, 0xE9 } };
434 const uint128_t prim_weight_uuid_btorder = {
435 .data = { 0x4F, 0x0A, 0xC0, 0x96, 0x35, 0xD4, 0x49, 0x11,
436 0x96, 0x31, 0xDE, 0xA8, 0xDC, 0x74, 0xEE, 0xFE } };
437 uint128_t prim_weight_uuid, char_weight_uuid;
438 uint16_t start_handle, h;
439 const int svc_size = 6;
445 btoh128(&char_weight_uuid_btorder, &char_weight_uuid);
446 btoh128(&prim_weight_uuid_btorder, &prim_weight_uuid);
447 bt_uuid128_create(&uuid, prim_weight_uuid);
448 start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
449 if (start_handle == 0) {
450 error("Not enough free handles to register service");
454 DBG("start_handle=0x%04x, vendor=0x%04x-0x%04x", start_handle,
455 vendor[0], vendor[1]);
459 /* Weight service: primary service definition */
460 bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
461 memcpy(atval, &prim_weight_uuid_btorder, 16);
462 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
465 if (vendor[0] && vendor[1]) {
466 /* Weight: include */
467 bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
468 att_put_u16(vendor[0], &atval[0]);
469 att_put_u16(vendor[1], &atval[2]);
470 att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
471 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
472 ATT_NOT_PERMITTED, atval, 6);
475 /* Weight: characteristic */
476 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
477 atval[0] = ATT_CHAR_PROPER_READ;
478 att_put_u16(h + 1, &atval[1]);
479 memcpy(&atval[3], &char_weight_uuid_btorder, 16);
480 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
483 /* Weight: characteristic value */
484 bt_uuid128_create(&uuid, char_weight_uuid);
489 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
492 /* Weight: characteristic format */
493 bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
496 att_put_u16(FMT_KILOGRAM_UUID, &atval[2]);
497 att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
498 att_put_u16(FMT_HANGING_UUID, &atval[6]);
499 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
502 /* Weight: characteristic user description */
503 bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
504 len = strlen(desc_weight);
505 strncpy((char *) atval, desc_weight, len);
506 attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
508 g_assert(h - start_handle + 1 == svc_size);
510 /* Add an SDP record for the above service */
511 sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
514 adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
515 GUINT_TO_POINTER(sdp_handle));
518 static int gatt_example_adapter_probe(struct btd_adapter *adapter)
520 uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0};
521 uint16_t vendor_range[2] = {0, 0};
522 struct gatt_example_adapter *gadapter;
524 gadapter = g_new0(struct gatt_example_adapter, 1);
525 gadapter->adapter = btd_adapter_ref(adapter);
527 if (!register_battery_service(adapter)) {
528 DBG("Battery service could not be registered");
529 gatt_example_adapter_free(gadapter);
533 register_manuf1_service(gadapter, manuf1_range);
534 register_manuf2_service(gadapter, manuf2_range);
535 register_termometer_service(gadapter, manuf1_range, manuf2_range);
536 register_vendor_service(gadapter, vendor_range);
537 register_weight_service(gadapter, vendor_range);
539 adapters = g_slist_append(adapters, gadapter);
544 static void gatt_example_adapter_remove(struct btd_adapter *adapter)
546 struct gatt_example_adapter *gadapter;
549 l = g_slist_find_custom(adapters, adapter, adapter_cmp);
554 adapters = g_slist_remove(adapters, gadapter);
555 gatt_example_adapter_free(gadapter);
558 static struct btd_adapter_driver gatt_example_adapter_driver = {
559 .name = "gatt-example-adapter-driver",
560 .probe = gatt_example_adapter_probe,
561 .remove = gatt_example_adapter_remove,
564 static int gatt_example_init(void)
566 if (!main_opts.gatt_enabled) {
567 DBG("GATT is disabled");
571 return btd_register_adapter_driver(&gatt_example_adapter_driver);
574 static void gatt_example_exit(void)
576 if (!main_opts.gatt_enabled)
579 btd_unregister_adapter_driver(&gatt_example_adapter_driver);
582 BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
583 gatt_example_init, gatt_example_exit)