1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/mesh.h>
8 #include <zephyr/bluetooth/mesh/brg_cfg.h>
9 #include "access.h"
10 #include "brg_cfg.h"
11 #include "foundation.h"
12 #include "subnet.h"
13
14 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(bt_mesh_brg_cfg_srv);
17
bridge_status_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx)18 static void bridge_status_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx)
19 {
20 BT_MESH_MODEL_BUF_DEFINE(msg, OP_SUBNET_BRIDGE_STATUS, 1);
21
22 bt_mesh_model_msg_init(&msg, OP_SUBNET_BRIDGE_STATUS);
23 net_buf_simple_add_u8(&msg, bt_mesh_brg_cfg_enable_get() ? 1 : 0);
24
25 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
26 LOG_ERR("Brg Status send failed");
27 }
28 }
29
subnet_bridge_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)30 static int subnet_bridge_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
31 struct net_buf_simple *buf)
32 {
33 bridge_status_send(model, ctx);
34
35 return 0;
36 }
37
subnet_bridge_set(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)38 static int subnet_bridge_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
39 struct net_buf_simple *buf)
40 {
41 uint8_t enable = net_buf_simple_pull_u8(buf);
42
43 if (enable > BT_MESH_BRG_CFG_ENABLED) {
44 return -EINVAL;
45 }
46
47 bt_mesh_brg_cfg_enable_set(enable);
48 bridge_status_send(model, ctx);
49
50 return 0;
51 }
52
bridging_table_status_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,uint8_t status,struct bt_mesh_brg_cfg_table_entry * entry)53 static void bridging_table_status_send(const struct bt_mesh_model *model,
54 struct bt_mesh_msg_ctx *ctx, uint8_t status,
55 struct bt_mesh_brg_cfg_table_entry *entry)
56 {
57 BT_MESH_MODEL_BUF_DEFINE(msg, OP_BRIDGING_TABLE_STATUS, 9);
58
59 bt_mesh_model_msg_init(&msg, OP_BRIDGING_TABLE_STATUS);
60 net_buf_simple_add_u8(&msg, status);
61 net_buf_simple_add_u8(&msg, entry->directions);
62 key_idx_pack_pair(&msg, entry->net_idx1, entry->net_idx2);
63 net_buf_simple_add_le16(&msg, entry->addr1);
64 net_buf_simple_add_le16(&msg, entry->addr2);
65
66 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
67 LOG_ERR("Brg Tbl Status send failed");
68 }
69 }
70
netkey_check(uint16_t net_idx1,uint16_t net_idx2)71 static bool netkey_check(uint16_t net_idx1, uint16_t net_idx2)
72 {
73 return bt_mesh_subnet_get(net_idx1) && bt_mesh_subnet_get(net_idx2);
74 }
75
bridging_table_add(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)76 static int bridging_table_add(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
77 struct net_buf_simple *buf)
78 {
79 struct bt_mesh_brg_cfg_table_entry entry;
80 uint8_t status = STATUS_SUCCESS;
81 int err;
82
83 entry.directions = net_buf_simple_pull_u8(buf);
84 key_idx_unpack_pair(buf, &entry.net_idx1, &entry.net_idx2);
85 entry.addr1 = net_buf_simple_pull_le16(buf);
86 entry.addr2 = net_buf_simple_pull_le16(buf);
87
88 err = bt_mesh_brg_cfg_tbl_add(entry.directions, entry.net_idx1, entry.net_idx2, entry.addr1,
89 entry.addr2, &status);
90 if (err) {
91 return err;
92 }
93
94 bridging_table_status_send(model, ctx, status, &entry);
95
96 return 0;
97 }
98
bridging_table_remove(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)99 static int bridging_table_remove(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
100 struct net_buf_simple *buf)
101 {
102 struct bt_mesh_brg_cfg_table_entry entry;
103 uint8_t status = STATUS_SUCCESS;
104 int err;
105
106 entry.directions = 0;
107 key_idx_unpack_pair(buf, &entry.net_idx1, &entry.net_idx2);
108 entry.addr1 = net_buf_simple_pull_le16(buf);
109 entry.addr2 = net_buf_simple_pull_le16(buf);
110
111 err = bt_mesh_brg_cfg_tbl_remove(entry.net_idx1, entry.net_idx2, entry.addr1, entry.addr2,
112 &status);
113 if (err) {
114 return err;
115 }
116
117 bridging_table_status_send(model, ctx, status, &entry);
118
119 return 0;
120 }
121
bridged_subnets_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)122 static int bridged_subnets_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
123 struct net_buf_simple *buf)
124 {
125 BT_MESH_MODEL_BUF_DEFINE(msg, OP_BRIDGED_SUBNETS_LIST,
126 BT_MESH_TX_SDU_MAX -
127 BT_MESH_MODEL_OP_LEN(OP_BRIDGED_SUBNETS_LIST));
128 bt_mesh_model_msg_init(&msg, OP_BRIDGED_SUBNETS_LIST);
129
130 const struct bt_mesh_brg_cfg_row *brg_tbl;
131 int rows = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
132 int16_t net_idx_filter = net_buf_simple_pull_le16(buf);
133
134 if (net_idx_filter & BT_MESH_BRG_CFG_NKEY_PRHB_FLT_MASK) {
135 return -EINVAL;
136 }
137
138 struct bt_mesh_brg_cfg_filter_netkey filter_net_idx;
139
140 filter_net_idx.filter = net_idx_filter & BIT_MASK(2);
141 filter_net_idx.net_idx = (net_idx_filter >> 4) & BIT_MASK(12);
142
143 uint8_t start_id = net_buf_simple_pull_u8(buf);
144
145 net_buf_simple_add_le16(&msg, net_idx_filter);
146 net_buf_simple_add_u8(&msg, start_id);
147
148 uint8_t cnt = 0;
149 uint16_t net_idx1, net_idx2;
150
151 for (int i = 0; i < rows; i++) {
152 net_idx1 = brg_tbl[i].net_idx1;
153 net_idx2 = brg_tbl[i].net_idx2;
154
155 if (net_buf_simple_tailroom(&msg) < 3 + BT_MESH_MIC_SHORT) {
156 break;
157 }
158
159 switch (filter_net_idx.filter) {
160 /* Report pair of NetKeys from the table, starting from start_id. */
161 case 0:
162 if (i >= start_id) {
163 key_idx_pack_pair(&msg, net_idx1, net_idx2);
164 }
165 break;
166
167 /* Report pair of NetKeys in which (NetKeyIndex1) matches the net_idx */
168 case 1:
169 if (net_idx1 == filter_net_idx.net_idx) {
170 if (cnt >= start_id) {
171 key_idx_pack_pair(&msg, net_idx1, net_idx2);
172 }
173 cnt++;
174 }
175 break;
176
177 /* Report pair of NetKeys in which (NetKeyIndex2) matches the net_idx */
178 case 2:
179 if (net_idx2 == filter_net_idx.net_idx) {
180 if (cnt >= start_id) {
181 key_idx_pack_pair(&msg, net_idx1, net_idx2);
182 }
183 cnt++;
184 }
185 break;
186
187 /* Report pair of NetKeys in which (NetKeyIndex1 or NetKeyIndex2) matches the
188 * net_idx
189 */
190 case 3:
191 if (net_idx1 == filter_net_idx.net_idx ||
192 net_idx2 == filter_net_idx.net_idx) {
193 if (cnt >= start_id) {
194 key_idx_pack_pair(&msg, net_idx1, net_idx2);
195 }
196 cnt++;
197 }
198 break;
199
200 default:
201 CODE_UNREACHABLE;
202 }
203 }
204
205 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
206 LOG_ERR("Brg Subnet List send failed");
207 }
208
209 return 0;
210 }
211
bridging_table_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)212 static int bridging_table_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
213 struct net_buf_simple *buf)
214 {
215 BT_MESH_MODEL_BUF_DEFINE(msg, OP_BRIDGING_TABLE_LIST,
216 BT_MESH_TX_SDU_MAX - BT_MESH_MODEL_OP_LEN(OP_BRIDGING_TABLE_LIST));
217 uint8_t status = STATUS_SUCCESS;
218 uint16_t net_idx1, net_idx2;
219
220 bt_mesh_model_msg_init(&msg, OP_BRIDGING_TABLE_LIST);
221
222 key_idx_unpack_pair(buf, &net_idx1, &net_idx2);
223
224 uint16_t start_id = net_buf_simple_pull_le16(buf);
225
226 if (!netkey_check(net_idx1, net_idx2)) {
227 status = STATUS_INVALID_NETKEY;
228 }
229
230 net_buf_simple_add_u8(&msg, status);
231 key_idx_pack_pair(&msg, net_idx1, net_idx2);
232 net_buf_simple_add_le16(&msg, start_id);
233
234 if (status != STATUS_SUCCESS) {
235 goto tbl_get_respond;
236 }
237
238 int cnt = 0;
239 const struct bt_mesh_brg_cfg_row *brg_tbl;
240 int rows = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
241
242 for (int i = 0; i < rows; i++) {
243 if (brg_tbl[i].net_idx1 == net_idx1 && brg_tbl[i].net_idx2 == net_idx2) {
244 if (cnt >= start_id) {
245 if (net_buf_simple_tailroom(&msg) < 5 + BT_MESH_MIC_SHORT) {
246 LOG_WRN("Bridging Table List message too large");
247 break;
248 }
249
250 net_buf_simple_add_le16(&msg, brg_tbl[i].addr1);
251 net_buf_simple_add_le16(&msg, brg_tbl[i].addr2);
252 net_buf_simple_add_u8(&msg, brg_tbl[i].direction);
253 }
254 cnt++;
255 }
256 }
257
258 tbl_get_respond:
259 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
260 LOG_ERR("Brg Tbl List send failed");
261 }
262
263 return 0;
264 }
265
bridging_table_size_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)266 static int bridging_table_size_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
267 struct net_buf_simple *buf)
268 {
269 BT_MESH_MODEL_BUF_DEFINE(msg, OP_BRIDGING_TABLE_SIZE_STATUS, 2);
270 bt_mesh_model_msg_init(&msg, OP_BRIDGING_TABLE_SIZE_STATUS);
271
272 net_buf_simple_add_le16(&msg, CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX);
273
274 if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
275 LOG_ERR("Brg Tbl Size Status send failed");
276 }
277
278 return 0;
279 }
280
281 const struct bt_mesh_model_op _bt_mesh_brg_cfg_srv_op[] = {
282 {OP_SUBNET_BRIDGE_GET, BT_MESH_LEN_EXACT(0), subnet_bridge_get},
283 {OP_SUBNET_BRIDGE_SET, BT_MESH_LEN_EXACT(1), subnet_bridge_set},
284 {OP_BRIDGING_TABLE_ADD, BT_MESH_LEN_EXACT(8), bridging_table_add},
285 {OP_BRIDGING_TABLE_REMOVE, BT_MESH_LEN_EXACT(7), bridging_table_remove},
286 {OP_BRIDGED_SUBNETS_GET, BT_MESH_LEN_EXACT(3), bridged_subnets_get},
287 {OP_BRIDGING_TABLE_GET, BT_MESH_LEN_EXACT(5), bridging_table_get},
288 {OP_BRIDGING_TABLE_SIZE_GET, BT_MESH_LEN_EXACT(0), bridging_table_size_get},
289 BT_MESH_MODEL_OP_END,
290 };
291
brg_cfg_srv_init(const struct bt_mesh_model * model)292 static int brg_cfg_srv_init(const struct bt_mesh_model *model)
293 {
294 const struct bt_mesh_model *config_srv =
295 bt_mesh_model_find(bt_mesh_model_elem(model), BT_MESH_MODEL_ID_CFG_SRV);
296
297 if (config_srv == NULL) {
298 LOG_ERR("Not on primary element");
299 return -EINVAL;
300 }
301
302 /*
303 * Bridge Configuration Server model security is device key based and only the local
304 * device key is allowed to access this model.
305 */
306 model->keys[0] = BT_MESH_KEY_DEV_LOCAL;
307 model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;
308
309 bt_mesh_model_extend(model, config_srv);
310
311 return 0;
312 }
313
brg_cfg_srv_reset(const struct bt_mesh_model * model)314 void brg_cfg_srv_reset(const struct bt_mesh_model *model)
315 {
316 bt_mesh_brg_cfg_tbl_reset();
317 }
318
319 const struct bt_mesh_model_cb _bt_mesh_brg_cfg_srv_cb = {
320 .init = brg_cfg_srv_init,
321 .reset = brg_cfg_srv_reset,
322 };
323