1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <zephyr/sys/util.h>
9 
10 #define BT_MESH_BLOB_OP_XFER_GET BT_MESH_MODEL_OP_2(0x83, 0x00)
11 #define BT_MESH_BLOB_OP_XFER_START BT_MESH_MODEL_OP_2(0x83, 0x01)
12 #define BT_MESH_BLOB_OP_XFER_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x02)
13 #define BT_MESH_BLOB_OP_XFER_STATUS BT_MESH_MODEL_OP_2(0x83, 0x03)
14 #define BT_MESH_BLOB_OP_BLOCK_GET BT_MESH_MODEL_OP_2(0x83, 0x05)
15 #define BT_MESH_BLOB_OP_BLOCK_START BT_MESH_MODEL_OP_2(0x83, 0x04)
16 #define BT_MESH_BLOB_OP_CHUNK BT_MESH_MODEL_OP_1(0x66)
17 #define BT_MESH_BLOB_OP_BLOCK_STATUS BT_MESH_MODEL_OP_1(0x67)
18 #define BT_MESH_BLOB_OP_BLOCK_REPORT BT_MESH_MODEL_OP_1(0x68)
19 #define BT_MESH_BLOB_OP_INFO_GET BT_MESH_MODEL_OP_2(0x83, 0x06)
20 #define BT_MESH_BLOB_OP_INFO_STATUS BT_MESH_MODEL_OP_2(0x83, 0x07)
21 
22 #define BLOB_BLOCK_NOT_SET 0xffff
23 
24 #define BLOB_CHUNK_SDU_OVERHEAD                                                \
25 	(BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK) + 2 + BT_MESH_MIC_SHORT)
26 
27 #define BLOB_CHUNK_SIZE_MAX(sdu_max) ((sdu_max) - BLOB_CHUNK_SDU_OVERHEAD)
28 #define BLOB_CHUNK_SDU_LEN(chunk_size) (BLOB_CHUNK_SDU_OVERHEAD + (chunk_size))
29 
30 /* Utility macros for calculating log2 of a number at compile time.
31  * Used to determine the log2 representation of the block size, which
32  * is configured as a raw number, but encoded as log2.
33  *
34  * The macros expand to a series of ternary expressions, effectively
35  * searching through power of twos until a match is found.
36  * According to MshMBTv1.0, the block size cannot be larger than 2^20,
37  * so we'll stop the search at 20.
38  */
39 #define _BLOB_LOG_2_CEIL(l, x) ((x) <= (1U << l)) ? l :
40 #define _BLOB_LOG_2_FLOOR(l, x) ((x) < (1U << (l + 1))) ? l :
41 
42 #define BLOB_BLOCK_SIZE_LOG_CEIL(x) (LISTIFY(20, _BLOB_LOG_2_CEIL, (), x) 20)
43 #define BLOB_BLOCK_SIZE_LOG_FLOOR(x) (LISTIFY(20, _BLOB_LOG_2_FLOOR, (), x) 20)
44 
45 /* Log2 representation of the minimum block size */
46 #define BLOB_BLOCK_SIZE_LOG_MIN BLOB_BLOCK_SIZE_LOG_CEIL(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN)
47 /* Log2 representation of the maximum block size */
48 #define BLOB_BLOCK_SIZE_LOG_MAX BLOB_BLOCK_SIZE_LOG_FLOOR(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX)
49 
50 #if defined(CONFIG_BT_MESH_BLOB_SRV)
51 #define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN ( \
52 					MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \
53 					    CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3))
54 #define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + \
55 				      MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \
56 					  CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3))
57 #else
58 #define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN sizeof(((struct bt_mesh_blob_srv *)0)->block.missing)
59 #define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + sizeof(((struct bt_mesh_blob_srv *)0)->block.missing))
60 #endif
61 
62 #define BLOB_XFER_STATUS_MSG_MAXLEN (17 + sizeof(((struct bt_mesh_blob_srv *)0)->state.blocks))
63 
64 enum bt_mesh_blob_chunks_missing {
65 	BT_MESH_BLOB_CHUNKS_MISSING_ALL,
66 	BT_MESH_BLOB_CHUNKS_MISSING_NONE,
67 	BT_MESH_BLOB_CHUNKS_MISSING_SOME,
68 	BT_MESH_BLOB_CHUNKS_MISSING_ENCODED,
69 };
70 
blob_block_size(size_t xfer_size,uint8_t block_size_log,uint32_t idx)71 static inline size_t blob_block_size(size_t xfer_size, uint8_t block_size_log,
72 				     uint32_t idx)
73 {
74 	if (((idx + 1U) << block_size_log) <= xfer_size) {
75 		return (1U << block_size_log);
76 	}
77 
78 	return xfer_size & BIT_MASK(block_size_log);
79 }
80 
blob_chunk_missing_set(uint8_t * missing_chunks,int idx,bool missing)81 static inline void blob_chunk_missing_set(uint8_t *missing_chunks,
82 					  int idx, bool missing)
83 {
84 	WRITE_BIT(missing_chunks[idx / 8], idx % 8, missing);
85 }
86 
87 static inline bool
blob_chunk_missing_get(const uint8_t * missing_chunks,int idx)88 blob_chunk_missing_get(const uint8_t *missing_chunks, int idx)
89 {
90 	return !!(missing_chunks[idx / 8] & BIT(idx % 8));
91 }
92 
blob_chunk_missing_set_all(struct bt_mesh_blob_block * block)93 static inline void blob_chunk_missing_set_all(struct bt_mesh_blob_block *block)
94 {
95 	size_t bytes = block->chunk_count / 8;
96 
97 	memset(block->missing, 0xff, bytes);
98 	if (block->chunk_count % 8) {
99 		block->missing[bytes] = BIT_MASK(block->chunk_count % 8);
100 	}
101 }
102 
blob_chunk_missing_set_none(struct bt_mesh_blob_block * block)103 static inline void blob_chunk_missing_set_none(struct bt_mesh_blob_block *block)
104 {
105 	memset(block->missing, 0, sizeof(block->missing));
106 }
107 
108 /** @brief Perform a message broadcast to all BLOB Transfer Client Target nodes.
109  *
110  *  Will send to a group or each Target node individually, repeating until
111  *  all Target nodes have responded or the retry time has run out.
112  *
113  *  @param cli BLOB Transfer Client instance
114  *  @param ctx Broadcast context
115  */
116 void blob_cli_broadcast(struct bt_mesh_blob_cli *cli,
117 			const struct blob_cli_broadcast_ctx *ctx);
118 
119 /** @brief Register that a Target node responded to a broadcast.
120  *
121  *  @param cli    BLOB Transfer Client instance
122  *  @param target Target node that responded.
123  */
124 void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli,
125 			    struct bt_mesh_blob_target *target);
126 
127 /** @brief Notify the BLOB Transfer Client that the requested transmission is complete.
128  *
129  *  Should be called once for each call to the @ref blob_cli_broadcast_ctx.send
130  *  callback.
131  *
132  *  @param cli BLOB Transfer Client instance.
133  */
134 void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli);
135 
136 /** @brief Aborts any ongoing BLOB Transfer Client operations.
137  *
138  * @param cli BLOB Transfer Client instance.
139  */
140 void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli);
141