1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/mesh.h>
8
9 #include "access.h"
10 #include "foundation.h"
11 #include "net.h"
12 #include "mesh.h"
13 #include "transport.h"
14 #include "op_agg.h"
15
16 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(bt_mesh_op_agg_srv);
19
20 NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_TX_SDU_MAX);
21
22 /** Mesh Opcodes Aggregator Server Model Context */
23 static struct bt_mesh_op_agg_srv {
24 /** Composition data model entry pointer. */
25 const struct bt_mesh_model *model;
26 /** Response error code. */
27 int rsp_err;
28 /** Indicates that the received aggregated message
29 * was acknowledged by local server model.
30 */
31 bool ack;
32 /** Aggregator context. */
33 struct op_agg_ctx ctx;
34 } srv = {.ctx.sdu = &sdu};
35
handle_sequence(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)36 static int handle_sequence(const struct bt_mesh_model *model,
37 struct bt_mesh_msg_ctx *ctx,
38 struct net_buf_simple *buf)
39 {
40 struct net_buf_simple_state state;
41 struct net_buf_simple msg;
42 uint16_t elem;
43 uint8_t *status;
44 int err;
45
46 elem = net_buf_simple_pull_le16(buf);
47 ctx->recv_dst = elem;
48
49 bt_mesh_model_msg_init(srv.ctx.sdu, OP_OPCODES_AGGREGATOR_STATUS);
50 status = net_buf_simple_add_u8(srv.ctx.sdu, 0);
51 net_buf_simple_add_le16(srv.ctx.sdu, elem);
52
53 srv.ctx.net_idx = ctx->net_idx;
54 srv.ctx.app_idx = ctx->app_idx;
55 srv.ctx.addr = ctx->addr;
56 srv.ctx.initialized = true;
57
58 if (!BT_MESH_ADDR_IS_UNICAST(elem)) {
59 LOG_WRN("Address is not unicast, ignoring.");
60 return -EINVAL;
61 }
62
63 net_buf_simple_save(buf, &state);
64 while (buf->len > 0) {
65 err = bt_mesh_op_agg_decode_msg(&msg, buf);
66 if (err) {
67 LOG_ERR("Unable to parse Opcodes Aggregator Sequence message (err %d)",
68 err);
69 return err;
70 }
71 }
72 net_buf_simple_restore(buf, &state);
73
74 if (!bt_mesh_elem_find(elem)) {
75 *status = ACCESS_STATUS_INVALID_ADDRESS;
76 goto send;
77 }
78
79 while (buf->len > 0) {
80 (void) bt_mesh_op_agg_decode_msg(&msg, buf);
81
82 srv.ack = false;
83 srv.rsp_err = 0;
84 err = bt_mesh_model_recv(ctx, &msg);
85
86 if (srv.rsp_err) {
87 *status = srv.rsp_err;
88 break;
89 }
90
91 if (err) {
92 *status = err;
93 break;
94 }
95
96 if (!srv.ack) {
97 net_buf_simple_add_u8(srv.ctx.sdu, 0);
98 }
99 }
100
101 send:
102 srv.ctx.initialized = false;
103 err = bt_mesh_model_send(model, ctx, srv.ctx.sdu, NULL, NULL);
104 if (err) {
105 LOG_ERR("Unable to send Opcodes Aggregator Status");
106 return err;
107 }
108
109 return 0;
110 }
111
112 const struct bt_mesh_model_op _bt_mesh_op_agg_srv_op[] = {
113 { OP_OPCODES_AGGREGATOR_SEQUENCE, BT_MESH_LEN_MIN(2), handle_sequence },
114 BT_MESH_MODEL_OP_END,
115 };
116
op_agg_srv_init(const struct bt_mesh_model * model)117 static int op_agg_srv_init(const struct bt_mesh_model *model)
118 {
119 if (!bt_mesh_model_in_primary(model)) {
120 LOG_ERR("Opcodes Aggregator Server only allowed in primary element");
121 return -EINVAL;
122 }
123
124 /* Opcodes Aggregator Server model shall use the device key and
125 * application keys.
126 */
127 model->keys[0] = BT_MESH_KEY_DEV_ANY;
128
129 srv.model = model;
130
131 return 0;
132 }
133
bt_mesh_op_agg_srv_send(const struct bt_mesh_model * model,struct net_buf_simple * msg)134 int bt_mesh_op_agg_srv_send(const struct bt_mesh_model *model, struct net_buf_simple *msg)
135 {
136 int err;
137
138 /* Model responded so mark this message as acknowledged */
139 srv.ack = true;
140
141 err = bt_mesh_op_agg_encode_msg(msg, srv.ctx.sdu);
142 if (err) {
143 srv.rsp_err = ACCESS_STATUS_RESPONSE_OVERFLOW;
144 }
145
146 return err;
147 }
148
bt_mesh_op_agg_srv_accept(struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)149 int bt_mesh_op_agg_srv_accept(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf)
150 {
151
152 return srv.ctx.initialized && (ctx->net_idx == srv.ctx.net_idx) &&
153 (ctx->addr == srv.ctx.addr) && (ctx->app_idx == srv.ctx.app_idx) &&
154 !bt_mesh_op_agg_is_op_agg_msg(buf);
155 }
156
157 const struct bt_mesh_model_cb _bt_mesh_op_agg_srv_cb = {
158 .init = op_agg_srv_init,
159 };
160