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