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