1 /*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "mesh_upper_transport.c"
39
40 #include <inttypes.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "btstack_bool.h"
46 #include "btstack_tlv.h"
47 #include "btstack_util.h"
48 #include "btstack_memory.h"
49 #include "btstack_debug.h"
50
51 #include "mesh/mesh_foundation.h"
52 #include "mesh_upper_transport.h"
53 #include "mesh/mesh_iv_index_seq_number.h"
54 #include "mesh/mesh_keys.h"
55 #include "mesh/mesh_lower_transport.h"
56 #include "mesh/mesh_peer.h"
57 #include "mesh/mesh_virtual_addresses.h"
58
59 // TODO: extract mesh_pdu functions into lower transport or network
60 #include "mesh/mesh_access.h"
61
62 // MESH_ACCESS_MESH_NETWORK_PAYLOAD_MAX (384) / MESH_NETWORK_PAYLOAD_MAX (29) = 13.24.. < 14
63 #define MESSAGE_BUILDER_MAX_NUM_NETWORK_PDUS (14)
64
65 // combined key x address iterator for upper transport decryption
66
67 typedef struct {
68 // state
69 mesh_transport_key_iterator_t key_it;
70 mesh_virtual_address_iterator_t address_it;
71 // elements
72 const mesh_transport_key_t * key;
73 const mesh_virtual_address_t * address;
74 // address - might be virtual
75 uint16_t dst;
76 // key info
77 } mesh_transport_key_and_virtual_address_iterator_t;
78
79 static void mesh_upper_transport_run(void);
80 static void mesh_upper_transport_schedule_send_requests(void);
81 static void mesh_upper_transport_validate_access_message(void);
82
83 // upper transport callbacks - in access layer
84 static void (*mesh_access_message_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
85 static void (*mesh_control_message_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
86
87 //
88 static int crypto_active;
89 static uint8_t application_nonce[13];
90 static btstack_crypto_ccm_t ccm;
91 static mesh_transport_key_and_virtual_address_iterator_t mesh_transport_key_it;
92
93 // incoming segmented (mesh_segmented_pdu_t) or unsegmented (network_pdu_t)
94 static mesh_pdu_t * incoming_access_encrypted;
95
96 // multi-purpose union: segmented control reassembly, decrypted access pdu
97 static union {
98 mesh_control_pdu_t control;
99 mesh_access_pdu_t access;
100 } incoming_pdu_singleton;
101
102 // pointer to incoming_pdu_singleton.access
103 static mesh_access_pdu_t * incoming_access_decrypted;
104
105 // pointer to incoming_pdu_singleton.access
106 static mesh_control_pdu_t * incoming_control_pdu;
107
108 // incoming incoming_access_decrypted ready to be deliverd
109 static bool incoming_access_pdu_ready;
110
111 // incoming unsegmented (network) and segmented (transport) control and access messages
112 static btstack_linked_list_t upper_transport_incoming;
113
114
115 // outgoing unsegmented and segmented control and access messages
116 static btstack_linked_list_t upper_transport_outgoing;
117
118 // outgoing upper transport messages that have been sent to lower transport and wait for sent event
119 static btstack_linked_list_t upper_transport_outgoing_active;
120
121 // outgoing send requests
122 static btstack_linked_list_t upper_transport_send_requests;
123
124 // message builder buffers
125 static mesh_upper_transport_pdu_t * message_builder_reserved_upper_pdu;
126 static uint8_t message_builder_num_network_pdus_reserved;
127 static btstack_linked_list_t message_builder_reserved_network_pdus;
128
129 // requets network pdus for outgoing send requests and outgoing run
130 static bool upper_transport_need_pdu_for_send_requests;
131 static bool upper_transport_need_pdu_for_run_outgoing;
132
133 // TODO: higher layer define used for assert
134 #define MESH_ACCESS_OPCODE_NOT_SET 0xFFFFFFFEu
135
mesh_print_hex(const char * name,const uint8_t * data,uint16_t len)136 static void mesh_print_hex(const char * name, const uint8_t * data, uint16_t len){
137 printf("%-20s ", name);
138 printf_hexdump(data, len);
139 }
140 // static void mesh_print_x(const char * name, uint32_t value){
141 // printf("%20s: 0x%x", name, (int) value);
142 // }
143
mesh_transport_key_and_virtual_address_iterator_init(mesh_transport_key_and_virtual_address_iterator_t * it,uint16_t dst,uint16_t netkey_index,uint8_t akf,uint8_t aid)144 static void mesh_transport_key_and_virtual_address_iterator_init(mesh_transport_key_and_virtual_address_iterator_t *it,
145 uint16_t dst, uint16_t netkey_index, uint8_t akf,
146 uint8_t aid) {
147 printf("KEY_INIT: dst %04x, akf %x, aid %x\n", dst, akf, aid);
148 // config
149 it->dst = dst;
150 // init elements
151 it->key = NULL;
152 it->address = NULL;
153 // init element iterators
154 mesh_transport_key_aid_iterator_init(&it->key_it, netkey_index, akf, aid);
155 // init address iterator
156 if (mesh_network_address_virtual(it->dst)){
157 mesh_virtual_address_iterator_init(&it->address_it, dst);
158 // get first key
159 if (mesh_transport_key_aid_iterator_has_more(&it->key_it)) {
160 it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it);
161 }
162 }
163 }
164
165 // cartesian product: keys x addressses
mesh_transport_key_and_virtual_address_iterator_has_more(mesh_transport_key_and_virtual_address_iterator_t * it)166 static int mesh_transport_key_and_virtual_address_iterator_has_more(mesh_transport_key_and_virtual_address_iterator_t * it){
167 if (mesh_network_address_virtual(it->dst)) {
168 // find next valid entry
169 while (true){
170 if (mesh_virtual_address_iterator_has_more(&it->address_it)) return 1;
171 if (!mesh_transport_key_aid_iterator_has_more(&it->key_it)) return 0;
172 // get next key
173 it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it);
174 mesh_virtual_address_iterator_init(&it->address_it, it->dst);
175 }
176 } else {
177 return mesh_transport_key_aid_iterator_has_more(&it->key_it);
178 }
179 }
180
mesh_transport_key_and_virtual_address_iterator_next(mesh_transport_key_and_virtual_address_iterator_t * it)181 static void mesh_transport_key_and_virtual_address_iterator_next(mesh_transport_key_and_virtual_address_iterator_t * it){
182 if (mesh_network_address_virtual(it->dst)) {
183 it->address = mesh_virtual_address_iterator_get_next(&it->address_it);
184 } else {
185 it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it);
186 }
187 }
188
189 // UPPER TRANSPORT
190
mesh_segmented_pdu_flatten(btstack_linked_list_t * segments,uint8_t segment_len,uint8_t * buffer)191 static void mesh_segmented_pdu_flatten(btstack_linked_list_t * segments, uint8_t segment_len, uint8_t * buffer) {
192 // assemble payload
193 btstack_linked_list_iterator_t it;
194 btstack_linked_list_iterator_init(&it, segments);
195 while (btstack_linked_list_iterator_has_next(&it)) {
196 mesh_network_pdu_t *segment = (mesh_network_pdu_t *) btstack_linked_list_iterator_next(&it);
197 btstack_assert(segment->pdu_header.pdu_type == MESH_PDU_TYPE_NETWORK);
198 uint8_t offset = 0;
199 while (offset < segment->len){
200 uint8_t seg_o = segment->data[offset++];
201 (void) memcpy(&buffer[seg_o * segment_len], &segment->data[offset], segment_len);
202 offset += segment_len;
203 }
204 }
205 }
206
mesh_upper_pdu_flatten(mesh_upper_transport_pdu_t * upper_pdu,uint8_t * buffer,uint16_t buffer_len)207 static uint16_t mesh_upper_pdu_flatten(mesh_upper_transport_pdu_t * upper_pdu, uint8_t * buffer, uint16_t buffer_len) {
208 // assemble payload
209 btstack_linked_list_iterator_t it;
210 btstack_linked_list_iterator_init(&it, &upper_pdu->segments);
211 uint16_t offset = 0;
212 while (btstack_linked_list_iterator_has_next(&it)) {
213 mesh_network_pdu_t *segment = (mesh_network_pdu_t *) btstack_linked_list_iterator_next(&it);
214 btstack_assert(segment->pdu_header.pdu_type == MESH_PDU_TYPE_NETWORK);
215 btstack_assert((offset + segment->len) <= buffer_len);
216 (void) memcpy(&buffer[offset], segment->data, segment->len);
217 offset += segment->len;
218 }
219 return offset;
220 }
221
222 // store payload in provided list of network pdus
mesh_segmented_store_payload(const uint8_t * payload,uint16_t payload_len,btstack_linked_list_t * in_segments,btstack_linked_list_t * out_segments)223 static void mesh_segmented_store_payload(const uint8_t * payload, uint16_t payload_len, btstack_linked_list_t * in_segments, btstack_linked_list_t * out_segments){
224 uint16_t payload_offset = 0;
225 uint16_t bytes_current_segment = 0;
226 mesh_network_pdu_t * network_pdu = NULL;
227 while (payload_offset < payload_len){
228 if (bytes_current_segment == 0){
229 network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(in_segments);
230 btstack_assert(network_pdu != NULL);
231 btstack_linked_list_add_tail(out_segments, (btstack_linked_item_t *) network_pdu);
232 bytes_current_segment = MESH_NETWORK_PAYLOAD_MAX;
233 }
234 uint16_t bytes_to_copy = btstack_min(bytes_current_segment, payload_len - payload_offset);
235 (void) memcpy(&network_pdu->data[network_pdu->len], &payload[payload_offset], bytes_to_copy);
236 bytes_current_segment -= bytes_to_copy;
237
238 // on enter, bytes_current_segment = 0 => network_pdu = pop (in segements) + assert (network != NULL)
239 // cppcheck-suppress nullPointer
240 network_pdu->len += bytes_to_copy;
241 payload_offset += bytes_to_copy;
242 }
243 }
244
245 // tries allocate and add enough segments to store payload of given size
mesh_segmented_allocate_segments(btstack_linked_list_t * segments,uint16_t payload_len)246 static bool mesh_segmented_allocate_segments(btstack_linked_list_t * segments, uint16_t payload_len){
247 uint16_t storage_size = btstack_linked_list_count(segments) * MESH_NETWORK_PAYLOAD_MAX;
248 while (storage_size < payload_len){
249 mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
250 if (network_pdu == NULL) break;
251 storage_size += MESH_NETWORK_PAYLOAD_MAX;
252 btstack_linked_list_add(segments, (btstack_linked_item_t *) network_pdu);
253 }
254 return (storage_size >= payload_len);
255 }
256
257 // stub lower transport
258
mesh_upper_transport_dump_pdus(const char * name,btstack_linked_list_t * list)259 static void mesh_upper_transport_dump_pdus(const char *name, btstack_linked_list_t *list){
260 printf("List: %s:\n", name);
261 btstack_linked_list_iterator_t it;
262 btstack_linked_list_iterator_init(&it, list);
263 while (btstack_linked_list_iterator_has_next(&it)){
264 mesh_pdu_t * pdu = (mesh_pdu_t*) btstack_linked_list_iterator_next(&it);
265 printf("- %p\n", pdu);
266 // printf_hexdump( mesh_pdu_data(pdu), mesh_pdu_len(pdu));
267 }
268 }
269
mesh_upper_transport_reset_pdus(btstack_linked_list_t * list)270 static void mesh_upper_transport_reset_pdus(btstack_linked_list_t *list){
271 while (!btstack_linked_list_empty(list)){
272 mesh_upper_transport_pdu_free((mesh_pdu_t *) btstack_linked_list_pop(list));
273 }
274 }
275
mesh_upper_transport_dump(void)276 void mesh_upper_transport_dump(void){
277 mesh_upper_transport_dump_pdus("upper_transport_incoming", &upper_transport_incoming);
278 }
279
mesh_upper_transport_reset(void)280 void mesh_upper_transport_reset(void){
281 crypto_active = 0;
282 mesh_upper_transport_reset_pdus(&upper_transport_incoming);
283 mesh_upper_transport_reset_pdus(&upper_transport_outgoing);
284 message_builder_num_network_pdus_reserved = 0;
285 mesh_upper_transport_reset_pdus(&message_builder_reserved_network_pdus);
286 if (message_builder_reserved_upper_pdu != NULL){
287 btstack_memory_mesh_upper_transport_pdu_free(message_builder_reserved_upper_pdu);
288 message_builder_reserved_upper_pdu = NULL;
289 }
290 }
291
mesh_upper_transport_get_outgoing_appkey(uint16_t netkey_index,uint16_t appkey_index)292 static mesh_transport_key_t * mesh_upper_transport_get_outgoing_appkey(uint16_t netkey_index, uint16_t appkey_index){
293 // Device Key is fixed
294 if (appkey_index == MESH_DEVICE_KEY_INDEX) {
295 return mesh_transport_key_get(appkey_index);
296 }
297
298 // Get key refresh state from subnet
299 mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
300 if (subnet == NULL) return NULL;
301
302 // identify old and new app keys for given appkey_index
303 mesh_transport_key_t * old_key = NULL;
304 mesh_transport_key_t * new_key = NULL;
305 mesh_transport_key_iterator_t it;
306 mesh_transport_key_iterator_init(&it, netkey_index);
307 while (mesh_transport_key_iterator_has_more(&it)){
308 mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
309 if (transport_key->appkey_index != appkey_index) continue;
310 if (transport_key->old_key == 0) {
311 new_key = transport_key;
312 } else {
313 old_key = transport_key;
314 }
315 }
316
317 // if no key is marked as old, just use the current one
318 if (old_key == NULL) return new_key;
319
320 // use new key if it exists in phase two
321 if ((subnet->key_refresh == MESH_KEY_REFRESH_SECOND_PHASE) && (new_key != NULL)){
322 return new_key;
323 } else {
324 return old_key;
325 }
326 }
327
iv_index_for_ivi_nid(uint8_t ivi_nid)328 static uint32_t iv_index_for_ivi_nid(uint8_t ivi_nid){
329 // get IV Index and IVI
330 uint32_t iv_index = mesh_get_iv_index();
331 int ivi = ivi_nid >> 7;
332
333 // if least significant bit differs, use previous IV Index
334 if ((iv_index & 1 ) ^ ivi){
335 iv_index--;
336 }
337 return iv_index;
338 }
339
transport_segmented_setup_nonce(uint8_t * nonce,const mesh_pdu_t * pdu)340 static void transport_segmented_setup_nonce(uint8_t * nonce, const mesh_pdu_t * pdu){
341 mesh_access_pdu_t * access_pdu;
342 mesh_upper_transport_pdu_t * upper_pdu;
343 switch (pdu->pdu_type){
344 case MESH_PDU_TYPE_ACCESS:
345 access_pdu = (mesh_access_pdu_t *) pdu;
346 nonce[1] = ((access_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 0x80 : 0x00;
347 big_endian_store_24(nonce, 2, access_pdu->seq);
348 big_endian_store_16(nonce, 5, access_pdu->src);
349 big_endian_store_16(nonce, 7, access_pdu->dst);
350 big_endian_store_32(nonce, 9, iv_index_for_ivi_nid(access_pdu->ivi_nid));
351 break;
352 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
353 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
354 upper_pdu = (mesh_upper_transport_pdu_t *) pdu;
355 nonce[1] = ((upper_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 0x80 : 0x00;
356 // 'network header'
357 big_endian_store_24(nonce, 2, upper_pdu->seq);
358 big_endian_store_16(nonce, 5, upper_pdu->src);
359 big_endian_store_16(nonce, 7, upper_pdu->dst);
360 big_endian_store_32(nonce, 9, iv_index_for_ivi_nid(upper_pdu->ivi_nid));
361 break;
362 default:
363 btstack_assert(0);
364 break;
365 }
366 }
367
transport_segmented_setup_application_nonce(uint8_t * nonce,const mesh_pdu_t * pdu)368 static void transport_segmented_setup_application_nonce(uint8_t * nonce, const mesh_pdu_t * pdu){
369 nonce[0] = 0x01;
370 transport_segmented_setup_nonce(nonce, pdu);
371 mesh_print_hex("AppNonce", nonce, 13);
372 }
373
transport_segmented_setup_device_nonce(uint8_t * nonce,const mesh_pdu_t * pdu)374 static void transport_segmented_setup_device_nonce(uint8_t * nonce, const mesh_pdu_t * pdu){
375 nonce[0] = 0x02;
376 transport_segmented_setup_nonce(nonce, pdu);
377 mesh_print_hex("DeviceNonce", nonce, 13);
378 }
379
mesh_upper_transport_process_access_message_done(mesh_access_pdu_t * access_pdu)380 static void mesh_upper_transport_process_access_message_done(mesh_access_pdu_t *access_pdu){
381 crypto_active = 0;
382 btstack_assert((access_pdu->ctl_ttl & 0x80) == 0);
383 mesh_lower_transport_message_processed_by_higher_layer(incoming_access_encrypted);
384 incoming_access_encrypted = NULL;
385 incoming_access_decrypted = NULL;
386 mesh_upper_transport_run();
387 }
388
mesh_upper_transport_process_control_message_done(mesh_control_pdu_t * control_pdu)389 static void mesh_upper_transport_process_control_message_done(mesh_control_pdu_t * control_pdu){
390 UNUSED(control_pdu);
391 crypto_active = 0;
392 incoming_control_pdu = NULL;
393 mesh_upper_transport_run();
394 }
395
mesh_upper_transport_network_pdu_freed(void)396 static void mesh_upper_transport_network_pdu_freed(void){
397 // call both while prioritizing run outgoing
398 // both functions will trigger request for network pdu if needed
399 if (upper_transport_need_pdu_for_run_outgoing){
400 upper_transport_need_pdu_for_run_outgoing = false;
401 mesh_upper_transport_run();
402 }
403 if (upper_transport_need_pdu_for_send_requests){
404 upper_transport_need_pdu_for_send_requests = false;
405 mesh_upper_transport_schedule_send_requests();
406 }
407 }
408
mesh_upper_transport_need_pdu_for_send_requests(void)409 static void mesh_upper_transport_need_pdu_for_send_requests(void) {
410 bool waiting = upper_transport_need_pdu_for_send_requests || upper_transport_need_pdu_for_run_outgoing;
411 upper_transport_need_pdu_for_send_requests = true;
412 if (waiting == false) {
413 mesh_network_notify_on_freed_pdu(&mesh_upper_transport_network_pdu_freed);
414 }
415 }
mesh_upper_transport_need_pdu_for_run_outgoing(void)416 static void mesh_upper_transport_need_pdu_for_run_outgoing(void) {
417 bool waiting = upper_transport_need_pdu_for_send_requests || upper_transport_need_pdu_for_run_outgoing;
418 upper_transport_need_pdu_for_run_outgoing = true;
419 if (waiting == false) {
420 mesh_network_notify_on_freed_pdu(&mesh_upper_transport_network_pdu_freed);
421 }
422 }
423
mesh_upper_transport_deliver_access_message(void)424 static void mesh_upper_transport_deliver_access_message(void) {
425 incoming_access_pdu_ready = false;
426 mesh_access_message_handler(MESH_TRANSPORT_PDU_RECEIVED, MESH_TRANSPORT_STATUS_SUCCESS, (mesh_pdu_t *) incoming_access_decrypted);
427 }
428
mesh_upper_transport_send_requests_pending(void)429 static bool mesh_upper_transport_send_requests_pending(void){
430 if (incoming_access_pdu_ready) {
431 return true;
432 }
433 return btstack_linked_list_empty(&upper_transport_send_requests) == false;
434 }
435
mesh_upper_transport_schedule_send_requests(void)436 static void mesh_upper_transport_schedule_send_requests(void){
437
438 while (mesh_upper_transport_send_requests_pending()){
439
440 // get ready
441 bool message_builder_ready = mesh_upper_transport_message_reserve();
442
443 if (message_builder_ready == false){
444 // waiting for free upper pdu, we will get called again on pdu free
445 if (message_builder_reserved_upper_pdu == NULL){
446 return;
447 }
448 // request callback on network pdu free
449 mesh_upper_transport_need_pdu_for_send_requests();
450 return;
451 }
452
453 // process send requests
454
455 // incoming access pdu
456 if (incoming_access_pdu_ready){
457 // message builder ready = one outgoing pdu is guaranteed, deliver access pdu
458 mesh_upper_transport_deliver_access_message();
459 continue;
460 }
461
462 // regular send request
463 btstack_context_callback_registration_t * send_request = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&upper_transport_send_requests);
464 btstack_assert(send_request != NULL);
465 (*send_request->callback)(send_request->context);
466 }
467 }
468
mesh_upper_transport_request_to_send(btstack_context_callback_registration_t * request)469 void mesh_upper_transport_request_to_send(btstack_context_callback_registration_t * request){
470 btstack_linked_list_add_tail(&upper_transport_send_requests, (btstack_linked_item_t *) request);
471 mesh_upper_transport_schedule_send_requests();
472 }
473
mesh_upper_transport_validate_access_message_ccm(void * arg)474 static void mesh_upper_transport_validate_access_message_ccm(void * arg){
475 UNUSED(arg);
476
477 uint8_t transmic_len = ((incoming_access_decrypted->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
478 uint8_t * upper_transport_pdu = incoming_access_decrypted->data;
479 uint8_t upper_transport_pdu_len = incoming_access_decrypted->len - transmic_len;
480
481 mesh_print_hex("Decrypted PDU", upper_transport_pdu, upper_transport_pdu_len);
482
483 // store TransMIC
484 uint8_t trans_mic[8];
485 btstack_crypto_ccm_get_authentication_value(&ccm, trans_mic);
486 mesh_print_hex("TransMIC", trans_mic, transmic_len);
487
488 if (memcmp(trans_mic, &upper_transport_pdu[upper_transport_pdu_len], transmic_len) == 0){
489 printf("TransMIC matches\n");
490
491 // remove TransMIC from payload
492 incoming_access_decrypted->len -= transmic_len;
493
494 // if virtual address, update dst to pseudo_dst
495 if (mesh_network_address_virtual(incoming_access_decrypted->dst)){
496 incoming_access_decrypted->dst = mesh_transport_key_it.address->pseudo_dst;
497 }
498
499 // pass to upper layer
500 incoming_access_pdu_ready = true;
501 mesh_upper_transport_schedule_send_requests();
502
503 } else {
504 uint8_t akf = incoming_access_decrypted->akf_aid_control & 0x40;
505 if (akf){
506 printf("TransMIC does not match, try next key\n");
507 mesh_upper_transport_validate_access_message();
508 } else {
509 printf("TransMIC does not match device key, done\n");
510 // done
511 mesh_upper_transport_process_access_message_done(incoming_access_decrypted);
512 }
513 }
514 }
515
mesh_upper_transport_validate_access_message_digest(void * arg)516 static void mesh_upper_transport_validate_access_message_digest(void * arg){
517 UNUSED(arg);
518 uint8_t transmic_len = ((incoming_access_decrypted->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
519 uint8_t upper_transport_pdu_len = incoming_access_decrypted->len - transmic_len;
520 uint8_t * upper_transport_pdu_data_out = incoming_access_decrypted->data;
521
522 mesh_network_pdu_t * unsegmented_pdu = NULL;
523 mesh_segmented_pdu_t * segmented_pdu = NULL;
524 switch (incoming_access_encrypted->pdu_type){
525 case MESH_PDU_TYPE_SEGMENTED:
526 segmented_pdu = (mesh_segmented_pdu_t *) incoming_access_encrypted;
527 mesh_segmented_pdu_flatten(&segmented_pdu->segments, 12, upper_transport_pdu_data_out);
528 mesh_print_hex("Encrypted Payload:", upper_transport_pdu_data_out, upper_transport_pdu_len);
529 btstack_crypto_ccm_decrypt_block(&ccm, upper_transport_pdu_len, upper_transport_pdu_data_out, upper_transport_pdu_data_out,
530 &mesh_upper_transport_validate_access_message_ccm, NULL);
531 break;
532 case MESH_PDU_TYPE_UNSEGMENTED:
533 unsegmented_pdu = (mesh_network_pdu_t *) incoming_access_encrypted;
534 (void)memcpy(upper_transport_pdu_data_out, &unsegmented_pdu->data[10], incoming_access_decrypted->len);
535 btstack_crypto_ccm_decrypt_block(&ccm, upper_transport_pdu_len, upper_transport_pdu_data_out, upper_transport_pdu_data_out,
536 &mesh_upper_transport_validate_access_message_ccm, NULL);
537 break;
538 default:
539 btstack_assert(false);
540 break;
541 }
542
543 }
544
mesh_upper_transport_validate_access_message(void)545 static void mesh_upper_transport_validate_access_message(void){
546 uint8_t transmic_len = ((incoming_access_decrypted->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
547 uint8_t * upper_transport_pdu_data = incoming_access_decrypted->data;
548 uint8_t upper_transport_pdu_len = incoming_access_decrypted->len - transmic_len;
549
550 if (!mesh_transport_key_and_virtual_address_iterator_has_more(&mesh_transport_key_it)){
551 printf("No valid transport key found\n");
552 mesh_upper_transport_process_access_message_done(incoming_access_decrypted);
553 return;
554 }
555 mesh_transport_key_and_virtual_address_iterator_next(&mesh_transport_key_it);
556 const mesh_transport_key_t * message_key = mesh_transport_key_it.key;
557
558 if (message_key->akf){
559 transport_segmented_setup_application_nonce(application_nonce, (mesh_pdu_t *) incoming_access_decrypted);
560 } else {
561 transport_segmented_setup_device_nonce(application_nonce, (mesh_pdu_t *) incoming_access_decrypted);
562 }
563
564 // store application / device key index
565 mesh_print_hex("AppOrDevKey", message_key->key, 16);
566 incoming_access_decrypted->appkey_index = message_key->appkey_index;
567
568 mesh_print_hex("EncAccessPayload", upper_transport_pdu_data, upper_transport_pdu_len);
569
570 // decrypt ccm
571 crypto_active = 1;
572 uint16_t aad_len = 0;
573 if (mesh_network_address_virtual(incoming_access_decrypted->dst)){
574 aad_len = 16;
575 }
576 btstack_crypto_ccm_init(&ccm, message_key->key, application_nonce, upper_transport_pdu_len, aad_len, transmic_len);
577
578 if (aad_len){
579 btstack_crypto_ccm_digest(&ccm, (uint8_t *) mesh_transport_key_it.address->label_uuid, aad_len,
580 &mesh_upper_transport_validate_access_message_digest, NULL);
581 } else {
582 mesh_upper_transport_validate_access_message_digest(NULL);
583 }
584 }
585
mesh_upper_transport_process_access_message(void)586 static void mesh_upper_transport_process_access_message(void){
587 uint8_t transmic_len = ((incoming_access_decrypted->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
588 uint8_t * upper_transport_pdu = incoming_access_decrypted->data;
589 uint8_t upper_transport_pdu_len = incoming_access_decrypted->len - transmic_len;
590 mesh_print_hex("Upper Transport pdu", upper_transport_pdu, upper_transport_pdu_len);
591
592 uint8_t aid = incoming_access_decrypted->akf_aid_control & 0x3f;
593 uint8_t akf = (incoming_access_decrypted->akf_aid_control & 0x40) >> 6;
594
595 printf("AKF: %u\n", akf);
596 printf("AID: %02x\n", aid);
597
598 mesh_transport_key_and_virtual_address_iterator_init(&mesh_transport_key_it, incoming_access_decrypted->dst,
599 incoming_access_decrypted->netkey_index, akf, aid);
600 mesh_upper_transport_validate_access_message();
601 }
602
mesh_upper_transport_message_received(mesh_pdu_t * pdu)603 static void mesh_upper_transport_message_received(mesh_pdu_t * pdu){
604 btstack_linked_list_add_tail(&upper_transport_incoming, (btstack_linked_item_t*) pdu);
605 mesh_upper_transport_run();
606 }
607
mesh_upper_transport_send_access_segmented(mesh_upper_transport_pdu_t * upper_pdu)608 static void mesh_upper_transport_send_access_segmented(mesh_upper_transport_pdu_t * upper_pdu){
609
610 mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) upper_pdu->lower_pdu;
611 segmented_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENTED;
612
613 // convert mesh_access_pdu_t into mesh_segmented_pdu_t
614 btstack_linked_list_t free_segments = segmented_pdu->segments;
615 segmented_pdu->segments = NULL;
616 mesh_segmented_store_payload(incoming_pdu_singleton.access.data, upper_pdu->len, &free_segments, &segmented_pdu->segments);
617
618 // copy meta
619 segmented_pdu->len = upper_pdu->len;
620 segmented_pdu->netkey_index = upper_pdu->netkey_index;
621 segmented_pdu->akf_aid_control = upper_pdu->akf_aid_control;
622 segmented_pdu->flags = upper_pdu->flags;
623
624 // setup segmented_pdu header
625 // (void)memcpy(segmented_pdu->network_header, upper_pdu->network_header, 9);
626 // TODO: use fields in mesh_segmented_pdu_t and setup network header in lower transport
627 segmented_pdu->ivi_nid = upper_pdu->ivi_nid;
628 segmented_pdu->ctl_ttl = upper_pdu->ctl_ttl;
629 segmented_pdu->seq = upper_pdu->seq;
630 segmented_pdu->src = upper_pdu->src;
631 segmented_pdu->dst = upper_pdu->dst;
632
633 // queue up
634 upper_pdu->lower_pdu = (mesh_pdu_t *) segmented_pdu;
635 btstack_linked_list_add(&upper_transport_outgoing_active, (btstack_linked_item_t *) upper_pdu);
636
637 mesh_lower_transport_send_pdu((mesh_pdu_t*) segmented_pdu);
638 }
639
mesh_upper_transport_send_access_unsegmented(mesh_upper_transport_pdu_t * upper_pdu)640 static void mesh_upper_transport_send_access_unsegmented(mesh_upper_transport_pdu_t * upper_pdu){
641
642 // provide segment
643 mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) upper_pdu->lower_pdu;
644
645 // setup network pdu
646 network_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS;
647 network_pdu->data[0] = upper_pdu->ivi_nid;
648 network_pdu->data[1] = upper_pdu->ctl_ttl;
649 big_endian_store_24(network_pdu->data, 2, upper_pdu->seq);
650 big_endian_store_16(network_pdu->data, 5, upper_pdu->src);
651 big_endian_store_16(network_pdu->data, 7, upper_pdu->dst);
652 network_pdu->netkey_index = upper_pdu->netkey_index;
653
654 // setup access message
655 network_pdu->data[9] = upper_pdu->akf_aid_control;
656 btstack_assert(upper_pdu->len < 15);
657 (void)memcpy(&network_pdu->data[10], &incoming_pdu_singleton.access.data, upper_pdu->len);
658 network_pdu->len = 10 + upper_pdu->len;
659 network_pdu->flags = 0;
660
661 // queue up
662 btstack_linked_list_add(&upper_transport_outgoing_active, (btstack_linked_item_t *) upper_pdu);
663
664 mesh_lower_transport_send_pdu((mesh_pdu_t*) network_pdu);
665 }
666
mesh_upper_transport_send_access_ccm(void * arg)667 static void mesh_upper_transport_send_access_ccm(void * arg){
668 crypto_active = 0;
669
670 mesh_upper_transport_pdu_t * upper_pdu = (mesh_upper_transport_pdu_t *) arg;
671 mesh_print_hex("EncAccessPayload", incoming_pdu_singleton.access.data, upper_pdu->len);
672 // store TransMIC
673 btstack_crypto_ccm_get_authentication_value(&ccm, &incoming_pdu_singleton.access.data[upper_pdu->len]);
674 uint8_t transmic_len = ((upper_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
675 mesh_print_hex("TransMIC", &incoming_pdu_singleton.access.data[upper_pdu->len], transmic_len);
676 upper_pdu->len += transmic_len;
677 mesh_print_hex("UpperTransportPDU", incoming_pdu_singleton.access.data, upper_pdu->len);
678 switch (upper_pdu->pdu_header.pdu_type){
679 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
680 mesh_upper_transport_send_access_unsegmented(upper_pdu);
681 break;
682 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
683 mesh_upper_transport_send_access_segmented(upper_pdu);
684 break;
685 default:
686 btstack_assert(false);
687 }
688 }
689
mesh_upper_transport_send_access_digest(void * arg)690 static void mesh_upper_transport_send_access_digest(void *arg){
691 mesh_upper_transport_pdu_t * upper_pdu = (mesh_upper_transport_pdu_t *) arg;
692 uint16_t access_pdu_len = upper_pdu->len;
693 btstack_crypto_ccm_encrypt_block(&ccm, access_pdu_len, incoming_pdu_singleton.access.data, incoming_pdu_singleton.access.data,
694 &mesh_upper_transport_send_access_ccm, upper_pdu);
695 }
696
mesh_upper_transport_send_access(mesh_upper_transport_pdu_t * upper_pdu)697 static void mesh_upper_transport_send_access(mesh_upper_transport_pdu_t * upper_pdu){
698
699 // if dst is virtual address, lookup label uuid and hash
700 uint16_t aad_len = 0;
701 mesh_virtual_address_t * virtual_address = NULL;
702 if (mesh_network_address_virtual(upper_pdu->dst)){
703 virtual_address = mesh_virtual_address_for_pseudo_dst(upper_pdu->dst);
704 if (!virtual_address){
705 printf("No virtual address register for pseudo dst %4x\n", upper_pdu->dst);
706 mesh_access_message_handler(MESH_TRANSPORT_PDU_SENT, MESH_TRANSPORT_STATUS_SEND_FAILED, (mesh_pdu_t *) upper_pdu);
707 return;
708 }
709 // printf("Using hash %4x with LabelUUID: ", virtual_address->hash);
710 // printf_hexdump(virtual_address->label_uuid, 16);
711 aad_len = 16;
712 upper_pdu->dst = virtual_address->hash;
713 }
714
715 // get app or device key
716 uint16_t appkey_index = upper_pdu->appkey_index;
717 const mesh_transport_key_t * appkey = mesh_upper_transport_get_outgoing_appkey(upper_pdu->netkey_index, appkey_index);
718 if (appkey == NULL){
719 printf("AppKey %04x not found, drop message\n", appkey_index);
720 mesh_access_message_handler(MESH_TRANSPORT_PDU_SENT, MESH_TRANSPORT_STATUS_SEND_FAILED, (mesh_pdu_t *) upper_pdu);
721 return;
722 }
723
724 // reserve slot
725 mesh_lower_transport_reserve_slot();
726
727 // reserve one sequence number, which is also used to encrypt access payload
728 uint32_t seq = mesh_sequence_number_next();
729 upper_pdu->flags |= MESH_TRANSPORT_FLAG_SEQ_RESERVED;
730 upper_pdu->seq = seq;
731
732 // also reserves crypto_buffer
733 crypto_active = 1;
734
735 // flatten segmented pdu into crypto buffer
736 uint16_t payload_len = mesh_upper_pdu_flatten(upper_pdu, incoming_pdu_singleton.access.data, sizeof(incoming_pdu_singleton.access.data));
737 btstack_assert(payload_len == upper_pdu->len);
738 UNUSED(payload_len);
739
740 // Dump PDU
741 printf("[+] Upper transport, send upper (un)segmented Access PDU - dest %04x, seq %06" PRIx32 "\n", upper_pdu->dst, upper_pdu->seq);
742 mesh_print_hex("Access Payload", incoming_pdu_singleton.access.data, upper_pdu->len);
743
744 // setup nonce - uses dst, so after pseudo address translation
745 if (appkey_index == MESH_DEVICE_KEY_INDEX){
746 transport_segmented_setup_device_nonce(application_nonce, (mesh_pdu_t *) upper_pdu);
747 } else {
748 transport_segmented_setup_application_nonce(application_nonce, (mesh_pdu_t *) upper_pdu);
749 }
750
751 // Dump key
752 mesh_print_hex("AppOrDevKey", appkey->key, 16);
753
754 // encrypt ccm
755 uint8_t transmic_len = ((upper_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
756 uint16_t access_pdu_len = upper_pdu->len;
757 btstack_crypto_ccm_init(&ccm, appkey->key, application_nonce, access_pdu_len, aad_len, transmic_len);
758 if (virtual_address){
759 mesh_print_hex("LabelUUID", virtual_address->label_uuid, 16);
760 btstack_crypto_ccm_digest(&ccm, virtual_address->label_uuid, 16,
761 &mesh_upper_transport_send_access_digest, upper_pdu);
762 } else {
763 mesh_upper_transport_send_access_digest(upper_pdu);
764 }
765 }
766
mesh_upper_transport_send_unsegmented_control_pdu(mesh_network_pdu_t * network_pdu)767 static void mesh_upper_transport_send_unsegmented_control_pdu(mesh_network_pdu_t * network_pdu){
768 // reserve slot
769 mesh_lower_transport_reserve_slot();
770 // reserve sequence number
771 uint32_t seq = mesh_sequence_number_next();
772 mesh_network_pdu_set_seq(network_pdu, seq);
773 // Dump PDU
774 uint8_t opcode = network_pdu->data[9];
775 printf("[+] Upper transport, send unsegmented Control PDU %p - seq %06" PRIx32 " opcode %02x\n", network_pdu, seq, opcode);
776 mesh_print_hex("Access Payload", &network_pdu->data[10], network_pdu->len - 10);
777
778 // send
779 mesh_lower_transport_send_pdu((mesh_pdu_t *) network_pdu);
780 }
781
mesh_upper_transport_send_segmented_control_pdu(mesh_upper_transport_pdu_t * upper_pdu)782 static void mesh_upper_transport_send_segmented_control_pdu(mesh_upper_transport_pdu_t * upper_pdu){
783 // reserve slot
784 mesh_lower_transport_reserve_slot();
785 // reserve sequence number
786 uint32_t seq = mesh_sequence_number_next();
787 upper_pdu->flags |= MESH_TRANSPORT_FLAG_SEQ_RESERVED;
788 upper_pdu->seq = seq;
789 // Dump PDU
790 // uint8_t opcode = upper_pdu->data[0];
791 // printf("[+] Upper transport, send segmented Control PDU %p - seq %06x opcode %02x\n", upper_pdu, seq, opcode);
792 // mesh_print_hex("Access Payload", &upper_pdu->data[1], upper_pdu->len - 1);
793 // send
794 mesh_segmented_pdu_t * segmented_pdu = (mesh_segmented_pdu_t *) upper_pdu->lower_pdu;
795 segmented_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENTED;
796
797 // lend segments to lower transport pdu
798 segmented_pdu->segments = upper_pdu->segments;
799 upper_pdu->segments = NULL;
800
801 // copy meta
802 segmented_pdu->len = upper_pdu->len;
803 segmented_pdu->netkey_index = upper_pdu->netkey_index;
804 segmented_pdu->akf_aid_control = upper_pdu->akf_aid_control;
805 segmented_pdu->flags = upper_pdu->flags;
806
807 btstack_assert((upper_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) == 0);
808
809 // setup segmented_pdu header
810 // TODO: use fields in mesh_segmented_pdu_t and setup network header in lower transport
811 segmented_pdu->ivi_nid = upper_pdu->ivi_nid;
812 segmented_pdu->ctl_ttl = upper_pdu->ctl_ttl;
813 segmented_pdu->seq = upper_pdu->seq;
814 segmented_pdu->src = upper_pdu->src;
815 segmented_pdu->dst = upper_pdu->dst;
816
817 // queue up
818 upper_pdu->lower_pdu = (mesh_pdu_t *) segmented_pdu;
819 btstack_linked_list_add(&upper_transport_outgoing_active, (btstack_linked_item_t *) upper_pdu);
820
821 mesh_lower_transport_send_pdu((mesh_pdu_t *) segmented_pdu);
822 }
823
mesh_upper_transport_run(void)824 static void mesh_upper_transport_run(void){
825
826 while(!btstack_linked_list_empty(&upper_transport_incoming)){
827
828 if (crypto_active) return;
829
830 // get next message
831 mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_pop(&upper_transport_incoming);
832 mesh_network_pdu_t * network_pdu;
833 mesh_segmented_pdu_t * segmented_pdu;
834 switch (pdu->pdu_type){
835 case MESH_PDU_TYPE_UNSEGMENTED:
836 network_pdu = (mesh_network_pdu_t *) pdu;
837 // control?
838 if (mesh_network_control(network_pdu)) {
839
840 incoming_control_pdu = &incoming_pdu_singleton.control;
841 incoming_control_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_CONTROL;
842 incoming_control_pdu->len = network_pdu->len;
843 incoming_control_pdu->netkey_index = network_pdu->netkey_index;
844
845 uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu);
846
847 incoming_control_pdu->akf_aid_control = lower_transport_pdu[0];
848 incoming_control_pdu->len = network_pdu->len - 10; // 9 header + 1 opcode
849 (void)memcpy(incoming_control_pdu->data, &lower_transport_pdu[1], incoming_control_pdu->len);
850
851 // copy meta data into encrypted pdu buffer
852 incoming_control_pdu->ivi_nid = network_pdu->data[0];
853 incoming_control_pdu->ctl_ttl = network_pdu->data[1];
854 incoming_control_pdu->seq = big_endian_read_24(network_pdu->data, 2);
855 incoming_control_pdu->src = big_endian_read_16(network_pdu->data, 5);
856 incoming_control_pdu->dst = big_endian_read_16(network_pdu->data, 7);
857
858 mesh_print_hex("Assembled payload", incoming_control_pdu->data, incoming_control_pdu->len);
859
860 // free mesh message
861 mesh_lower_transport_message_processed_by_higher_layer(pdu);
862
863 btstack_assert(mesh_control_message_handler != NULL);
864 mesh_control_message_handler(MESH_TRANSPORT_PDU_RECEIVED, MESH_TRANSPORT_STATUS_SUCCESS, (mesh_pdu_t*) incoming_control_pdu);
865
866 } else {
867
868 incoming_access_encrypted = (mesh_pdu_t *) network_pdu;
869
870 incoming_access_decrypted = &incoming_pdu_singleton.access;
871 incoming_access_decrypted->pdu_header.pdu_type = MESH_PDU_TYPE_ACCESS;
872 incoming_access_decrypted->flags = 0;
873 incoming_access_decrypted->netkey_index = network_pdu->netkey_index;
874 incoming_access_decrypted->akf_aid_control = network_pdu->data[9];
875 incoming_access_decrypted->len = network_pdu->len - 10; // 9 header + 1 AID
876 incoming_access_decrypted->ivi_nid = network_pdu->data[0];
877 incoming_access_decrypted->ctl_ttl = network_pdu->data[1];
878 incoming_access_decrypted->seq = big_endian_read_24(network_pdu->data, 2);
879 incoming_access_decrypted->src = big_endian_read_16(network_pdu->data, 5);
880 incoming_access_decrypted->dst = big_endian_read_16(network_pdu->data, 7);
881
882 mesh_upper_transport_process_access_message();
883 }
884 break;
885 case MESH_PDU_TYPE_SEGMENTED:
886 segmented_pdu = (mesh_segmented_pdu_t *) pdu;
887 uint8_t ctl = segmented_pdu->ctl_ttl >> 7;
888 if (ctl){
889 incoming_control_pdu= &incoming_pdu_singleton.control;
890 incoming_control_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_CONTROL;
891
892 // flatten
893 mesh_segmented_pdu_flatten(&segmented_pdu->segments, 8, incoming_control_pdu->data);
894
895 // copy meta data into encrypted pdu buffer
896 incoming_control_pdu->flags = 0;
897 incoming_control_pdu->len = segmented_pdu->len;
898 incoming_control_pdu->netkey_index = segmented_pdu->netkey_index;
899 incoming_control_pdu->akf_aid_control = segmented_pdu->akf_aid_control;
900 incoming_control_pdu->ivi_nid = segmented_pdu->ivi_nid;
901 incoming_control_pdu->ctl_ttl = segmented_pdu->ctl_ttl;
902 incoming_control_pdu->seq = segmented_pdu->seq;
903 incoming_control_pdu->src = segmented_pdu->src;
904 incoming_control_pdu->dst = segmented_pdu->dst;
905
906 mesh_print_hex("Assembled payload", incoming_control_pdu->data, incoming_control_pdu->len);
907
908 // free mesh message
909 mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *)segmented_pdu);
910
911 btstack_assert(mesh_control_message_handler != NULL);
912 mesh_control_message_handler(MESH_TRANSPORT_PDU_RECEIVED, MESH_TRANSPORT_STATUS_SUCCESS, (mesh_pdu_t*) incoming_control_pdu);
913
914 } else {
915
916 incoming_access_encrypted = (mesh_pdu_t *) segmented_pdu;
917
918 incoming_access_decrypted = &incoming_pdu_singleton.access;
919 incoming_access_decrypted->pdu_header.pdu_type = MESH_PDU_TYPE_ACCESS;
920 incoming_access_decrypted->flags = segmented_pdu->flags;
921 incoming_access_decrypted->len = segmented_pdu->len;
922 incoming_access_decrypted->netkey_index = segmented_pdu->netkey_index;
923 incoming_access_decrypted->akf_aid_control = segmented_pdu->akf_aid_control;
924 incoming_access_decrypted->ivi_nid = segmented_pdu->ivi_nid;
925 incoming_access_decrypted->ctl_ttl = segmented_pdu->ctl_ttl;
926 incoming_access_decrypted->seq = segmented_pdu->seq;
927 incoming_access_decrypted->src = segmented_pdu->src;
928 incoming_access_decrypted->dst = segmented_pdu->dst;
929
930 mesh_upper_transport_process_access_message();
931 }
932 break;
933 default:
934 btstack_assert(0);
935 break;
936 }
937 }
938
939 btstack_linked_list_iterator_t it;
940 btstack_linked_list_iterator_init(&it, &upper_transport_outgoing);
941 while (btstack_linked_list_iterator_has_next(&it)){
942
943 if (crypto_active) break;
944
945 mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&it);
946 if (mesh_lower_transport_can_send_to_dest(mesh_pdu_dst(pdu)) == false) {
947 // skip pdu for now
948 continue;
949 }
950
951 mesh_upper_transport_pdu_t * upper_pdu;
952 mesh_segmented_pdu_t * segmented_pdu;
953 uint8_t transmic_len;
954 bool ok;
955 bool abort_outgoing_loop = false;
956
957 switch (pdu->pdu_type){
958 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
959 // control pdus can go through directly
960 btstack_assert(mesh_pdu_ctl(pdu) != 0);
961 btstack_linked_list_iterator_remove(&it);
962 mesh_upper_transport_send_unsegmented_control_pdu((mesh_network_pdu_t *) pdu);
963 break;
964 case MESH_PDU_TYPE_UPPER_SEGMENTED_CONTROL:
965 // control pdus can go through directly
966 btstack_assert(mesh_pdu_ctl(pdu) != 0);
967 btstack_linked_list_iterator_remove(&it);
968 mesh_upper_transport_send_segmented_control_pdu((mesh_upper_transport_pdu_t *) pdu);
969 break;
970 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
971 // segmented access pdus required a mesh-segmented-pdu
972 upper_pdu = (mesh_upper_transport_pdu_t *) pdu;
973 if (upper_pdu->lower_pdu == NULL){
974 upper_pdu->lower_pdu = (mesh_pdu_t *) btstack_memory_mesh_segmented_pdu_get();
975 }
976 if (upper_pdu->lower_pdu == NULL){
977 mesh_upper_transport_need_pdu_for_run_outgoing();
978 abort_outgoing_loop = true;
979 break;
980 }
981 segmented_pdu = (mesh_segmented_pdu_t *) upper_pdu->lower_pdu;
982 segmented_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENTED;
983 // and a mesh-network-pdu for each segment in upper pdu
984 transmic_len = ((upper_pdu->flags & MESH_TRANSPORT_FLAG_TRANSMIC_64) != 0) ? 8 : 4;
985 ok = mesh_segmented_allocate_segments(&segmented_pdu->segments, upper_pdu->len + transmic_len);
986 if (!ok) {
987 abort_outgoing_loop = true;
988 break;
989 }
990 // all buffers available, get started
991 btstack_linked_list_iterator_remove(&it);
992 mesh_upper_transport_send_access(upper_pdu);
993 break;
994 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
995 // unsegmented access pdus require a single mesh-network-dpu
996 upper_pdu = (mesh_upper_transport_pdu_t *) pdu;
997 if (upper_pdu->lower_pdu == NULL){
998 upper_pdu->lower_pdu = (mesh_pdu_t *) mesh_network_pdu_get();
999 }
1000 if (upper_pdu->lower_pdu == NULL) {
1001 mesh_upper_transport_need_pdu_for_run_outgoing();
1002 abort_outgoing_loop = true;
1003 break;
1004 }
1005 btstack_linked_list_iterator_remove(&it);
1006 mesh_upper_transport_send_access((mesh_upper_transport_pdu_t *) pdu);
1007 break;
1008 default:
1009 btstack_assert(false);
1010 break;
1011 }
1012 if (abort_outgoing_loop) {
1013 break;
1014 }
1015 }
1016 }
1017
mesh_upper_transport_find_and_remove_pdu_for_lower(mesh_pdu_t * pdu_to_find)1018 static mesh_upper_transport_pdu_t * mesh_upper_transport_find_and_remove_pdu_for_lower(mesh_pdu_t * pdu_to_find){
1019 btstack_linked_list_iterator_t it;
1020 btstack_linked_list_iterator_init(&it, &upper_transport_outgoing_active);
1021 mesh_upper_transport_pdu_t * upper_pdu;
1022 while (btstack_linked_list_iterator_has_next(&it)){
1023 mesh_pdu_t * mesh_pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&it);
1024 switch (mesh_pdu->pdu_type){
1025 case MESH_PDU_TYPE_UPPER_SEGMENTED_CONTROL:
1026 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
1027 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
1028 upper_pdu = (mesh_upper_transport_pdu_t *) mesh_pdu;
1029 if (upper_pdu->lower_pdu == pdu_to_find){
1030 btstack_linked_list_iterator_remove(&it);
1031 return upper_pdu;
1032 }
1033 break;
1034 default:
1035 break;
1036 }
1037 }
1038 return NULL;
1039 }
1040
mesh_upper_transport_pdu_handler(mesh_transport_callback_type_t callback_type,mesh_transport_status_t status,mesh_pdu_t * pdu)1041 static void mesh_upper_transport_pdu_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){
1042 mesh_upper_transport_pdu_t * upper_pdu;
1043 mesh_segmented_pdu_t * segmented_pdu;
1044 switch (callback_type){
1045 case MESH_TRANSPORT_PDU_RECEIVED:
1046 mesh_upper_transport_message_received(pdu);
1047 break;
1048 case MESH_TRANSPORT_PDU_SENT:
1049 switch (pdu->pdu_type){
1050 case MESH_PDU_TYPE_SEGMENTED:
1051 // try to find in outgoing active
1052 upper_pdu = mesh_upper_transport_find_and_remove_pdu_for_lower(pdu);
1053 btstack_assert(upper_pdu != NULL);
1054 segmented_pdu = (mesh_segmented_pdu_t *) pdu;
1055 // free chunks
1056 while (!btstack_linked_list_empty(&segmented_pdu->segments)){
1057 mesh_network_pdu_t * chunk_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&segmented_pdu->segments);
1058 mesh_network_pdu_free(chunk_pdu);
1059 }
1060 // free segmented pdu
1061 btstack_memory_mesh_segmented_pdu_free(segmented_pdu);
1062 upper_pdu->lower_pdu = NULL;
1063 switch (upper_pdu->pdu_header.pdu_type){
1064 case MESH_PDU_TYPE_UPPER_SEGMENTED_CONTROL:
1065 mesh_control_message_handler(callback_type, status, (mesh_pdu_t *) upper_pdu);
1066 break;
1067 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
1068 mesh_access_message_handler(callback_type, status, (mesh_pdu_t *) upper_pdu);
1069 break;
1070 default:
1071 btstack_assert(false);
1072 break;
1073 }
1074 break;
1075 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
1076 // find corresponding upper transport pdu and free single segment
1077 upper_pdu = mesh_upper_transport_find_and_remove_pdu_for_lower(pdu);
1078 btstack_assert(upper_pdu != NULL);
1079 btstack_assert(upper_pdu->lower_pdu == (mesh_pdu_t *) pdu);
1080 mesh_network_pdu_free((mesh_network_pdu_t *) pdu);
1081 upper_pdu->lower_pdu = NULL;
1082 mesh_access_message_handler(callback_type, status, (mesh_pdu_t*) upper_pdu);
1083 break;
1084 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
1085 mesh_access_message_handler(callback_type, status, pdu);
1086 break;
1087 default:
1088 btstack_assert(false);
1089 break;
1090 }
1091 mesh_upper_transport_run();
1092 break;
1093 default:
1094 break;
1095 }
1096 }
1097
mesh_upper_transport_pdu_free(mesh_pdu_t * pdu)1098 void mesh_upper_transport_pdu_free(mesh_pdu_t * pdu){
1099 btstack_assert(pdu != NULL);
1100 mesh_network_pdu_t * network_pdu;
1101 mesh_segmented_pdu_t * message_pdu;
1102 mesh_upper_transport_pdu_t * upper_pdu;
1103 switch (pdu->pdu_type) {
1104 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
1105 case MESH_PDU_TYPE_NETWORK:
1106 network_pdu = (mesh_network_pdu_t *) pdu;
1107 mesh_network_pdu_free(network_pdu);
1108 break;
1109 case MESH_PDU_TYPE_SEGMENTED:
1110 message_pdu = (mesh_segmented_pdu_t *) pdu;
1111 mesh_segmented_pdu_free(message_pdu);
1112 break;
1113 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
1114 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
1115 case MESH_PDU_TYPE_UPPER_SEGMENTED_CONTROL:
1116 upper_pdu = (mesh_upper_transport_pdu_t *) pdu;
1117 while (upper_pdu->segments) {
1118 mesh_network_pdu_t *segment = (mesh_network_pdu_t *) btstack_linked_list_pop(&upper_pdu->segments);
1119 mesh_network_pdu_free(segment);
1120 }
1121 btstack_memory_mesh_upper_transport_pdu_free(upper_pdu);
1122 // check if send request can be handled now
1123 mesh_upper_transport_schedule_send_requests();
1124 break;
1125 default:
1126 btstack_assert(false);
1127 break;
1128 }
1129 }
1130
mesh_upper_transport_message_processed_by_higher_layer(mesh_pdu_t * pdu)1131 void mesh_upper_transport_message_processed_by_higher_layer(mesh_pdu_t * pdu){
1132 crypto_active = 0;
1133 switch (pdu->pdu_type){
1134 case MESH_PDU_TYPE_ACCESS:
1135 mesh_upper_transport_process_access_message_done((mesh_access_pdu_t *) pdu);
1136 break;
1137 case MESH_PDU_TYPE_CONTROL:
1138 mesh_upper_transport_process_control_message_done((mesh_control_pdu_t *) pdu);
1139 break;
1140 default:
1141 btstack_assert(0);
1142 break;
1143 }
1144 }
1145
mesh_upper_transport_send_access_pdu(mesh_pdu_t * pdu)1146 void mesh_upper_transport_send_access_pdu(mesh_pdu_t *pdu){
1147 switch (pdu->pdu_type){
1148 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
1149 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
1150 break;
1151 default:
1152 btstack_assert(false);
1153 break;
1154 }
1155
1156 btstack_assert(((mesh_upper_transport_pdu_t *) pdu)->lower_pdu == NULL);
1157
1158 btstack_linked_list_add_tail(&upper_transport_outgoing, (btstack_linked_item_t*) pdu);
1159 mesh_upper_transport_run();
1160 }
1161
mesh_upper_transport_send_control_pdu(mesh_pdu_t * pdu)1162 void mesh_upper_transport_send_control_pdu(mesh_pdu_t * pdu){
1163 switch (pdu->pdu_type){
1164 case MESH_PDU_TYPE_UPPER_SEGMENTED_CONTROL:
1165 break;
1166 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL:
1167 btstack_assert( ((mesh_network_pdu_t *) pdu)->len >= 9);
1168 break;
1169 default:
1170 btstack_assert(false);
1171 break;
1172 }
1173
1174 btstack_linked_list_add_tail(&upper_transport_outgoing, (btstack_linked_item_t*) pdu);
1175 mesh_upper_transport_run();
1176 }
1177
mesh_upper_transport_setup_unsegmented_control_pdu(mesh_network_pdu_t * network_pdu,uint16_t netkey_index,uint8_t ttl,uint16_t src,uint16_t dest,uint8_t opcode,const uint8_t * control_pdu_data,uint16_t control_pdu_len)1178 uint8_t mesh_upper_transport_setup_unsegmented_control_pdu(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t opcode,
1179 const uint8_t * control_pdu_data, uint16_t control_pdu_len){
1180
1181 btstack_assert(network_pdu != NULL);
1182 btstack_assert(control_pdu_len <= 11);
1183
1184 const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1185 if (!network_key) return 1;
1186
1187 uint8_t transport_pdu_data[12];
1188 transport_pdu_data[0] = opcode;
1189 (void)memcpy(&transport_pdu_data[1], control_pdu_data, control_pdu_len);
1190 uint16_t transport_pdu_len = control_pdu_len + 1;
1191
1192 // setup network_pdu
1193 network_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL;
1194 mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 1, ttl, 0, src, dest, transport_pdu_data, transport_pdu_len);
1195
1196 return 0;
1197 }
1198
mesh_upper_transport_setup_segmented_control_pdu_header(mesh_upper_transport_pdu_t * upper_pdu,uint16_t netkey_index,uint8_t ttl,uint16_t src,uint16_t dest,uint8_t opcode)1199 uint8_t mesh_upper_transport_setup_segmented_control_pdu_header(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t opcode){
1200
1201 const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1202 if (!network_key) return 1;
1203
1204 upper_pdu->ivi_nid = network_key->nid | ((mesh_get_iv_index_for_tx() & 1) << 7);
1205 upper_pdu->ctl_ttl = ttl;
1206 upper_pdu->src = src;
1207 upper_pdu->dst = dest;
1208 upper_pdu->netkey_index = netkey_index;
1209 upper_pdu->akf_aid_control = opcode;
1210 return 0;
1211 }
1212
mesh_upper_transport_setup_upper_access_pdu_header(mesh_upper_transport_pdu_t * upper_pdu,uint16_t netkey_index,uint16_t appkey_index,uint8_t ttl,uint16_t src,uint16_t dest,uint8_t szmic)1213 static uint8_t mesh_upper_transport_setup_upper_access_pdu_header(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index,
1214 uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic){
1215
1216 // get app or device key
1217 const mesh_transport_key_t *appkey;
1218 appkey = mesh_transport_key_get(appkey_index);
1219 if (appkey == NULL) {
1220 printf("[!] Upper transport, setup segmented Access PDU - appkey_index %x unknown\n", appkey_index);
1221 return 1;
1222 }
1223 uint8_t akf_aid = (appkey->akf << 6) | appkey->aid;
1224
1225 // lookup network by netkey_index
1226 const mesh_network_key_t *network_key = mesh_network_key_list_get(netkey_index);
1227 if (!network_key) return 1;
1228 if (network_key == NULL) {
1229 printf("[!] Upper transport, setup segmented Access PDU - netkey_index %x unknown\n", appkey_index);
1230 return 1;
1231 }
1232
1233 // store in transport pdu
1234 upper_pdu->ivi_nid = network_key->nid | ((mesh_get_iv_index_for_tx() & 1) << 7);
1235 upper_pdu->ctl_ttl = ttl;
1236 upper_pdu->src = src;
1237 upper_pdu->dst = dest;
1238 upper_pdu->netkey_index = netkey_index;
1239 upper_pdu->appkey_index = appkey_index;
1240 upper_pdu->akf_aid_control = akf_aid;
1241 if (szmic) {
1242 upper_pdu->flags |= MESH_TRANSPORT_FLAG_TRANSMIC_64;
1243 }
1244 return 0;
1245 }
1246
mesh_upper_transport_setup_access_pdu_header(mesh_pdu_t * pdu,uint16_t netkey_index,uint16_t appkey_index,uint8_t ttl,uint16_t src,uint16_t dest,uint8_t szmic)1247 uint8_t mesh_upper_transport_setup_access_pdu_header(mesh_pdu_t * pdu, uint16_t netkey_index, uint16_t appkey_index,
1248 uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic){
1249 switch (pdu->pdu_type){
1250 case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
1251 case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
1252 return mesh_upper_transport_setup_upper_access_pdu_header((mesh_upper_transport_pdu_t *) pdu, netkey_index,
1253 appkey_index, ttl, src, dest, szmic);
1254 default:
1255 btstack_assert(false);
1256 return 1;
1257 }
1258 }
1259
mesh_upper_transport_register_access_message_handler(void (* callback)(mesh_transport_callback_type_t callback_type,mesh_transport_status_t status,mesh_pdu_t * pdu))1260 void mesh_upper_transport_register_access_message_handler(void (*callback)(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu)) {
1261 mesh_access_message_handler = callback;
1262 }
1263
mesh_upper_transport_register_control_message_handler(void (* callback)(mesh_transport_callback_type_t callback_type,mesh_transport_status_t status,mesh_pdu_t * pdu))1264 void mesh_upper_transport_register_control_message_handler(void (*callback)(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu)){
1265 mesh_control_message_handler = callback;
1266 }
1267
mesh_upper_transport_init()1268 void mesh_upper_transport_init(){
1269 mesh_lower_transport_set_higher_layer_handler(&mesh_upper_transport_pdu_handler);
1270 }
1271
mesh_upper_transport_message_reserve(void)1272 bool mesh_upper_transport_message_reserve(void){
1273 if (message_builder_reserved_upper_pdu == NULL){
1274 message_builder_reserved_upper_pdu = btstack_memory_mesh_upper_transport_pdu_get();
1275 }
1276 if (message_builder_reserved_upper_pdu == NULL){
1277 return false;
1278 }
1279 while (message_builder_num_network_pdus_reserved < MESSAGE_BUILDER_MAX_NUM_NETWORK_PDUS){
1280 mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
1281 if (network_pdu == NULL){
1282 return false;
1283 }
1284 btstack_linked_list_add(&message_builder_reserved_network_pdus, (btstack_linked_item_t *) network_pdu);
1285 message_builder_num_network_pdus_reserved++;
1286 }
1287 return true;
1288 }
1289
mesh_upper_transport_message_init(mesh_upper_transport_builder_t * builder,mesh_pdu_type_t pdu_type)1290 void mesh_upper_transport_message_init(mesh_upper_transport_builder_t * builder, mesh_pdu_type_t pdu_type) {
1291 btstack_assert(builder != NULL);
1292
1293 // use reserved buffer if available
1294 if (message_builder_reserved_upper_pdu != NULL){
1295 builder->pdu = message_builder_reserved_upper_pdu;
1296 message_builder_reserved_upper_pdu = NULL;
1297 } else {
1298 builder->pdu = btstack_memory_mesh_upper_transport_pdu_get();
1299 }
1300 if (!builder->pdu) return;
1301
1302 builder->segment = NULL;
1303 builder->pdu->pdu_header.pdu_type = pdu_type;
1304 builder->pdu->ack_opcode = MESH_ACCESS_OPCODE_NOT_SET;
1305 }
1306
1307
mesh_upper_transport_message_add_data(mesh_upper_transport_builder_t * builder,const uint8_t * data,uint16_t data_len)1308 void mesh_upper_transport_message_add_data(mesh_upper_transport_builder_t * builder, const uint8_t * data, uint16_t data_len){
1309 btstack_assert(builder != NULL);
1310
1311 if (builder->pdu == NULL) return;
1312
1313 builder->pdu->len += data_len;
1314
1315 uint16_t bytes_current_segment = 0;
1316 if (builder->segment){
1317 bytes_current_segment = MESH_NETWORK_PAYLOAD_MAX - builder->segment->len;
1318 }
1319 while (data_len > 0){
1320 if (bytes_current_segment == 0){
1321 // use reserved buffer if available
1322 if (message_builder_num_network_pdus_reserved > 0){
1323 message_builder_num_network_pdus_reserved--;
1324 builder->segment = (mesh_network_pdu_t *) btstack_linked_list_pop(&message_builder_reserved_network_pdus);
1325 } else {
1326 builder->segment = (mesh_network_pdu_t *) mesh_network_pdu_get();
1327 }
1328 if (builder->segment == NULL) {
1329 mesh_upper_transport_pdu_free((mesh_pdu_t *) builder->pdu);
1330 builder->pdu = NULL;
1331 return;
1332 }
1333 btstack_linked_list_add_tail(&builder->pdu->segments, (btstack_linked_item_t *) builder->segment);
1334 bytes_current_segment = MESH_NETWORK_PAYLOAD_MAX;
1335 }
1336 uint16_t bytes_to_copy = btstack_min(bytes_current_segment, data_len);
1337 (void) memcpy(&builder->segment->data[builder->segment->len], data, bytes_to_copy);
1338 builder->segment->len += bytes_to_copy;
1339 bytes_current_segment -= bytes_to_copy;
1340 data += bytes_to_copy;
1341 data_len -= bytes_to_copy;
1342 }
1343 }
1344
mesh_upper_transport_message_add_uint8(mesh_upper_transport_builder_t * builder,uint8_t value)1345 void mesh_upper_transport_message_add_uint8(mesh_upper_transport_builder_t * builder, uint8_t value){
1346 mesh_upper_transport_message_add_data(builder, &value, 1);
1347 }
1348
mesh_upper_transport_message_add_uint16(mesh_upper_transport_builder_t * builder,uint16_t value)1349 void mesh_upper_transport_message_add_uint16(mesh_upper_transport_builder_t * builder, uint16_t value){
1350 uint8_t buffer[2];
1351 little_endian_store_16(buffer, 0, value);
1352 mesh_upper_transport_message_add_data(builder, buffer, sizeof(buffer));
1353 }
1354
mesh_upper_transport_message_add_uint24(mesh_upper_transport_builder_t * builder,uint32_t value)1355 void mesh_upper_transport_message_add_uint24(mesh_upper_transport_builder_t * builder, uint32_t value){
1356 uint8_t buffer[3];
1357 little_endian_store_24(buffer, 0, value);
1358 mesh_upper_transport_message_add_data(builder, buffer, sizeof(buffer));
1359 }
1360
mesh_upper_transport_message_add_uint32(mesh_upper_transport_builder_t * builder,uint32_t value)1361 void mesh_upper_transport_message_add_uint32(mesh_upper_transport_builder_t * builder, uint32_t value){
1362 uint8_t buffer[4];
1363 little_endian_store_32(buffer, 0, value);
1364 mesh_upper_transport_message_add_data(builder, buffer, sizeof(buffer));
1365 }
1366
mesh_upper_transport_message_finalize(mesh_upper_transport_builder_t * builder)1367 mesh_upper_transport_pdu_t * mesh_upper_transport_message_finalize(mesh_upper_transport_builder_t * builder){
1368 return builder->pdu;
1369 }
1370