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