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 "mesh.h"
19 #include "net.h"
20 #include "rpl.h"
21 #include "transport.h"
22 #include "prov.h"
23 #include "beacon.h"
24 #include "foundation.h"
25 #include "access.h"
26 #include "proxy.h"
27 #include "gatt_cli.h"
28 #include "proxy_msg.h"
29 #include "crypto.h"
30 
31 #define LOG_LEVEL CONFIG_BT_MESH_PROXY_LOG_LEVEL
32 #include <zephyr/logging/log.h>
33 LOG_MODULE_REGISTER(bt_mesh_proxy_client);
34 
35 static struct bt_mesh_proxy_server {
36 	struct bt_mesh_proxy_role *role;
37 	bool link_opened;
38 	uint16_t net_idx;
39 } servers[CONFIG_BT_MAX_CONN] = {
40 	[0 ... (CONFIG_BT_MAX_CONN - 1)] = {
41 		.net_idx = BT_MESH_KEY_UNUSED,
42 	},
43 };
44 
45 static bool allow_all_subnet;
46 
find_proxy_srv(uint16_t net_idx,bool conn,bool disconn)47 static struct bt_mesh_proxy_server *find_proxy_srv(uint16_t net_idx,
48 						   bool conn, bool disconn)
49 {
50 	for (int i = 0; i < ARRAY_SIZE(servers); i++) {
51 		if (!servers[i].role) {
52 			if (!disconn) {
53 				continue;
54 			}
55 		} else if (!conn) {
56 			continue;
57 		}
58 
59 		if (servers[i].net_idx == net_idx) {
60 			return &servers[i];
61 		}
62 	}
63 
64 	return NULL;
65 }
66 
find_proxy_srv_by_conn(struct bt_conn * conn)67 static struct bt_mesh_proxy_server *find_proxy_srv_by_conn(struct bt_conn *conn)
68 {
69 	for (int i = 0; i < ARRAY_SIZE(servers); i++) {
70 		if (!servers[i].role ||
71 		    servers[i].role->conn != conn) {
72 			continue;
73 		}
74 
75 		return &servers[i];
76 	}
77 
78 	return NULL;
79 }
80 
bt_mesh_proxy_cli_relay(struct bt_mesh_adv * adv)81 bool bt_mesh_proxy_cli_relay(struct bt_mesh_adv *adv)
82 {
83 	bool relayed = false;
84 	int i;
85 
86 	for (i = 0; i < ARRAY_SIZE(servers); i++) {
87 		struct bt_mesh_proxy_server *server = &servers[i];
88 
89 		if (!server->link_opened) {
90 			continue;
91 		}
92 
93 		if (bt_mesh_proxy_relay_send(server->role->conn, adv)) {
94 			continue;
95 		}
96 
97 		relayed = true;
98 	}
99 
100 	return relayed;
101 }
102 
proxy_msg_recv(struct bt_mesh_proxy_role * role)103 static void proxy_msg_recv(struct bt_mesh_proxy_role *role)
104 {
105 	switch (role->msg_type) {
106 	case BT_MESH_PROXY_NET_PDU:
107 		LOG_DBG("Mesh Network PDU");
108 		bt_mesh_net_recv(&role->buf, 0, BT_MESH_NET_IF_PROXY);
109 		break;
110 	case BT_MESH_PROXY_BEACON:
111 		LOG_DBG("Mesh Beacon PDU");
112 		bt_mesh_beacon_recv(&role->buf);
113 		break;
114 	case BT_MESH_PROXY_CONFIG:
115 		LOG_DBG("Mesh Configuration PDU");
116 		/* TODO */
117 		break;
118 	default:
119 		LOG_WRN("Unhandled Message Type 0x%02x", role->msg_type);
120 		break;
121 	}
122 }
123 
proxy_connected(struct bt_conn * conn,void * user_data)124 static void proxy_connected(struct bt_conn *conn, void *user_data)
125 {
126 	struct bt_mesh_proxy_server *srv = user_data;
127 
128 	srv->role = bt_mesh_proxy_role_setup(conn, bt_mesh_gatt_send,
129 					     proxy_msg_recv);
130 }
131 
proxy_link_open(struct bt_conn * conn)132 static void proxy_link_open(struct bt_conn *conn)
133 {
134 	struct bt_mesh_proxy_server *srv = find_proxy_srv_by_conn(conn);
135 
136 	srv->link_opened = true;
137 }
138 
proxy_disconnected(struct bt_conn * conn)139 static void proxy_disconnected(struct bt_conn *conn)
140 {
141 	struct bt_mesh_proxy_server *srv = find_proxy_srv_by_conn(conn);
142 
143 	bt_mesh_proxy_role_cleanup(srv->role);
144 
145 	srv->role = NULL;
146 	srv->link_opened = false;
147 }
148 
149 static const struct bt_mesh_gatt_cli proxy = {
150 	.srv_uuid		= BT_UUID_INIT_16(BT_UUID_MESH_PROXY_VAL),
151 	.data_in_uuid		= BT_UUID_INIT_16(BT_UUID_MESH_PROXY_DATA_IN_VAL),
152 	.data_out_uuid		= BT_UUID_INIT_16(BT_UUID_MESH_PROXY_DATA_OUT_VAL),
153 	.data_out_cccd_uuid	= BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL),
154 
155 	.connected		= proxy_connected,
156 	.link_open		= proxy_link_open,
157 	.disconnected		= proxy_disconnected
158 };
159 
proxy_srv_check_and_get(struct bt_mesh_subnet * sub,const uint8_t * net_id,struct bt_mesh_proxy_server ** p_srv)160 static bool proxy_srv_check_and_get(struct bt_mesh_subnet *sub, const uint8_t *net_id,
161 				    struct bt_mesh_proxy_server **p_srv)
162 {
163 	struct bt_mesh_proxy_server *srv;
164 
165 	srv = find_proxy_srv(sub->net_idx, true, true);
166 	if (srv) {
167 		if (srv->role) {
168 			return true;
169 		}
170 	} else if (!allow_all_subnet) {
171 		return false;
172 	}
173 
174 	if (!srv) {
175 		srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
176 		if (!srv) {
177 			return true;
178 		}
179 	}
180 
181 	/* If net_id is NULL we already know that the networks match */
182 	if (!net_id || !memcmp(sub->keys[0].net_id, net_id, 8) ||
183 	    (bt_mesh_subnet_has_new_key(sub) && !memcmp(sub->keys[1].net_id, net_id, 8))) {
184 
185 		*p_srv = srv;
186 		return true;
187 	}
188 
189 	return false;
190 }
191 
192 struct find_net_id {
193 	uint8_t type;
194 
195 	union {
196 		const uint8_t *net_id;
197 		struct {
198 			const uint8_t *hash;
199 			const uint8_t *rand;
200 		} priv;
201 	} data;
202 
203 	struct bt_mesh_proxy_server *srv;
204 };
205 
is_hash_equal(struct bt_mesh_subnet * sub,struct find_net_id * res,uint8_t idx)206 static bool is_hash_equal(struct bt_mesh_subnet *sub, struct find_net_id *res, uint8_t idx)
207 {
208 	int err;
209 	uint8_t in[16], out[16];
210 
211 	memcpy(&in[0], sub->keys[idx].net_id, 8);
212 	memcpy(&in[8], res->data.priv.rand, 8);
213 	err = bt_mesh_encrypt(&sub->keys[idx].identity, in, out);
214 	if (err) {
215 		LOG_ERR("Failed to generate hash (err: %d)", err);
216 		return false;
217 	}
218 
219 	if (memcmp(&out[8], res->data.priv.hash, 8)) {
220 		return false;
221 	}
222 
223 	return true;
224 }
225 
has_net_id(struct bt_mesh_subnet * sub,void * user_data)226 static bool has_net_id(struct bt_mesh_subnet *sub, void *user_data)
227 {
228 	struct find_net_id *res = user_data;
229 	uint8_t *net_id = NULL;
230 
231 	if (res->type == BT_MESH_ID_TYPE_NET) {
232 		net_id = (uint8_t *)res->data.net_id;
233 		goto end;
234 	}
235 
236 	/* Additional handling for BT_MESH_ID_TYPE_PRIV_NET msg type */
237 	if (!(is_hash_equal(sub, res, 0) ||
238 	      (bt_mesh_subnet_has_new_key(sub) && is_hash_equal(sub, res, 1)))) {
239 		return false;
240 	}
241 end:
242 	return proxy_srv_check_and_get(sub, net_id, &res->srv);
243 }
244 
handle_net_id(uint8_t type,const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)245 static void handle_net_id(uint8_t type, const struct bt_le_scan_recv_info *info,
246 			  struct net_buf_simple *buf)
247 {
248 	int err;
249 	struct find_net_id res;
250 	struct bt_mesh_subnet *sub;
251 
252 	res.type = type;
253 	res.srv = NULL;
254 
255 	if (type == BT_MESH_ID_TYPE_NET) {
256 		if (buf->len != 8) {
257 			return;
258 		}
259 		res.data.net_id = net_buf_simple_pull_mem(buf, 8);
260 
261 	} else {
262 		if (buf->len != 16) {
263 			return;
264 		}
265 
266 		res.data.priv.hash = net_buf_simple_pull_mem(buf, 8);
267 		res.data.priv.rand = net_buf_simple_pull_mem(buf, 8);
268 	}
269 
270 	sub = bt_mesh_subnet_find(has_net_id, (void *)&res);
271 	if (sub && res.srv) {
272 		err = bt_mesh_gatt_cli_connect(info->addr, &proxy, res.srv);
273 		if (err) {
274 			LOG_DBG("Failed to connect over GATT (err:%d)", err);
275 		}
276 	}
277 }
278 
bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)279 void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info,
280 				struct net_buf_simple *buf)
281 {
282 	uint8_t type;
283 
284 	type = net_buf_simple_pull_u8(buf);
285 	switch (type) {
286 	case BT_MESH_ID_TYPE_NET:
287 		/* Fallthrough */
288 	case BT_MESH_ID_TYPE_PRIV_NET: {
289 		handle_net_id(type, info, buf);
290 		break;
291 	}
292 	case BT_MESH_ID_TYPE_NODE: {
293 		/* TODO */
294 		break;
295 	}
296 	case BT_MESH_ID_TYPE_PRIV_NODE: {
297 		/* TODO */
298 		break;
299 	}
300 	default:
301 		return;
302 	}
303 }
304 
bt_mesh_proxy_connect(uint16_t net_idx)305 int bt_mesh_proxy_connect(uint16_t net_idx)
306 {
307 	struct bt_mesh_proxy_server *srv;
308 
309 	if (net_idx == BT_MESH_KEY_ANY) {
310 		if (allow_all_subnet) {
311 			return -EALREADY;
312 		}
313 
314 		allow_all_subnet = true;
315 
316 		return 0;
317 	}
318 
319 	srv = find_proxy_srv(net_idx, true, true);
320 	if (srv) {
321 		return -EALREADY;
322 	}
323 
324 	srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
325 	if (!srv) {
326 		return -ENOMEM;
327 	}
328 
329 	srv->net_idx = net_idx;
330 
331 	return 0;
332 }
333 
bt_mesh_proxy_disconnect(uint16_t net_idx)334 int bt_mesh_proxy_disconnect(uint16_t net_idx)
335 {
336 	int err;
337 	struct bt_mesh_proxy_server *srv;
338 
339 	if (net_idx != BT_MESH_KEY_ANY) {
340 		srv = find_proxy_srv(net_idx, true, true);
341 		if (!srv) {
342 			return -EALREADY;
343 		}
344 
345 		srv->net_idx = BT_MESH_KEY_UNUSED;
346 
347 		if (!srv->role) {
348 			return 0;
349 		}
350 
351 		return bt_conn_disconnect(srv->role->conn,
352 					  BT_HCI_ERR_REMOTE_USER_TERM_CONN);
353 	}
354 
355 	if (!allow_all_subnet) {
356 		return -EALREADY;
357 	}
358 
359 	allow_all_subnet = false;
360 
361 	for (int i = 0; i < ARRAY_SIZE(servers); i++) {
362 		servers[i].net_idx = BT_MESH_KEY_UNUSED;
363 
364 		if (!servers[i].role) {
365 			continue;
366 		}
367 
368 		err = bt_conn_disconnect(servers[i].role->conn,
369 					 BT_HCI_ERR_REMOTE_USER_TERM_CONN);
370 		if (err) {
371 			return err;
372 		}
373 	}
374 
375 	return 0;
376 }
377 
subnet_evt(struct bt_mesh_subnet * sub,enum bt_mesh_key_evt evt)378 static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
379 {
380 	switch (evt) {
381 	case BT_MESH_KEY_DELETED:
382 		(void)bt_mesh_proxy_disconnect(sub->net_idx);
383 		break;
384 
385 	default:
386 		break;
387 	}
388 }
389 
390 BT_MESH_SUBNET_CB_DEFINE(proxy_cli) = {
391 	.evt_handler = subnet_evt,
392 };
393 
bt_mesh_proxy_cli_is_connected(uint16_t net_idx)394 bool bt_mesh_proxy_cli_is_connected(uint16_t net_idx)
395 {
396 	if (find_proxy_srv(net_idx, true, false)) {
397 		return true;
398 	}
399 
400 	return false;
401 }
402