1 /*
2 * Copyright (c) 2021 Xiaomi Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/byteorder.h>
9
10 #include <zephyr/net_buf.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/bluetooth/uuid.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/mesh.h>
17
18 #include "common/bt_str.h"
19
20 #include "mesh.h"
21 #include "net.h"
22 #include "rpl.h"
23 #include "transport.h"
24 #include "prov.h"
25 #include "beacon.h"
26 #include "foundation.h"
27 #include "access.h"
28 #include "proxy.h"
29 #include "proxy_msg.h"
30 #include "proxy_cli.h"
31 #include "gatt_cli.h"
32 #include "pb_gatt_cli.h"
33
34 #define LOG_LEVEL CONFIG_BT_MESH_PROXY_LOG_LEVEL
35 #include <zephyr/logging/log.h>
36 LOG_MODULE_REGISTER(bt_mesh_gatt_client);
37
38 static struct bt_mesh_gatt_server {
39 struct bt_conn *conn;
40 uint16_t svc_start_handle;
41 uint16_t data_in_handle;
42 const struct bt_mesh_gatt_cli *gatt;
43
44 union {
45 void *user_data;
46 struct bt_gatt_discover_params discover;
47 struct bt_gatt_subscribe_params subscribe;
48 };
49 } servers[CONFIG_BT_MAX_CONN];
50
get_server(struct bt_conn * conn)51 static struct bt_mesh_gatt_server *get_server(struct bt_conn *conn)
52 {
53 return &servers[bt_conn_index(conn)];
54 }
55
notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)56 static uint8_t notify_func(struct bt_conn *conn,
57 struct bt_gatt_subscribe_params *params,
58 const void *data, uint16_t length)
59 {
60 const uint8_t *val = data;
61
62 if (!data) {
63 LOG_WRN("[UNSUBSCRIBED]");
64 params->value_handle = 0U;
65 return BT_GATT_ITER_STOP;
66 }
67
68 if (length < 1) {
69 LOG_WRN("Too small Proxy PDU");
70 return BT_GATT_ITER_STOP;
71 }
72
73 (void)bt_mesh_proxy_msg_recv(conn, val, length);
74
75 return BT_GATT_ITER_CONTINUE;
76 }
77
notify_enabled(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)78 static void notify_enabled(struct bt_conn *conn, uint8_t err,
79 struct bt_gatt_subscribe_params *params)
80 {
81 struct bt_mesh_gatt_server *server = get_server(conn);
82
83 if (err != 0) {
84 LOG_WRN("Enable notify failed(err:%d)", err);
85 return;
86 }
87
88 LOG_DBG("[SUBSCRIBED]");
89
90 server->gatt->link_open(conn);
91 }
92
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)93 static uint8_t discover_func(struct bt_conn *conn,
94 const struct bt_gatt_attr *attr,
95 struct bt_gatt_discover_params *params)
96 {
97 int err;
98 struct bt_mesh_gatt_server *server = get_server(conn);
99
100 if (!attr) {
101 LOG_DBG("GATT Services Discover complete");
102 (void)memset(params, 0, sizeof(*params));
103 return BT_GATT_ITER_STOP;
104 }
105
106 LOG_DBG("[ATTRIBUTE UUID 0x%04x] handle %u", BT_UUID_16(server->discover.uuid)->val,
107 attr->handle);
108
109 if (!bt_uuid_cmp(server->discover.uuid, &server->gatt->srv_uuid.uuid)) {
110 server->svc_start_handle = attr->handle;
111
112 server->discover.uuid = &server->gatt->data_in_uuid.uuid;
113 server->discover.start_handle = attr->handle + 1;
114 server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
115
116 err = bt_gatt_discover(conn, &server->discover);
117 if (err) {
118 LOG_DBG("Discover GATT data in char failed (err %d)", err);
119 }
120 } else if (!bt_uuid_cmp(server->discover.uuid,
121 &server->gatt->data_in_uuid.uuid)) {
122 server->data_in_handle = attr->handle + 1;
123
124 server->discover.uuid = &server->gatt->data_out_uuid.uuid;
125 server->discover.start_handle = server->svc_start_handle + 1;
126 server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
127
128 err = bt_gatt_discover(conn, &server->discover);
129 if (err) {
130 LOG_DBG("Discover GATT data out char failed (err %d)", err);
131 }
132 } else if (!bt_uuid_cmp(server->discover.uuid,
133 &server->gatt->data_out_uuid.uuid)) {
134 server->discover.uuid = &server->gatt->data_out_cccd_uuid.uuid;
135 server->discover.start_handle = attr->handle + 2;
136 server->discover.type = BT_GATT_DISCOVER_DESCRIPTOR;
137
138 err = bt_gatt_discover(conn, &server->discover);
139 if (err) {
140 LOG_DBG("Discover GATT CCCD failed (err %d)", err);
141 }
142 } else {
143 (void)memset(&server->subscribe, 0, sizeof(server->subscribe));
144
145 server->subscribe.notify = notify_func;
146 server->subscribe.subscribe = notify_enabled;
147 server->subscribe.value = BT_GATT_CCC_NOTIFY;
148 server->subscribe.ccc_handle = attr->handle;
149 server->subscribe.value_handle = attr->handle - 1;
150
151 err = bt_gatt_subscribe(conn, &server->subscribe);
152 if (err && err != -EALREADY) {
153 LOG_DBG("Subscribe failed (err %d)", err);
154 }
155 }
156
157 return BT_GATT_ITER_STOP;
158 }
159
bt_mesh_gatt_send(struct bt_conn * conn,const void * data,uint16_t len,bt_gatt_complete_func_t end,void * user_data)160 int bt_mesh_gatt_send(struct bt_conn *conn,
161 const void *data, uint16_t len,
162 bt_gatt_complete_func_t end, void *user_data)
163 {
164 struct bt_mesh_gatt_server *server = get_server(conn);
165
166 LOG_DBG("%u bytes: %s", len, bt_hex(data, len));
167
168 return bt_gatt_write_without_response_cb(conn, server->data_in_handle,
169 data, len, false, end, user_data);
170 }
171
gatt_connected(struct bt_conn * conn,uint8_t conn_err)172 static void gatt_connected(struct bt_conn *conn, uint8_t conn_err)
173 {
174 struct bt_mesh_gatt_server *server = get_server(conn);
175 struct bt_conn_info info;
176 int err;
177
178 err = bt_conn_get_info(conn, &info);
179 if (err || info.role != BT_CONN_ROLE_CENTRAL ||
180 !server->gatt) {
181 return;
182 }
183
184 if (conn_err) {
185 LOG_ERR("Failed to connect GATT Services(%u)", conn_err);
186
187 bt_conn_unref(server->conn);
188 server->conn = NULL;
189
190 (void)bt_mesh_scan_enable();
191
192 return;
193 }
194
195 LOG_DBG("conn %p err 0x%02x", (void *)conn, conn_err);
196
197 server->gatt->connected(conn, server->user_data);
198
199 (void)bt_mesh_scan_enable();
200
201 server->discover.uuid = &server->gatt->srv_uuid.uuid;
202 server->discover.func = discover_func;
203 server->discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
204 server->discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
205 server->discover.type = BT_GATT_DISCOVER_PRIMARY;
206 err = bt_gatt_discover(conn, &server->discover);
207 if (err) {
208 LOG_ERR("Unable discover GATT Services (err %d)", err);
209 }
210 }
211
gatt_disconnected(struct bt_conn * conn,uint8_t reason)212 static void gatt_disconnected(struct bt_conn *conn, uint8_t reason)
213 {
214 struct bt_conn_info info;
215 struct bt_mesh_gatt_server *server = get_server(conn);
216 int err;
217
218 err = bt_conn_get_info(conn, &info);
219 if (err || info.role != BT_CONN_ROLE_CENTRAL ||
220 !server->gatt) {
221 return;
222 }
223
224 server->gatt->disconnected(conn);
225
226 bt_conn_unref(server->conn);
227
228 (void)memset(server, 0, sizeof(struct bt_mesh_gatt_server));
229 }
230
bt_mesh_gatt_cli_connect(const bt_addr_le_t * addr,const struct bt_mesh_gatt_cli * gatt,void * user_data)231 int bt_mesh_gatt_cli_connect(const bt_addr_le_t *addr,
232 const struct bt_mesh_gatt_cli *gatt,
233 void *user_data)
234 {
235 int err;
236 struct bt_conn *conn;
237 struct bt_mesh_gatt_server *server;
238
239 /* Avoid interconnection between proxy client and server */
240 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
241 if (conn) {
242 bt_conn_unref(conn);
243 return -EALREADY;
244 }
245
246 err = bt_mesh_scan_disable();
247 if (err) {
248 return err;
249 }
250
251 LOG_DBG("Try to connect services");
252
253 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
254 BT_LE_CONN_PARAM_DEFAULT, &conn);
255 if (err) {
256 LOG_ERR("Connection failed (err:%d)", err);
257
258 (void)bt_mesh_scan_enable();
259
260 return err;
261 }
262
263 server = get_server(conn);
264 server->conn = conn;
265 server->gatt = gatt;
266 server->user_data = user_data;
267
268 return 0;
269 }
270
gatt_advertising_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)271 static void gatt_advertising_recv(const struct bt_le_scan_recv_info *info,
272 struct net_buf_simple *buf)
273 {
274 uint16_t uuid;
275
276 if (buf->len < 3) {
277 return;
278 }
279
280 uuid = net_buf_simple_pull_le16(buf);
281 switch (uuid) {
282 #if defined(CONFIG_BT_MESH_PROXY_CLIENT)
283 case BT_UUID_MESH_PROXY_VAL:
284 bt_mesh_proxy_cli_adv_recv(info, buf);
285 break;
286 #endif
287 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
288 case BT_UUID_MESH_PROV_VAL:
289 bt_mesh_pb_gatt_cli_adv_recv(info, buf);
290 break;
291 #endif
292
293 default:
294 break;
295 }
296 }
297
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)298 static void scan_recv(const struct bt_le_scan_recv_info *info,
299 struct net_buf_simple *buf)
300 {
301 if (info->adv_type != BT_GAP_ADV_TYPE_ADV_IND) {
302 return;
303 }
304
305 if (!bt_mesh_proxy_has_avail_conn()) {
306 return;
307 }
308
309 while (buf->len > 1) {
310 struct net_buf_simple_state state;
311 uint8_t len, type;
312
313 len = net_buf_simple_pull_u8(buf);
314 /* Check for early termination */
315 if (len == 0U) {
316 return;
317 }
318
319 if (len > buf->len) {
320 LOG_WRN("AD malformed");
321 return;
322 }
323
324 net_buf_simple_save(buf, &state);
325
326 type = net_buf_simple_pull_u8(buf);
327
328 buf->len = len - 1;
329
330 switch (type) {
331 case BT_DATA_SVC_DATA16:
332 gatt_advertising_recv(info, buf);
333 break;
334 default:
335 break;
336 }
337
338 net_buf_simple_restore(buf, &state);
339 net_buf_simple_pull(buf, len);
340 }
341 }
342
343 static struct bt_le_scan_cb scan_cb = {
344 .recv = scan_recv,
345 };
346
bt_mesh_gatt_client_init(void)347 void bt_mesh_gatt_client_init(void)
348 {
349 bt_le_scan_cb_register(&scan_cb);
350 }
351
bt_mesh_gatt_client_deinit(void)352 void bt_mesh_gatt_client_deinit(void)
353 {
354 bt_le_scan_cb_unregister(&scan_cb);
355 }
356
357 BT_CONN_CB_DEFINE(conn_callbacks) = {
358 .connected = gatt_connected,
359 .disconnected = gatt_disconnected,
360 };
361