1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <zephyr/types.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/sys/byteorder.h>
14
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/mesh.h>
18
19 #include <common/bt_str.h>
20
21 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_REGISTER(bt_mesh_large_comp_data_srv);
24
25 #include "access.h"
26 #include "cfg.h"
27 #include "foundation.h"
28 #include "net.h"
29 #include "mesh.h"
30 #include "transport.h"
31
32 #define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff)
33 #define BT_MESH_MODEL_PAYLOAD_MAX \
34 (BT_MESH_TX_SDU_MAX - BT_MESH_MODEL_OP_LEN(DUMMY_2_BYTE_OP) - \
35 BT_MESH_MIC_SHORT)
36
37 /** Mesh Large Composition Data Server Model Context */
38 static struct bt_mesh_large_comp_data_srv {
39 /** Composition data model entry pointer. */
40 const struct bt_mesh_model *model;
41 } srv;
42
handle_large_comp_data_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)43 static int handle_large_comp_data_get(const struct bt_mesh_model *model,
44 struct bt_mesh_msg_ctx *ctx,
45 struct net_buf_simple *buf)
46 {
47 BT_MESH_MODEL_BUF_DEFINE(rsp, OP_LARGE_COMP_DATA_STATUS,
48 BT_MESH_MODEL_PAYLOAD_MAX);
49 uint8_t page;
50 size_t offset, total_size;
51 int err;
52
53 LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
54 ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
55 bt_hex(buf->data, buf->len));
56
57 page = bt_mesh_comp_parse_page(buf);
58 offset = net_buf_simple_pull_le16(buf);
59
60 LOG_DBG("page %u offset %u", page, offset);
61
62 bt_mesh_model_msg_init(&rsp, OP_LARGE_COMP_DATA_STATUS);
63 net_buf_simple_add_u8(&rsp, page);
64 net_buf_simple_add_le16(&rsp, offset);
65
66 if (atomic_test_bit(bt_mesh.flags, BT_MESH_COMP_DIRTY) && page < 128) {
67 size_t msg_space;
68
69 NET_BUF_SIMPLE_DEFINE(temp_buf, CONFIG_BT_MESH_COMP_PST_BUF_SIZE);
70 err = bt_mesh_comp_read(&temp_buf, page);
71 if (err) {
72 LOG_ERR("Could not read comp data p%d, err: %d", page, err);
73 return err;
74 }
75
76 net_buf_simple_add_le16(&rsp, temp_buf.len);
77 if (offset > temp_buf.len) {
78 return 0;
79 }
80
81 msg_space = net_buf_simple_tailroom(&rsp) - BT_MESH_MIC_SHORT;
82 net_buf_simple_add_mem(
83 &rsp, temp_buf.data + offset,
84 (msg_space < (temp_buf.len - offset)) ? msg_space : temp_buf.len - offset);
85 } else {
86 total_size = bt_mesh_comp_page_size(page);
87 net_buf_simple_add_le16(&rsp, total_size);
88
89 if (offset < total_size) {
90 err = bt_mesh_comp_data_get_page(&rsp, page, offset);
91 if (err && err != -E2BIG) {
92 LOG_ERR("Could not read comp data p%d, err: %d", page, err);
93 return err;
94 }
95 }
96 }
97
98 if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
99 LOG_ERR("Unable to send Large Composition Data Status");
100 }
101
102 return 0;
103 }
104
handle_models_metadata_get(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)105 static int handle_models_metadata_get(const struct bt_mesh_model *model,
106 struct bt_mesh_msg_ctx *ctx,
107 struct net_buf_simple *buf)
108 {
109 BT_MESH_MODEL_BUF_DEFINE(rsp, OP_MODELS_METADATA_STATUS,
110 BT_MESH_MODEL_PAYLOAD_MAX);
111 size_t offset, total_size;
112 uint8_t page;
113 int err;
114
115 LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
116 ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
117 bt_hex(buf->data, buf->len));
118
119 page = net_buf_simple_pull_u8(buf);
120 offset = net_buf_simple_pull_le16(buf);
121
122 LOG_DBG("page %u offset %u", page, offset);
123
124 if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY)) {
125 LOG_DBG("Models Metadata Page 128");
126 page = 128U;
127 } else if (page != 0U) {
128 LOG_DBG("Models Metadata Page %u not available", page);
129 page = 0U;
130 }
131
132 bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
133 net_buf_simple_add_u8(&rsp, page);
134 net_buf_simple_add_le16(&rsp, offset);
135
136 if (atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY) == (page == 0U)) {
137 rsp.size -= BT_MESH_MIC_SHORT;
138 err = bt_mesh_models_metadata_read(&rsp, offset);
139 if (err) {
140 LOG_ERR("Unable to get stored models metadata");
141 return err;
142 }
143
144 rsp.size += BT_MESH_MIC_SHORT;
145 } else {
146 total_size = bt_mesh_metadata_page_0_size();
147 net_buf_simple_add_le16(&rsp, total_size);
148
149 if (offset < total_size) {
150 err = bt_mesh_metadata_get_page_0(&rsp, offset);
151 if (err && err != -E2BIG) {
152 LOG_ERR("Failed to get Models Metadata Page 0: %d", err);
153 return err;
154 }
155 }
156 }
157
158 if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
159 LOG_ERR("Unable to send Models Metadata Status");
160 }
161
162 return 0;
163 }
164
165 const struct bt_mesh_model_op _bt_mesh_large_comp_data_srv_op[] = {
166 { OP_LARGE_COMP_DATA_GET, BT_MESH_LEN_EXACT(3), handle_large_comp_data_get },
167 { OP_MODELS_METADATA_GET, BT_MESH_LEN_EXACT(3), handle_models_metadata_get },
168 BT_MESH_MODEL_OP_END,
169 };
170
large_comp_data_srv_init(const struct bt_mesh_model * model)171 static int large_comp_data_srv_init(const struct bt_mesh_model *model)
172 {
173 const struct bt_mesh_model *config_srv =
174 bt_mesh_model_find(bt_mesh_model_elem(model), BT_MESH_MODEL_ID_CFG_SRV);
175
176 if (config_srv == NULL) {
177 LOG_ERR("Large Composition Data Server cannot extend Configuration server");
178 return -EINVAL;
179 }
180
181 /* Large Composition Data Server model shall use the device key */
182 model->keys[0] = BT_MESH_KEY_DEV;
183 model->rt->flags |= BT_MESH_MOD_DEVKEY_ONLY;
184
185 srv.model = model;
186
187 bt_mesh_model_extend(model, config_srv);
188
189 return 0;
190 }
191
192 const struct bt_mesh_model_cb _bt_mesh_large_comp_data_srv_cb = {
193 .init = large_comp_data_srv_init,
194 };
195