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 "adv.h"
20 #include "net.h"
21 #include "rpl.h"
22 #include "transport.h"
23 #include "prov.h"
24 #include "beacon.h"
25 #include "foundation.h"
26 #include "access.h"
27 #include "proxy.h"
28 #include "gatt_cli.h"
29 #include "proxy_msg.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 net_buf * buf)81 bool bt_mesh_proxy_cli_relay(struct net_buf *buf)
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, buf)) {
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 
160 struct find_net_id {
161 	const uint8_t *net_id;
162 	struct bt_mesh_proxy_server *srv;
163 };
164 
has_net_id(struct bt_mesh_subnet * sub,void * user_data)165 static bool has_net_id(struct bt_mesh_subnet *sub, void *user_data)
166 {
167 	struct find_net_id *res = user_data;
168 	struct bt_mesh_proxy_server *srv;
169 
170 	srv = find_proxy_srv(sub->net_idx, true, true);
171 	if (srv) {
172 		if (srv->role) {
173 			return true;
174 		}
175 	} else if (!allow_all_subnet) {
176 		return false;
177 	}
178 
179 	if (!srv) {
180 		srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
181 		if (!srv) {
182 			return true;
183 		}
184 	}
185 
186 	if (!memcmp(sub->keys[0].net_id, res->net_id, 8) ||
187 	    (bt_mesh_subnet_has_new_key(sub) &&
188 	     !memcmp(sub->keys[1].net_id, res->net_id, 8))) {
189 		res->srv = srv;
190 		return true;
191 	}
192 
193 	return false;
194 }
195 
bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)196 void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info,
197 				struct net_buf_simple *buf)
198 {
199 	uint8_t type;
200 	struct find_net_id res;
201 	struct bt_mesh_subnet *sub;
202 
203 	type = net_buf_simple_pull_u8(buf);
204 	switch (type) {
205 	case BT_MESH_ID_TYPE_NET:
206 		if (buf->len != 8) {
207 			break;
208 		}
209 
210 		res.net_id = net_buf_simple_pull_mem(buf, 8);
211 		res.srv = NULL;
212 
213 		sub = bt_mesh_subnet_find(has_net_id, (void *)&res);
214 		if (sub && res.srv) {
215 			(void)bt_mesh_gatt_cli_connect(info->addr, &proxy, res.srv);
216 		}
217 
218 		break;
219 	case BT_MESH_ID_TYPE_NODE: {
220 		/* TODO */
221 		break;
222 	}
223 	default:
224 		return;
225 	}
226 }
227 
bt_mesh_proxy_connect(uint16_t net_idx)228 int bt_mesh_proxy_connect(uint16_t net_idx)
229 {
230 	struct bt_mesh_proxy_server *srv;
231 
232 	if (net_idx == BT_MESH_KEY_ANY) {
233 		if (allow_all_subnet) {
234 			return -EALREADY;
235 		}
236 
237 		allow_all_subnet = true;
238 
239 		return 0;
240 	}
241 
242 	srv = find_proxy_srv(net_idx, true, true);
243 	if (srv) {
244 		return -EALREADY;
245 	}
246 
247 	srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
248 	if (!srv) {
249 		return -ENOMEM;
250 	}
251 
252 	srv->net_idx = net_idx;
253 
254 	return 0;
255 }
256 
bt_mesh_proxy_disconnect(uint16_t net_idx)257 int bt_mesh_proxy_disconnect(uint16_t net_idx)
258 {
259 	int err;
260 	struct bt_mesh_proxy_server *srv;
261 
262 	if (net_idx != BT_MESH_KEY_ANY) {
263 		srv = find_proxy_srv(net_idx, true, true);
264 		if (!srv) {
265 			return -EALREADY;
266 		}
267 
268 		srv->net_idx = BT_MESH_KEY_UNUSED;
269 
270 		if (!srv->role) {
271 			return 0;
272 		}
273 
274 		return bt_conn_disconnect(srv->role->conn,
275 					  BT_HCI_ERR_REMOTE_USER_TERM_CONN);
276 	}
277 
278 	if (!allow_all_subnet) {
279 		return -EALREADY;
280 	}
281 
282 	allow_all_subnet = false;
283 
284 	for (int i = 0; i < ARRAY_SIZE(servers); i++) {
285 		servers[i].net_idx = BT_MESH_KEY_UNUSED;
286 
287 		if (!servers[i].role) {
288 			continue;
289 		}
290 
291 		err = bt_conn_disconnect(servers[i].role->conn,
292 					 BT_HCI_ERR_REMOTE_USER_TERM_CONN);
293 		if (err) {
294 			return err;
295 		}
296 	}
297 
298 	return 0;
299 }
300 
subnet_evt(struct bt_mesh_subnet * sub,enum bt_mesh_key_evt evt)301 static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
302 {
303 	switch (evt) {
304 	case BT_MESH_KEY_DELETED:
305 		(void)bt_mesh_proxy_disconnect(sub->net_idx);
306 		break;
307 
308 	default:
309 		break;
310 	}
311 }
312 
313 BT_MESH_SUBNET_CB_DEFINE(proxy_cli) = {
314 	.evt_handler = subnet_evt,
315 };
316