1 /** @file
2 * @brief Message APIs.
3 */
4
5 /*
6 * Copyright (c) 2021 Nordic Semiconductor ASA
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10 #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_
11 #define ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_
12
13 /**
14 * @brief Message
15 * @defgroup bt_mesh_msg Message
16 * @ingroup bt_mesh
17 * @{
18 */
19
20 #include <zephyr/kernel.h>
21 #include <zephyr/net/buf.h>
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 struct bt_mesh_model;
28
29 /** Length of a short Mesh MIC. */
30 #define BT_MESH_MIC_SHORT 4
31 /** Length of a long Mesh MIC. */
32 #define BT_MESH_MIC_LONG 8
33
34 /**
35 * @brief Helper to determine the length of an opcode.
36 *
37 * @param _op Opcode.
38 */
39 #define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3)
40
41 /**
42 * @brief Helper for model message buffer length.
43 *
44 * Returns the length of a Mesh model message buffer, including the opcode
45 * length and a short MIC.
46 *
47 * @param _op Opcode of the message.
48 * @param _payload_len Length of the model payload.
49 */
50 #define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \
51 (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT)
52
53 /**
54 * @brief Helper for model message buffer length.
55 *
56 * Returns the length of a Mesh model message buffer, including the opcode
57 * length and a long MIC.
58 *
59 * @param _op Opcode of the message.
60 * @param _payload_len Length of the model payload.
61 */
62 #define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \
63 (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG)
64
65 /**
66 * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE_DEFINE.
67 *
68 * @param _buf Buffer name.
69 * @param _op Opcode of the message.
70 * @param _payload_len Length of the model message payload.
71 */
72 #define BT_MESH_MODEL_BUF_DEFINE(_buf, _op, _payload_len) \
73 NET_BUF_SIMPLE_DEFINE(_buf, BT_MESH_MODEL_BUF_LEN(_op, (_payload_len)))
74
75 /** Message sending context. */
76 struct bt_mesh_msg_ctx {
77 /** NetKey Index of the subnet to send the message on. */
78 uint16_t net_idx;
79
80 /** AppKey Index to encrypt the message with. */
81 uint16_t app_idx;
82
83 /** Remote address. */
84 uint16_t addr;
85
86 /** Destination address of a received message. Not used for sending. */
87 uint16_t recv_dst;
88
89 /** Label UUID if Remote address is Virtual address, or NULL otherwise. */
90 const uint8_t *uuid;
91
92 /** RSSI of received packet. Not used for sending. */
93 int8_t recv_rssi;
94
95 /** Received TTL value. Not used for sending. */
96 uint8_t recv_ttl;
97
98 /** Force sending reliably by using segment acknowledgment */
99 bool send_rel;
100
101 /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
102 uint8_t send_ttl;
103 };
104
105 /**
106 * @brief Helper for bt_mesh_msg_ctx structure initialization.
107 *
108 * @note If @c dst is a Virtual Address, Label UUID shall be initialized separately.
109 *
110 * @param net_key_idx NetKey Index of the subnet to send the message on. Only used if
111 * @c app_key_idx points to devkey.
112 * @param app_key_idx AppKey Index to encrypt the message with.
113 * @param dst Remote addr.
114 * @param ttl Time To Live.
115 */
116 #define BT_MESH_MSG_CTX_INIT(net_key_idx, app_key_idx, dst, ttl) \
117 { \
118 .net_idx = (net_key_idx), \
119 .app_idx = (app_key_idx), \
120 .addr = (dst), \
121 .send_ttl = (ttl), \
122 }
123
124 /**
125 * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Application Key.
126 *
127 * @param app_key_idx AppKey Index to encrypt the message with.
128 * @param dst Remote addr.
129 */
130 #define BT_MESH_MSG_CTX_INIT_APP(app_key_idx, dst) \
131 BT_MESH_MSG_CTX_INIT(0, app_key_idx, dst, BT_MESH_TTL_DEFAULT)
132
133 /**
134 * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Device Key of a remote
135 * device.
136 *
137 * @param net_key_idx NetKey Index of the subnet to send the message on.
138 * @param dst Remote addr.
139 */
140 #define BT_MESH_MSG_CTX_INIT_DEV(net_key_idx, dst) \
141 BT_MESH_MSG_CTX_INIT(net_key_idx, BT_MESH_KEY_DEV_REMOTE, dst, BT_MESH_TTL_DEFAULT)
142
143 /**
144 * @brief Helper for bt_mesh_msg_ctx structure initialization using Model Publication context.
145 *
146 * @param pub Pointer to a model publication context.
147 */
148 #define BT_MESH_MSG_CTX_INIT_PUB(pub) \
149 { \
150 .app_idx = (pub)->key, \
151 .addr = (pub)->addr, \
152 .send_ttl = (pub)->ttl, \
153 .uuid = (pub)->uuid, \
154 }
155
156 /** @brief Initialize a model message.
157 *
158 * Clears the message buffer contents, and encodes the given opcode.
159 * The message buffer will be ready for filling in payload data.
160 *
161 * @param msg Message buffer.
162 * @param opcode Opcode to encode.
163 */
164 void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode);
165
166 /**
167 * Acknowledged message context for tracking the status of model messages pending a response.
168 */
169 struct bt_mesh_msg_ack_ctx {
170 struct k_sem sem; /**< Sync semaphore. */
171 uint32_t op; /**< Opcode we're waiting for. */
172 uint16_t dst; /**< Address of the node that should respond. */
173 void *user_data; /**< User specific parameter. */
174 };
175
176 /** @brief Initialize an acknowledged message context.
177 *
178 * Initializes semaphore used for synchronization between @ref bt_mesh_msg_ack_ctx_wait and
179 * @ref bt_mesh_msg_ack_ctx_rx calls. Call this function before using @ref bt_mesh_msg_ack_ctx.
180 *
181 * @param ack Acknowledged message context to initialize.
182 */
bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx * ack)183 static inline void bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx *ack)
184 {
185 k_sem_init(&ack->sem, 0, 1);
186 }
187
188 /** @brief Reset the synchronization semaphore in an acknowledged message context.
189 *
190 * This function aborts call to @ref bt_mesh_msg_ack_ctx_wait.
191 *
192 * @param ack Acknowledged message context to be reset.
193 */
bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx * ack)194 static inline void bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx *ack)
195 {
196 k_sem_reset(&ack->sem);
197 }
198
199 /** @brief Clear parameters of an acknowledged message context.
200 *
201 * This function clears the opcode, remote address and user data set
202 * by @ref bt_mesh_msg_ack_ctx_prepare.
203 *
204 * @param ack Acknowledged message context to be cleared.
205 */
206 void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack);
207
208 /** @brief Prepare an acknowledged message context for the incoming message to wait.
209 *
210 * This function sets the opcode, remote address of the incoming message and stores the user data.
211 * Use this function before calling @ref bt_mesh_msg_ack_ctx_wait.
212 *
213 * @param ack Acknowledged message context to prepare.
214 * @param op The message OpCode.
215 * @param dst Destination address of the message.
216 * @param user_data User data for the acknowledged message context.
217 *
218 * @return 0 on success, or (negative) error code on failure.
219 */
220 int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack,
221 uint32_t op, uint16_t dst, void *user_data);
222
223 /** @brief Check if the acknowledged message context is initialized with an opcode.
224 *
225 * @param ack Acknowledged message context.
226 *
227 * @return true if the acknowledged message context is initialized with an opcode,
228 * false otherwise.
229 */
bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx * ack)230 static inline bool bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx *ack)
231 {
232 return (ack->op != 0);
233 }
234
235 /** @brief Wait for a message acknowledge.
236 *
237 * This function blocks execution until @ref bt_mesh_msg_ack_ctx_rx is called or by timeout.
238 *
239 * @param ack Acknowledged message context of the message to wait for.
240 * @param timeout Wait timeout.
241 *
242 * @return 0 on success, or (negative) error code on failure.
243 */
244 int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout);
245
246 /** @brief Mark a message as acknowledged.
247 *
248 * This function unblocks call to @ref bt_mesh_msg_ack_ctx_wait.
249 *
250 * @param ack Context of a message to be acknowledged.
251 */
bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx * ack)252 static inline void bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx *ack)
253 {
254 k_sem_give(&ack->sem);
255 }
256
257 /** @brief Check if an opcode and address of a message matches the expected one.
258 *
259 * @param ack Acknowledged message context to be checked.
260 * @param op OpCode of the incoming message.
261 * @param addr Source address of the incoming message.
262 * @param user_data If not NULL, returns a user data stored in the acknowledged message context
263 * by @ref bt_mesh_msg_ack_ctx_prepare.
264 *
265 * @return true if the incoming message matches the expected one, false otherwise.
266 */
267 bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack,
268 uint32_t op, uint16_t addr, void **user_data);
269
270 #ifdef __cplusplus
271 }
272 #endif
273
274 /**
275 * @}
276 */
277
278 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ */
279