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