1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/mesh.h>
8
9 #include "msg.h"
10
11 #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(bt_mesh_msg);
14
bt_mesh_model_msg_init(struct net_buf_simple * msg,uint32_t opcode)15 void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode)
16 {
17 net_buf_simple_init(msg, 0);
18
19 switch (BT_MESH_MODEL_OP_LEN(opcode)) {
20 case 1:
21 net_buf_simple_add_u8(msg, opcode);
22 break;
23 case 2:
24 net_buf_simple_add_be16(msg, opcode);
25 break;
26 case 3:
27 net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
28 /* Using LE for the CID since the model layer is defined as
29 * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3
30 * will declare the opcode in this way.
31 */
32 net_buf_simple_add_le16(msg, opcode & 0xffff);
33 break;
34 default:
35 LOG_WRN("Unknown opcode format");
36 break;
37 }
38 }
39
bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx * ack)40 void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack)
41 {
42 ack->op = 0U;
43 ack->user_data = NULL;
44 ack->dst = BT_MESH_ADDR_UNASSIGNED;
45 }
46
bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx * ack,uint32_t op,uint16_t dst,void * user_data)47 int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack,
48 uint32_t op, uint16_t dst, void *user_data)
49 {
50 if (ack->op) {
51 LOG_WRN("Another synchronous operation pending");
52 return -EBUSY;
53 }
54
55 ack->op = op;
56 ack->user_data = user_data;
57 ack->dst = dst;
58
59 return 0;
60 }
61
bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx * ack,k_timeout_t timeout)62 int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout)
63 {
64 int err;
65
66 err = k_sem_take(&ack->sem, timeout);
67 bt_mesh_msg_ack_ctx_clear(ack);
68
69 if (err == -EAGAIN) {
70 return -ETIMEDOUT;
71 }
72
73 return err;
74 }
75
bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx * ack,uint32_t op,uint16_t addr,void ** user_data)76 bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack,
77 uint32_t op, uint16_t addr, void **user_data)
78 {
79 if (ack->op != op || (BT_MESH_ADDR_IS_UNICAST(ack->dst) && ack->dst != addr)) {
80 return false;
81 }
82
83 if (user_data != NULL) {
84 *user_data = ack->user_data;
85 }
86
87 return true;
88 }
89
bt_mesh_msg_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)90 int bt_mesh_msg_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
91 struct net_buf_simple *buf)
92 {
93 if (!ctx && !model->pub) {
94 return -ENOTSUP;
95 }
96
97 if (ctx) {
98 return bt_mesh_model_send(model, ctx, buf, NULL, 0);
99 }
100
101 net_buf_simple_reset(model->pub->msg);
102 net_buf_simple_add_mem(model->pub->msg, buf->data, buf->len);
103
104 return bt_mesh_model_publish(model);
105 }
106
bt_mesh_msg_ackd_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf,const struct bt_mesh_msg_rsp_ctx * rsp)107 int bt_mesh_msg_ackd_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
108 struct net_buf_simple *buf, const struct bt_mesh_msg_rsp_ctx *rsp)
109 {
110 int err;
111
112 if (rsp) {
113 err = bt_mesh_msg_ack_ctx_prepare(rsp->ack, rsp->op,
114 ctx ? ctx->addr : model->pub->addr,
115 rsp->user_data);
116 if (err) {
117 return err;
118 }
119 }
120
121 err = bt_mesh_msg_send(model, ctx, buf);
122
123 if (!rsp) {
124 return err;
125 }
126
127 if (!err) {
128 return bt_mesh_msg_ack_ctx_wait(rsp->ack, K_MSEC(rsp->timeout));
129 }
130
131 bt_mesh_msg_ack_ctx_clear(rsp->ack);
132
133 return err;
134 }
135