dis.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012 Texas Instruments, Inc.
  7. *
  8. */
  9. #ifdef HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. #include <stdbool.h>
  13. #include <errno.h>
  14. #include <glib.h>
  15. #include "src/log.h"
  16. #include "lib/bluetooth.h"
  17. #include "lib/sdp.h"
  18. #include "lib/uuid.h"
  19. #include "src/shared/util.h"
  20. #include "src/shared/queue.h"
  21. #include "src/shared/att.h"
  22. #include "src/shared/gatt-db.h"
  23. #include "attrib/gattrib.h"
  24. #include "attrib/att.h"
  25. #include "attrib/gatt.h"
  26. #include "profiles/deviceinfo/dis.h"
  27. #define DIS_UUID16 0x180a
  28. #define PNP_ID_SIZE 7
  29. struct bt_dis {
  30. int ref_count;
  31. uint16_t handle;
  32. uint8_t source;
  33. uint16_t vendor;
  34. uint16_t product;
  35. uint16_t version;
  36. GAttrib *attrib; /* GATT connection */
  37. struct gatt_primary *primary; /* Primary details */
  38. bt_dis_notify notify;
  39. void *notify_data;
  40. struct queue *gatt_op;
  41. };
  42. struct characteristic {
  43. struct gatt_char attr; /* Characteristic */
  44. struct bt_dis *d; /* deviceinfo where the char belongs */
  45. };
  46. struct gatt_request {
  47. unsigned int id;
  48. struct bt_dis *dis;
  49. void *user_data;
  50. };
  51. static void destroy_gatt_req(struct gatt_request *req)
  52. {
  53. queue_remove(req->dis->gatt_op, req);
  54. bt_dis_unref(req->dis);
  55. free(req);
  56. }
  57. static void dis_free(struct bt_dis *dis)
  58. {
  59. bt_dis_detach(dis);
  60. g_free(dis->primary);
  61. queue_destroy(dis->gatt_op, (void *) destroy_gatt_req);
  62. g_free(dis);
  63. }
  64. static void foreach_dis_char(struct gatt_db_attribute *attr, void *user_data)
  65. {
  66. struct bt_dis *dis = user_data;
  67. bt_uuid_t pnpid_uuid, uuid;
  68. uint16_t value_handle;
  69. /* Ignore if there are multiple instances */
  70. if (dis->handle)
  71. return;
  72. if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL, NULL, &uuid))
  73. return;
  74. /* Find PNPID characteristic's value handle */
  75. bt_string_to_uuid(&pnpid_uuid, PNPID_UUID);
  76. if (bt_uuid_cmp(&pnpid_uuid, &uuid) == 0)
  77. dis->handle = value_handle;
  78. }
  79. static void foreach_dis_service(struct gatt_db_attribute *attr, void *user_data)
  80. {
  81. struct bt_dis *dis = user_data;
  82. /* Ignore if there are multiple instances */
  83. if (dis->handle)
  84. return;
  85. gatt_db_service_foreach_char(attr, foreach_dis_char, dis);
  86. }
  87. struct bt_dis *bt_dis_new(struct gatt_db *db)
  88. {
  89. struct bt_dis *dis;
  90. dis = g_try_new0(struct bt_dis, 1);
  91. if (!dis)
  92. return NULL;
  93. dis->gatt_op = queue_new();
  94. if (db) {
  95. bt_uuid_t uuid;
  96. /* Handle the DIS service */
  97. bt_uuid16_create(&uuid, DIS_UUID16);
  98. gatt_db_foreach_service(db, &uuid, foreach_dis_service, dis);
  99. if (!dis->handle) {
  100. dis_free(dis);
  101. return NULL;
  102. }
  103. }
  104. return bt_dis_ref(dis);
  105. }
  106. struct bt_dis *bt_dis_new_primary(void *primary)
  107. {
  108. struct bt_dis *dis;
  109. dis = g_try_new0(struct bt_dis, 1);
  110. if (!dis)
  111. return NULL;
  112. dis->gatt_op = queue_new();
  113. if (primary)
  114. dis->primary = g_memdup(primary, sizeof(*dis->primary));
  115. return bt_dis_ref(dis);
  116. }
  117. struct bt_dis *bt_dis_ref(struct bt_dis *dis)
  118. {
  119. if (!dis)
  120. return NULL;
  121. __sync_fetch_and_add(&dis->ref_count, 1);
  122. return dis;
  123. }
  124. void bt_dis_unref(struct bt_dis *dis)
  125. {
  126. if (!dis)
  127. return;
  128. if (__sync_sub_and_fetch(&dis->ref_count, 1))
  129. return;
  130. dis_free(dis);
  131. }
  132. static struct gatt_request *create_request(struct bt_dis *dis,
  133. void *user_data)
  134. {
  135. struct gatt_request *req;
  136. req = new0(struct gatt_request, 1);
  137. req->user_data = user_data;
  138. req->dis = bt_dis_ref(dis);
  139. return req;
  140. }
  141. static bool set_and_store_gatt_req(struct bt_dis *dis,
  142. struct gatt_request *req,
  143. unsigned int id)
  144. {
  145. req->id = id;
  146. return queue_push_head(dis->gatt_op, req);
  147. }
  148. static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
  149. gpointer user_data)
  150. {
  151. struct gatt_request *req = user_data;
  152. struct bt_dis *dis = req->user_data;
  153. uint8_t value[PNP_ID_SIZE];
  154. ssize_t vlen;
  155. destroy_gatt_req(req);
  156. if (status != 0) {
  157. error("Error reading PNP_ID value: %s", att_ecode2str(status));
  158. return;
  159. }
  160. vlen = dec_read_resp(pdu, len, value, sizeof(value));
  161. if (vlen < 0) {
  162. error("Error reading PNP_ID: Protocol error");
  163. return;
  164. }
  165. if (vlen < 7) {
  166. error("Error reading PNP_ID: Invalid pdu length received");
  167. return;
  168. }
  169. dis->source = value[0];
  170. dis->vendor = get_le16(&value[1]);
  171. dis->product = get_le16(&value[3]);
  172. dis->version = get_le16(&value[5]);
  173. DBG("source: 0x%02X vendor: 0x%04X product: 0x%04X version: 0x%04X",
  174. dis->source, dis->vendor, dis->product, dis->version);
  175. if (dis->notify)
  176. dis->notify(dis->source, dis->vendor, dis->product,
  177. dis->version, dis->notify_data);
  178. }
  179. static void read_char(struct bt_dis *dis, GAttrib *attrib, uint16_t handle,
  180. GAttribResultFunc func, gpointer user_data)
  181. {
  182. struct gatt_request *req;
  183. unsigned int id;
  184. req = create_request(dis, user_data);
  185. id = gatt_read_char(attrib, handle, func, req);
  186. if (set_and_store_gatt_req(dis, req, id))
  187. return;
  188. error("dis: Could not read characteristic");
  189. g_attrib_cancel(attrib, id);
  190. free(req);
  191. }
  192. static void discover_char(struct bt_dis *dis, GAttrib *attrib,
  193. uint16_t start, uint16_t end,
  194. bt_uuid_t *uuid, gatt_cb_t func,
  195. gpointer user_data)
  196. {
  197. struct gatt_request *req;
  198. unsigned int id;
  199. req = create_request(dis, user_data);
  200. id = gatt_discover_char(attrib, start, end, uuid, func, req);
  201. if (set_and_store_gatt_req(dis, req, id))
  202. return;
  203. error("dis: Could not send discover characteristic");
  204. g_attrib_cancel(attrib, id);
  205. free(req);
  206. }
  207. static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
  208. void *user_data)
  209. {
  210. struct gatt_request *req = user_data;
  211. struct bt_dis *d = req->user_data;
  212. GSList *l;
  213. destroy_gatt_req(req);
  214. if (status != 0) {
  215. error("Discover deviceinfo characteristics: %s",
  216. att_ecode2str(status));
  217. return;
  218. }
  219. for (l = characteristics; l; l = l->next) {
  220. struct gatt_char *c = l->data;
  221. if (strcmp(c->uuid, PNPID_UUID) == 0) {
  222. d->handle = c->value_handle;
  223. read_char(d, d->attrib, d->handle, read_pnpid_cb, d);
  224. break;
  225. }
  226. }
  227. }
  228. bool bt_dis_attach(struct bt_dis *dis, void *attrib)
  229. {
  230. struct gatt_primary *primary = dis->primary;
  231. if (dis->attrib)
  232. return false;
  233. dis->attrib = g_attrib_ref(attrib);
  234. if (!dis->handle)
  235. discover_char(dis, dis->attrib, primary->range.start,
  236. primary->range.end, NULL,
  237. configure_deviceinfo_cb, dis);
  238. else
  239. read_char(dis, attrib, dis->handle, read_pnpid_cb, dis);
  240. return true;
  241. }
  242. static void cancel_gatt_req(struct gatt_request *req)
  243. {
  244. if (g_attrib_cancel(req->dis->attrib, req->id))
  245. destroy_gatt_req(req);
  246. }
  247. void bt_dis_detach(struct bt_dis *dis)
  248. {
  249. if (!dis->attrib)
  250. return;
  251. queue_foreach(dis->gatt_op, (void *) cancel_gatt_req, NULL);
  252. g_attrib_unref(dis->attrib);
  253. dis->attrib = NULL;
  254. }
  255. bool bt_dis_set_notification(struct bt_dis *dis, bt_dis_notify func,
  256. void *user_data)
  257. {
  258. if (!dis)
  259. return false;
  260. dis->notify = func;
  261. dis->notify_data = user_data;
  262. return true;
  263. }