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