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 	/** Send message with a random delay according to the Access layer transmitting rules. */
102 	bool  rnd_delay;
103 
104 	/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
105 	uint8_t  send_ttl;
106 };
107 
108 /**
109  * @brief Helper for bt_mesh_msg_ctx structure initialization.
110  *
111  * @note If @c dst is a Virtual Address, Label UUID shall be initialized separately.
112  *
113  * @param net_key_idx NetKey Index of the subnet to send the message on. Only used if
114  * @c app_key_idx points to devkey.
115  * @param app_key_idx AppKey Index to encrypt the message with.
116  * @param dst Remote addr.
117  * @param ttl Time To Live.
118  */
119 #define BT_MESH_MSG_CTX_INIT(net_key_idx, app_key_idx, dst, ttl) \
120 	{ \
121 		.net_idx = (net_key_idx), \
122 		.app_idx = (app_key_idx), \
123 		.addr = (dst), \
124 		.send_ttl = (ttl), \
125 	}
126 
127 /**
128  * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Application Key.
129  *
130  * @param app_key_idx AppKey Index to encrypt the message with.
131  * @param dst Remote addr.
132  */
133 #define BT_MESH_MSG_CTX_INIT_APP(app_key_idx, dst) \
134 	BT_MESH_MSG_CTX_INIT(0, app_key_idx, dst, BT_MESH_TTL_DEFAULT)
135 
136 /**
137  * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Device Key of a remote
138  * device.
139  *
140  * @param net_key_idx NetKey Index of the subnet to send the message on.
141  * @param dst Remote addr.
142  */
143 #define BT_MESH_MSG_CTX_INIT_DEV(net_key_idx, dst) \
144 	BT_MESH_MSG_CTX_INIT(net_key_idx, BT_MESH_KEY_DEV_REMOTE, dst, BT_MESH_TTL_DEFAULT)
145 
146 /**
147  * @brief Helper for bt_mesh_msg_ctx structure initialization using Model Publication context.
148  *
149  * @param pub Pointer to a model publication context.
150  */
151 #define BT_MESH_MSG_CTX_INIT_PUB(pub) \
152 	{ \
153 		.app_idx = (pub)->key, \
154 		.addr = (pub)->addr, \
155 		.send_ttl = (pub)->ttl, \
156 		.uuid = (pub)->uuid, \
157 	}
158 
159 /** @brief Initialize a model message.
160  *
161  *  Clears the message buffer contents, and encodes the given opcode.
162  *  The message buffer will be ready for filling in payload data.
163  *
164  *  @param msg    Message buffer.
165  *  @param opcode Opcode to encode.
166  */
167 void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode);
168 
169 /**
170  * Acknowledged message context for tracking the status of model messages pending a response.
171  */
172 struct bt_mesh_msg_ack_ctx {
173 	struct k_sem          sem;       /**< Sync semaphore. */
174 	uint32_t              op;        /**< Opcode we're waiting for. */
175 	uint16_t              dst;       /**< Address of the node that should respond. */
176 	void                 *user_data; /**< User specific parameter. */
177 };
178 
179 /** @brief Initialize an acknowledged message context.
180  *
181  *  Initializes semaphore used for synchronization between @ref bt_mesh_msg_ack_ctx_wait and
182  *  @ref bt_mesh_msg_ack_ctx_rx calls. Call this function before using @ref bt_mesh_msg_ack_ctx.
183  *
184  *  @param ack Acknowledged message context to initialize.
185  */
bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx * ack)186 static inline void bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx *ack)
187 {
188 	k_sem_init(&ack->sem, 0, 1);
189 }
190 
191 /** @brief Reset the synchronization semaphore in an acknowledged message context.
192  *
193  *  This function aborts call to @ref bt_mesh_msg_ack_ctx_wait.
194  *
195  *  @param ack Acknowledged message context to be reset.
196  */
bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx * ack)197 static inline void bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx *ack)
198 {
199 	k_sem_reset(&ack->sem);
200 }
201 
202 /** @brief Clear parameters of an acknowledged message context.
203  *
204  *  This function clears the opcode, remote address and user data set
205  *  by @ref bt_mesh_msg_ack_ctx_prepare.
206  *
207  *  @param ack Acknowledged message context to be cleared.
208  */
209 void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack);
210 
211 /** @brief Prepare an acknowledged message context for the incoming message to wait.
212  *
213  *  This function sets the opcode, remote address of the incoming message and stores the user data.
214  *  Use this function before calling @ref bt_mesh_msg_ack_ctx_wait.
215  *
216  *  @param ack       Acknowledged message context to prepare.
217  *  @param op        The message OpCode.
218  *  @param dst       Destination address of the message.
219  *  @param user_data User data for the acknowledged message context.
220  *
221  *  @return 0 on success, or (negative) error code on failure.
222  */
223 int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack,
224 				uint32_t op, uint16_t dst, void *user_data);
225 
226 /** @brief Check if the acknowledged message context is initialized with an opcode.
227  *
228  *  @param ack Acknowledged message context.
229  *
230  *  @return true if the acknowledged message context is initialized with an opcode,
231  *  false otherwise.
232  */
bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx * ack)233 static inline bool bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx *ack)
234 {
235 	return (ack->op != 0);
236 }
237 
238 /** @brief Wait for a message acknowledge.
239  *
240  *  This function blocks execution until @ref bt_mesh_msg_ack_ctx_rx is called or by timeout.
241  *
242  *  @param ack     Acknowledged message context of the message to wait for.
243  *  @param timeout Wait timeout.
244  *
245  *  @return 0 on success, or (negative) error code on failure.
246  */
247 int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout);
248 
249 /** @brief Mark a message as acknowledged.
250  *
251  *  This function unblocks call to @ref bt_mesh_msg_ack_ctx_wait.
252  *
253  *  @param ack Context of a message to be acknowledged.
254  */
bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx * ack)255 static inline void bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx *ack)
256 {
257 	k_sem_give(&ack->sem);
258 }
259 
260 /** @brief Check if an opcode and address of a message matches the expected one.
261  *
262  *  @param ack       Acknowledged message context to be checked.
263  *  @param op        OpCode of the incoming message.
264  *  @param addr      Source address of the incoming message.
265  *  @param user_data If not NULL, returns a user data stored in the acknowledged message context
266  *  by @ref bt_mesh_msg_ack_ctx_prepare.
267  *
268  *  @return true if the incoming message matches the expected one, false otherwise.
269  */
270 bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack,
271 			       uint32_t op, uint16_t addr, void **user_data);
272 
273 #ifdef __cplusplus
274 }
275 #endif
276 
277 /**
278  * @}
279  */
280 
281 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ */
282