1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @defgroup bt_mesh_dfd_srv Firmware Distribution Server model
10  * @ingroup bt_mesh_dfd
11  * @{
12  * @brief API for the Firmware Distribution Server model
13  */
14 
15 #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__
16 #define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__
17 
18 #include <zephyr/bluetooth/mesh/access.h>
19 #include <zephyr/bluetooth/mesh/dfd.h>
20 #include <zephyr/bluetooth/mesh/blob_srv.h>
21 #include <zephyr/bluetooth/mesh/blob_cli.h>
22 #include <zephyr/bluetooth/mesh/dfu_cli.h>
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #ifndef CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX
29 #define CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX 0
30 #endif
31 
32 #ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE
33 #define CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE 0
34 #endif
35 
36 #ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE
37 #define CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE 0
38 #endif
39 
40 struct bt_mesh_dfd_srv;
41 
42 #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD
43 /**
44  *
45  *  @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB
46  *         upload support.
47  *
48  *  @param[in] _cb                Pointer to a @ref bt_mesh_dfd_srv_cb instance.
49  *  @param[in] _oob_schemes       Array of OOB schemes supported by the server,
50  *                                each scheme being a code point from the
51  *                                Bluetooth SIG Assigned Numbers document.
52  *  @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes.
53  */
54 #define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count)        \
55 	{                                                                      \
56 		.cb = _cb,                                                     \
57 		.dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb),         \
58 		.upload = {                                                    \
59 			.blob = { .cb = &_bt_mesh_dfd_srv_blob_cb },           \
60 		},                                                             \
61 		.oob_schemes = {                                               \
62 			.schemes = _oob_schemes,                               \
63 			.count = _oob_schemes_count,                           \
64 		},                                                             \
65 	}
66 #endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */
67 
68 /**
69  *
70  *  @brief Initialization parameters for the @ref bt_mesh_dfd_srv.
71  *
72  *  @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance.
73  */
74 #define BT_MESH_DFD_SRV_INIT(_cb)                                              \
75 	{                                                                      \
76 		.cb = _cb,                                                     \
77 		.dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb),         \
78 		.upload = {                                                    \
79 			.blob = { .cb = &_bt_mesh_dfd_srv_blob_cb },           \
80 		},                                                             \
81 	}
82 
83 /**
84  *
85  *  @brief Firmware Distribution Server model Composition Data entry.
86  *
87  *  @param _srv Pointer to a @ref bt_mesh_dfd_srv instance.
88  */
89 #define BT_MESH_MODEL_DFD_SRV(_srv)                                            \
90 	BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu),                                   \
91 	BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob),                          \
92 	BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL,  \
93 			 _srv, &_bt_mesh_dfd_srv_cb)
94 
95 /** Firmware Distribution Server callbacks: */
96 struct bt_mesh_dfd_srv_cb {
97 
98 	/** @brief Slot receive callback.
99 	 *
100 	 *  Called at the start of an upload procedure. The callback must fill
101 	 *  @c io with a pointer to a writable BLOB stream for the Firmware Distribution
102 	 *  Server to write the firmware image to.
103 	 *
104 	 *  @param srv  Firmware Distribution Server model instance.
105 	 *  @param slot DFU image slot being received.
106 	 *  @param io   BLOB stream response pointer.
107 	 *
108 	 *  @return 0 on success, or (negative) error code otherwise.
109 	 */
110 	int (*recv)(struct bt_mesh_dfd_srv *srv,
111 		    const struct bt_mesh_dfu_slot *slot,
112 		    const struct bt_mesh_blob_io **io);
113 
114 #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD
115 	/** @brief Firmware upload OOB start callback.
116 	 *
117 	 *  Called at the start of an OOB firmware upload. The application must
118 	 *  start a firmware check using an OOB mechanism, and then call
119 	 *  @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return
120 	 *  value of this function, the application must then start storing the
121 	 *  firmware image using an OOB mechanism, and call
122 	 *  @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory
123 	 *  to support OOB uploads.
124 	 *
125 	 *  @param srv          Firmware Distribution Server model instance.
126 	 *  @param slot         Slot to be used for the upload.
127 	 *  @param uri          Pointer to buffer containing the URI used to
128 	 *                      check for new firmware.
129 	 *  @param uri_len      Length of the URI buffer.
130 	 *  @param fwid         Pointer to buffer containing the current
131 	 *                      firmware ID to be used when checking for
132 	 *                      availability of new firmware.
133 	 *  @param fwid_len     Length of the current firmware ID. Must be set
134 	 *                      to the length of the new firmware ID if it is
135 	 *                      available, or to 0 if new firmware is not
136 	 *                      available.
137 	 *
138 	 *  @return BT_MESH_DFD_SUCCESS on success, or error code otherwise.
139 	 */
140 	int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv,
141 				const struct bt_mesh_dfu_slot *slot,
142 				const char *uri, uint8_t uri_len,
143 				const uint8_t *fwid, uint16_t fwid_len);
144 
145 	/** @brief Cancel store OOB callback
146 	 *
147 	 *  Called when an OOB store is cancelled. The application must stop
148 	 *  any ongoing OOB image transfer. This callback is mandatory to
149 	 *  support OOB uploads.
150 	 *
151 	 *  @param srv  Firmware Distribution Server model instance.
152 	 *  @param slot DFU image slot to cancel
153 	 */
154 	void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv,
155 				  const struct bt_mesh_dfu_slot *slot);
156 
157 	/** @brief Get the progress of an ongoing OOB store
158 	 *
159 	 *  Called by the Firmware Distribution Server model when it needs to
160 	 *  get the current progress of an ongoing OOB store from the
161 	 *  application. This callback is mandatory to support OOB uploads.
162 	 *
163 	 *  @param srv  Firmware Distribution Server model instance.
164 	 *  @param slot DFU image slot to get progress for.
165 	 *
166 	 *  @return The current progress of the ongoing OOB store, in percent.
167 	 */
168 	uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv,
169 				    const struct bt_mesh_dfu_slot *slot);
170 #endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */
171 
172 	/** @brief Slot delete callback.
173 	 *
174 	 *  Called when the Firmware Distribution Server is about to delete a DFU image slot.
175 	 *  All allocated data associated with the firmware slot should be
176 	 *  deleted.
177 	 *
178 	 *  @param srv  Firmware Update Server instance.
179 	 *  @param slot DFU image slot being deleted.
180 	 */
181 	void (*del)(struct bt_mesh_dfd_srv *srv,
182 		    const struct bt_mesh_dfu_slot *slot);
183 
184 	/** @brief Slot send callback.
185 	 *
186 	 *  Called at the start of a distribution procedure. The callback must
187 	 *  fill @c io with a pointer to a readable BLOB stream for the Firmware
188 	 *  Distribution Server to read the firmware image from.
189 	 *
190 	 *  @param srv  Firmware Distribution Server model instance.
191 	 *  @param slot DFU image slot being sent.
192 	 *  @param io   BLOB stream response pointer.
193 	 *
194 	 *  @return 0 on success, or (negative) error code otherwise.
195 	 */
196 	int (*send)(struct bt_mesh_dfd_srv *srv,
197 		    const struct bt_mesh_dfu_slot *slot,
198 		    const struct bt_mesh_blob_io **io);
199 
200 	/** @brief Phase change callback (Optional).
201 	 *
202 	 *  Called whenever the phase of the Firmware Distribution Server changes.
203 	 *
204 	 *  @param srv  Firmware Distribution Server model instance.
205 	 *  @param phase  New Firmware Distribution phase.
206 	 */
207 	void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase);
208 };
209 
210 /** Firmware Distribution Server instance. */
211 struct bt_mesh_dfd_srv {
212 	const struct bt_mesh_dfd_srv_cb *cb;
213 	struct bt_mesh_model *mod;
214 	struct bt_mesh_dfu_cli dfu;
215 	struct bt_mesh_dfu_target targets[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX];
216 	struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX];
217 	const struct bt_mesh_blob_io *io;
218 	uint16_t target_cnt;
219 	uint16_t slot_idx;
220 	bool apply;
221 	enum bt_mesh_dfd_phase phase;
222 	struct bt_mesh_blob_cli_inputs inputs;
223 
224 	struct {
225 		enum bt_mesh_dfd_upload_phase phase;
226 		struct bt_mesh_dfu_slot *slot;
227 		const struct flash_area *area;
228 		struct bt_mesh_blob_srv blob;
229 #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD
230 		bool is_oob;
231 		bool is_pending_oob_check;
232 		struct {
233 			uint8_t uri_len;
234 			uint8_t uri[CONFIG_BT_MESH_DFU_URI_MAXLEN];
235 			uint16_t current_fwid_len;
236 			uint8_t current_fwid[CONFIG_BT_MESH_DFU_FWID_MAXLEN];
237 			struct bt_mesh_msg_ctx ctx;
238 		} oob;
239 #endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */
240 	} upload;
241 
242 #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD
243 	struct {
244 		const uint8_t *schemes;
245 		const uint8_t count;
246 	} oob_schemes;
247 #endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */
248 };
249 
250 #ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD
251 /** @brief Call when an OOB check has completed or failed
252  *
253  *  This should be called by the application after an OOB check started by the @c start_oob_upload
254  *  callback has completed or failed. The @p status param should be set to one of the following
255  *  values:
256  *
257  *  * @c BT_MESH_DFD_SUCCESS if the check was succesfull and a new firmware ID was found.
258  *  * @c BT_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly.
259  *  * @c BT_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node.
260  *  * @c BT_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached.
261  *  * @c BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new
262  *    firmware is available.
263  *
264  *  If this function returns 0, the application should then download the firmware to the
265  *  slot. If an error code is returned, the application should abort the OOB upload.
266  *
267  *  @param srv      Firmware Distribution Server model instance.
268  *  @param slot     The slot used in the OOB upload.
269  *  @param status   The result of the firmware check.
270  *  @param fwid     If the check was successful and new firmware found, this should point to a
271  *                  buffer containing the new firmware ID to store.
272  *  @param fwid_len The length of the firmware ID pointed to by @p fwid.
273  *
274  *  @return 0 on success, (negative) error code otherwise.
275  */
276 int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv,
277 				       const struct bt_mesh_dfu_slot *slot, int status,
278 				       uint8_t *fwid, size_t fwid_len);
279 
280 /** @brief Call when an OOB store has completed or failed
281  *
282  *  This should be called by the application after an OOB store started after a succesfull call to
283  *  @c bt_mesh_dfd_srv_oob_check_complete has completed successfully or failed.
284  *
285  *  @param srv          Firmware Distribution Server model instance.
286  *  @param slot         The slot used when storing the firmware image.
287  *  @param success      @c true if the OOB store completed successfully, @c false otherwise.
288  *  @param size         The size of the stored firmware image, in bytes.
289  *  @param metadata     Pointer to the metadata received OOB, or @c NULL if no metadata was
290  *                      received.
291  *  @param metadata_len Size of the metadata pointed to by @p metadata.
292  *
293  *  @return 0 on success, (negative) error code otherwise.
294  */
295 int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv,
296 				       const struct bt_mesh_dfu_slot *slot, bool success,
297 				       size_t size, const uint8_t *metadata, size_t metadata_len);
298 #endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */
299 
300 /** @cond INTERNAL_HIDDEN */
301 extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[];
302 extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb;
303 extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb;
304 extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb;
305 /** @endcond */
306 
307 #ifdef __cplusplus
308 }
309 #endif
310 
311 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ */
312 
313 /** @} */
314