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 "adv.h"
22 #include "net.h"
23 #include "rpl.h"
24 #include "transport.h"
25 #include "prov.h"
26 #include "beacon.h"
27 #include "foundation.h"
28 #include "access.h"
29 #include "proxy.h"
30 #include "proxy_msg.h"
31 #include "proxy_cli.h"
32 #include "gatt_cli.h"
33 #include "pb_gatt_cli.h"
34
35 #define LOG_LEVEL CONFIG_BT_MESH_PROXY_LOG_LEVEL
36 #include <zephyr/logging/log.h>
37 LOG_MODULE_REGISTER(bt_mesh_gatt_client);
38
39 static struct bt_mesh_gatt_server {
40 struct bt_conn *conn;
41 uint16_t svc_start_handle;
42 uint16_t data_in_handle;
43 const struct bt_mesh_gatt_cli *gatt;
44
45 union {
46 void *user_data;
47 struct bt_gatt_discover_params discover;
48 struct bt_gatt_subscribe_params subscribe;
49 };
50 } servers[CONFIG_BT_MAX_CONN];
51
get_server(struct bt_conn * conn)52 static struct bt_mesh_gatt_server *get_server(struct bt_conn *conn)
53 {
54 return &servers[bt_conn_index(conn)];
55 }
56
notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)57 static uint8_t notify_func(struct bt_conn *conn,
58 struct bt_gatt_subscribe_params *params,
59 const void *data, uint16_t length)
60 {
61 const uint8_t *val = data;
62
63 if (!data) {
64 LOG_WRN("[UNSUBSCRIBED]");
65 params->value_handle = 0U;
66 return BT_GATT_ITER_STOP;
67 }
68
69 if (length < 1) {
70 LOG_WRN("Too small Proxy PDU");
71 return BT_GATT_ITER_STOP;
72 }
73
74 (void)bt_mesh_proxy_msg_recv(conn, val, length);
75
76 return BT_GATT_ITER_CONTINUE;
77 }
78
notify_enabled(struct bt_conn * conn,uint8_t err,struct bt_gatt_subscribe_params * params)79 static void notify_enabled(struct bt_conn *conn, uint8_t err,
80 struct bt_gatt_subscribe_params *params)
81 {
82 struct bt_mesh_gatt_server *server = get_server(conn);
83
84 if (err != 0) {
85 LOG_WRN("Enable notify failed(err:%d)", err);
86 return;
87 }
88
89 LOG_DBG("[SUBSCRIBED]");
90
91 server->gatt->link_open(conn);
92 }
93
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)94 static uint8_t discover_func(struct bt_conn *conn,
95 const struct bt_gatt_attr *attr,
96 struct bt_gatt_discover_params *params)
97 {
98 int err;
99 struct bt_mesh_gatt_server *server = get_server(conn);
100
101 if (!attr) {
102 LOG_DBG("GATT Services Discover complete");
103 (void)memset(params, 0, sizeof(*params));
104 return BT_GATT_ITER_STOP;
105 }
106
107 LOG_DBG("[ATTRIBUTE UUID 0x%04x] handle %u", BT_UUID_16(server->discover.uuid)->val,
108 attr->handle);
109
110 if (!bt_uuid_cmp(server->discover.uuid, &server->gatt->srv_uuid.uuid)) {
111 server->svc_start_handle = attr->handle;
112
113 server->discover.uuid = &server->gatt->data_in_uuid.uuid;
114 server->discover.start_handle = attr->handle + 1;
115 server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
116
117 err = bt_gatt_discover(conn, &server->discover);
118 if (err) {
119 LOG_DBG("Discover GATT data in char failed (err %d)", err);
120 }
121 } else if (!bt_uuid_cmp(server->discover.uuid,
122 &server->gatt->data_in_uuid.uuid)) {
123 server->data_in_handle = attr->handle + 1;
124
125 server->discover.uuid = &server->gatt->data_out_uuid.uuid;
126 server->discover.start_handle = server->svc_start_handle + 1;
127 server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
128
129 err = bt_gatt_discover(conn, &server->discover);
130 if (err) {
131 LOG_DBG("Discover GATT data out char failed (err %d)", err);
132 }
133 } else if (!bt_uuid_cmp(server->discover.uuid,
134 &server->gatt->data_out_uuid.uuid)) {
135 server->discover.uuid = &server->gatt->data_out_cccd_uuid.uuid;
136 server->discover.start_handle = attr->handle + 2;
137 server->discover.type = BT_GATT_DISCOVER_DESCRIPTOR;
138
139 err = bt_gatt_discover(conn, &server->discover);
140 if (err) {
141 LOG_DBG("Discover GATT CCCD failed (err %d)", err);
142 }
143 } else {
144 (void)memset(&server->subscribe, 0, sizeof(server->subscribe));
145
146 server->subscribe.notify = notify_func;
147 server->subscribe.subscribe = notify_enabled;
148 server->subscribe.value = BT_GATT_CCC_NOTIFY;
149 server->subscribe.ccc_handle = attr->handle;
150 server->subscribe.value_handle = attr->handle - 1;
151
152 err = bt_gatt_subscribe(conn, &server->subscribe);
153 if (err && err != -EALREADY) {
154 LOG_DBG("Subscribe failed (err %d)", err);
155 }
156 }
157
158 return BT_GATT_ITER_STOP;
159 }
160
bt_mesh_gatt_send(struct bt_conn * conn,const void * data,uint16_t len,bt_gatt_complete_func_t end,void * user_data)161 int bt_mesh_gatt_send(struct bt_conn *conn,
162 const void *data, uint16_t len,
163 bt_gatt_complete_func_t end, void *user_data)
164 {
165 struct bt_mesh_gatt_server *server = get_server(conn);
166
167 LOG_DBG("%u bytes: %s", len, bt_hex(data, len));
168
169 return bt_gatt_write_without_response_cb(conn, server->data_in_handle,
170 data, len, false, end, user_data);
171 }
172
gatt_connected(struct bt_conn * conn,uint8_t conn_err)173 static void gatt_connected(struct bt_conn *conn, uint8_t conn_err)
174 {
175 struct bt_mesh_gatt_server *server = get_server(conn);
176 struct bt_conn_info info;
177 int err;
178
179 bt_conn_get_info(conn, &info);
180 if (info.role != BT_CONN_ROLE_CENTRAL ||
181 !server->gatt) {
182 return;
183 }
184
185 if (conn_err) {
186 LOG_ERR("Failed to connect GATT Services(%u)", conn_err);
187
188 bt_conn_unref(server->conn);
189 server->conn = NULL;
190
191 (void)bt_mesh_scan_enable();
192
193 return;
194 }
195
196 LOG_DBG("conn %p err 0x%02x", (void *)conn, conn_err);
197
198 server->gatt->connected(conn, server->user_data);
199
200 (void)bt_mesh_scan_enable();
201
202 server->discover.uuid = &server->gatt->srv_uuid.uuid;
203 server->discover.func = discover_func;
204 server->discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
205 server->discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
206 server->discover.type = BT_GATT_DISCOVER_PRIMARY;
207 err = bt_gatt_discover(conn, &server->discover);
208 if (err) {
209 LOG_ERR("Unable discover GATT Services (err %d)", err);
210 }
211 }
212
gatt_disconnected(struct bt_conn * conn,uint8_t reason)213 static void gatt_disconnected(struct bt_conn *conn, uint8_t reason)
214 {
215 struct bt_conn_info info;
216 struct bt_mesh_gatt_server *server = get_server(conn);
217
218 bt_conn_get_info(conn, &info);
219 if (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