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 	struct bt_mesh_model *model;
41 } srv;
42 
handle_large_comp_data_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)43 static int handle_large_comp_data_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
44 				      struct net_buf_simple *buf)
45 {
46 	BT_MESH_MODEL_BUF_DEFINE(rsp, OP_LARGE_COMP_DATA_STATUS,
47 				 BT_MESH_MODEL_PAYLOAD_MAX);
48 	uint8_t page;
49 	size_t offset, total_size;
50 	int err;
51 
52 	LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
53 		ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
54 		bt_hex(buf->data, buf->len));
55 
56 	page = net_buf_simple_pull_u8(buf);
57 	offset = net_buf_simple_pull_le16(buf);
58 
59 	LOG_DBG("page %u offset %u", page, offset);
60 
61 	bt_mesh_model_msg_init(&rsp, OP_LARGE_COMP_DATA_STATUS);
62 
63 	if (page != 0U) {
64 		LOG_DBG("Composition page %u not available", page);
65 		page = 0U;
66 	}
67 
68 	net_buf_simple_add_u8(&rsp, page);
69 
70 	total_size = bt_mesh_comp_page_0_size();
71 	net_buf_simple_add_le16(&rsp, offset);
72 	net_buf_simple_add_le16(&rsp, total_size);
73 
74 	if (offset < total_size) {
75 		err = bt_mesh_comp_data_get_page_0(&rsp, offset);
76 		if (err && err != -E2BIG) {
77 			LOG_ERR("comp_get_page_0 returned error");
78 			return err;
79 		}
80 	}
81 
82 	if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
83 		LOG_ERR("Unable to send Large Composition Data Status");
84 	}
85 
86 	return 0;
87 }
88 
handle_models_metadata_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)89 static int handle_models_metadata_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
90 				      struct net_buf_simple *buf)
91 {
92 	BT_MESH_MODEL_BUF_DEFINE(rsp, OP_MODELS_METADATA_STATUS,
93 				 BT_MESH_MODEL_PAYLOAD_MAX);
94 	size_t offset, total_size;
95 	uint8_t page;
96 	int err;
97 
98 	LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
99 		ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
100 		bt_hex(buf->data, buf->len));
101 
102 	page = net_buf_simple_pull_u8(buf);
103 	offset = net_buf_simple_pull_le16(buf);
104 
105 	LOG_DBG("page %u offset %u", page, offset);
106 
107 	if (page >= 128U && atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY)) {
108 		LOG_DBG("Models Metadata Page 128");
109 		page = 128U;
110 	} else if (page != 0U) {
111 		LOG_DBG("Models Metadata Page %u not available", page);
112 		page = 0U;
113 	}
114 
115 	bt_mesh_model_msg_init(&rsp, OP_MODELS_METADATA_STATUS);
116 	net_buf_simple_add_u8(&rsp, page);
117 	net_buf_simple_add_le16(&rsp, offset);
118 
119 	if (atomic_test_bit(bt_mesh.flags, BT_MESH_METADATA_DIRTY) == (page == 0U)) {
120 		rsp.size -= BT_MESH_MIC_SHORT;
121 		err = bt_mesh_models_metadata_read(&rsp, offset);
122 		if (err) {
123 			LOG_ERR("Unable to get stored models metadata");
124 			return err;
125 		}
126 
127 		rsp.size += BT_MESH_MIC_SHORT;
128 	} else {
129 		total_size = bt_mesh_metadata_page_0_size();
130 		net_buf_simple_add_le16(&rsp, total_size);
131 
132 		if (offset < total_size) {
133 			err = bt_mesh_metadata_get_page_0(&rsp, offset);
134 			if (err && err != -E2BIG) {
135 				LOG_ERR("Failed to get Models Metadata Page 0: %d", err);
136 				return err;
137 			}
138 		}
139 	}
140 
141 	if (bt_mesh_model_send(model, ctx, &rsp, NULL, NULL)) {
142 		LOG_ERR("Unable to send Models Metadata Status");
143 	}
144 
145 	return 0;
146 }
147 
148 const struct bt_mesh_model_op _bt_mesh_large_comp_data_srv_op[] = {
149 	{ OP_LARGE_COMP_DATA_GET, BT_MESH_LEN_EXACT(3), handle_large_comp_data_get },
150 	{ OP_MODELS_METADATA_GET, BT_MESH_LEN_EXACT(3), handle_models_metadata_get },
151 	BT_MESH_MODEL_OP_END,
152 };
153 
large_comp_data_srv_init(struct bt_mesh_model * model)154 static int large_comp_data_srv_init(struct bt_mesh_model *model)
155 {
156 	if (!bt_mesh_model_in_primary(model)) {
157 		LOG_ERR("Large Composition Data Server only allowed in primary element");
158 		return -EINVAL;
159 	}
160 
161 	/* Large Composition Data Server model shall use the device key */
162 	model->keys[0] = BT_MESH_KEY_DEV;
163 	model->flags |= BT_MESH_MOD_DEVKEY_ONLY;
164 
165 	srv.model = model;
166 
167 	return 0;
168 }
169 
170 const struct bt_mesh_model_cb _bt_mesh_large_comp_data_srv_cb = {
171 	.init = large_comp_data_srv_init,
172 };
173