1*77ba3d3fSMatthias Ringwald /* 2*77ba3d3fSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*77ba3d3fSMatthias Ringwald * 4*77ba3d3fSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*77ba3d3fSMatthias Ringwald * modification, are permitted provided that the following conditions 6*77ba3d3fSMatthias Ringwald * are met: 7*77ba3d3fSMatthias Ringwald * 8*77ba3d3fSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*77ba3d3fSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*77ba3d3fSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*77ba3d3fSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*77ba3d3fSMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*77ba3d3fSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*77ba3d3fSMatthias Ringwald * contributors may be used to endorse or promote products derived 15*77ba3d3fSMatthias Ringwald * from this software without specific prior written permission. 16*77ba3d3fSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*77ba3d3fSMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*77ba3d3fSMatthias Ringwald * monetary gain. 19*77ba3d3fSMatthias Ringwald * 20*77ba3d3fSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*77ba3d3fSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*77ba3d3fSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*77ba3d3fSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*77ba3d3fSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*77ba3d3fSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*77ba3d3fSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*77ba3d3fSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*77ba3d3fSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*77ba3d3fSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*77ba3d3fSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*77ba3d3fSMatthias Ringwald * SUCH DAMAGE. 32*77ba3d3fSMatthias Ringwald * 33*77ba3d3fSMatthias Ringwald * Please inquire about commercial licensing options at 34*77ba3d3fSMatthias Ringwald * [email protected] 35*77ba3d3fSMatthias Ringwald * 36*77ba3d3fSMatthias Ringwald */ 37*77ba3d3fSMatthias Ringwald 38*77ba3d3fSMatthias Ringwald #define __BTSTACK_FILE__ "mesh_transport.c" 39*77ba3d3fSMatthias Ringwald 40*77ba3d3fSMatthias Ringwald #include <stdio.h> 41*77ba3d3fSMatthias Ringwald #include <stdlib.h> 42*77ba3d3fSMatthias Ringwald #include <string.h> 43*77ba3d3fSMatthias Ringwald #include "mesh/beacon.h" 44*77ba3d3fSMatthias Ringwald #include "mesh/mesh_lower_transport.h" 45*77ba3d3fSMatthias Ringwald #include "mesh/mesh_upper_transport.h" 46*77ba3d3fSMatthias Ringwald #include "btstack_util.h" 47*77ba3d3fSMatthias Ringwald #include "btstack_memory.h" 48*77ba3d3fSMatthias Ringwald #include "mesh_peer.h" 49*77ba3d3fSMatthias Ringwald #include "mesh_keys.h" 50*77ba3d3fSMatthias Ringwald #include "mesh_virtual_addresses.h" 51*77ba3d3fSMatthias Ringwald 52*77ba3d3fSMatthias Ringwald static uint16_t primary_element_address; 53*77ba3d3fSMatthias Ringwald 54*77ba3d3fSMatthias Ringwald static void (*higher_layer_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu); 55*77ba3d3fSMatthias Ringwald 56*77ba3d3fSMatthias Ringwald static void mesh_print_hex(const char * name, const uint8_t * data, uint16_t len){ 57*77ba3d3fSMatthias Ringwald printf("%-20s ", name); 58*77ba3d3fSMatthias Ringwald printf_hexdump(data, len); 59*77ba3d3fSMatthias Ringwald } 60*77ba3d3fSMatthias Ringwald // static void mesh_print_x(const char * name, uint32_t value){ 61*77ba3d3fSMatthias Ringwald // printf("%20s: 0x%x", name, (int) value); 62*77ba3d3fSMatthias Ringwald // } 63*77ba3d3fSMatthias Ringwald 64*77ba3d3fSMatthias Ringwald 65*77ba3d3fSMatthias Ringwald // combined key x address iterator for upper transport decryption 66*77ba3d3fSMatthias Ringwald 67*77ba3d3fSMatthias Ringwald typedef struct { 68*77ba3d3fSMatthias Ringwald // state 69*77ba3d3fSMatthias Ringwald mesh_transport_key_iterator_t key_it; 70*77ba3d3fSMatthias Ringwald mesh_virtual_address_iterator_t address_it; 71*77ba3d3fSMatthias Ringwald // elements 72*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * key; 73*77ba3d3fSMatthias Ringwald const mesh_virtual_address_t * address; 74*77ba3d3fSMatthias Ringwald // address - might be virtual 75*77ba3d3fSMatthias Ringwald uint16_t dst; 76*77ba3d3fSMatthias Ringwald // key info 77*77ba3d3fSMatthias Ringwald } mesh_transport_key_and_virtual_address_iterator_t; 78*77ba3d3fSMatthias Ringwald 79*77ba3d3fSMatthias Ringwald static void mesh_transport_key_and_virtual_address_iterator_init(mesh_transport_key_and_virtual_address_iterator_t *it, 80*77ba3d3fSMatthias Ringwald uint16_t dst, uint16_t netkey_index, uint8_t akf, 81*77ba3d3fSMatthias Ringwald uint8_t aid) { 82*77ba3d3fSMatthias Ringwald printf("KEY_INIT: dst %04x, akf %x, aid %x\n", dst, akf, aid); 83*77ba3d3fSMatthias Ringwald // config 84*77ba3d3fSMatthias Ringwald it->dst = dst; 85*77ba3d3fSMatthias Ringwald // init elements 86*77ba3d3fSMatthias Ringwald it->key = NULL; 87*77ba3d3fSMatthias Ringwald it->address = NULL; 88*77ba3d3fSMatthias Ringwald // init element iterators 89*77ba3d3fSMatthias Ringwald mesh_transport_key_aid_iterator_init(&it->key_it, netkey_index, akf, aid); 90*77ba3d3fSMatthias Ringwald // init address iterator 91*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(it->dst)){ 92*77ba3d3fSMatthias Ringwald mesh_virtual_address_iterator_init(&it->address_it, dst); 93*77ba3d3fSMatthias Ringwald // get first key 94*77ba3d3fSMatthias Ringwald if (mesh_transport_key_aid_iterator_has_more(&it->key_it)) { 95*77ba3d3fSMatthias Ringwald it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it); 96*77ba3d3fSMatthias Ringwald } 97*77ba3d3fSMatthias Ringwald } 98*77ba3d3fSMatthias Ringwald } 99*77ba3d3fSMatthias Ringwald 100*77ba3d3fSMatthias Ringwald // cartesian product: keys x addressses 101*77ba3d3fSMatthias Ringwald static int mesh_transport_key_and_virtual_address_iterator_has_more(mesh_transport_key_and_virtual_address_iterator_t * it){ 102*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(it->dst)) { 103*77ba3d3fSMatthias Ringwald // find next valid entry 104*77ba3d3fSMatthias Ringwald while (1){ 105*77ba3d3fSMatthias Ringwald if (mesh_virtual_address_iterator_has_more(&it->address_it)) return 1; 106*77ba3d3fSMatthias Ringwald if (!mesh_transport_key_aid_iterator_has_more(&it->key_it)) return 0; 107*77ba3d3fSMatthias Ringwald // get next key 108*77ba3d3fSMatthias Ringwald it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it); 109*77ba3d3fSMatthias Ringwald mesh_virtual_address_iterator_init(&it->address_it, it->dst); 110*77ba3d3fSMatthias Ringwald } 111*77ba3d3fSMatthias Ringwald } else { 112*77ba3d3fSMatthias Ringwald return mesh_transport_key_aid_iterator_has_more(&it->key_it); 113*77ba3d3fSMatthias Ringwald } 114*77ba3d3fSMatthias Ringwald } 115*77ba3d3fSMatthias Ringwald 116*77ba3d3fSMatthias Ringwald static void mesh_transport_key_and_virtual_address_iterator_next(mesh_transport_key_and_virtual_address_iterator_t * it){ 117*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(it->dst)) { 118*77ba3d3fSMatthias Ringwald it->address = mesh_virtual_address_iterator_get_next(&it->address_it); 119*77ba3d3fSMatthias Ringwald } else { 120*77ba3d3fSMatthias Ringwald it->key = mesh_transport_key_aid_iterator_get_next(&it->key_it); 121*77ba3d3fSMatthias Ringwald } 122*77ba3d3fSMatthias Ringwald } 123*77ba3d3fSMatthias Ringwald 124*77ba3d3fSMatthias Ringwald // UPPER TRANSPORT 125*77ba3d3fSMatthias Ringwald 126*77ba3d3fSMatthias Ringwald // stub lower transport 127*77ba3d3fSMatthias Ringwald 128*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_unsegmented_message(mesh_network_pdu_t * network_pdu); 129*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_segmented_message(mesh_transport_pdu_t * transport_pdu); 130*77ba3d3fSMatthias Ringwald 131*77ba3d3fSMatthias Ringwald static void mesh_transport_run(void); 132*77ba3d3fSMatthias Ringwald 133*77ba3d3fSMatthias Ringwald static int crypto_active; 134*77ba3d3fSMatthias Ringwald static mesh_network_pdu_t * network_pdu_in_validation; 135*77ba3d3fSMatthias Ringwald static mesh_transport_pdu_t * transport_pdu_in_validation; 136*77ba3d3fSMatthias Ringwald static uint8_t application_nonce[13]; 137*77ba3d3fSMatthias Ringwald static btstack_crypto_ccm_t ccm; 138*77ba3d3fSMatthias Ringwald static mesh_transport_key_and_virtual_address_iterator_t mesh_transport_key_it; 139*77ba3d3fSMatthias Ringwald 140*77ba3d3fSMatthias Ringwald // upper transport callbacks - in access layer 141*77ba3d3fSMatthias Ringwald static void (*mesh_access_message_handler)(mesh_pdu_t * pdu); 142*77ba3d3fSMatthias Ringwald static void (*mesh_control_message_handler)(mesh_pdu_t * pdu); 143*77ba3d3fSMatthias Ringwald 144*77ba3d3fSMatthias Ringwald // unsegmented (network) and segmented (transport) control and access messages 145*77ba3d3fSMatthias Ringwald static btstack_linked_list_t upper_transport_incoming; 146*77ba3d3fSMatthias Ringwald 147*77ba3d3fSMatthias Ringwald 148*77ba3d3fSMatthias Ringwald void mesh_upper_unsegmented_control_message_received(mesh_network_pdu_t * network_pdu){ 149*77ba3d3fSMatthias Ringwald uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); 150*77ba3d3fSMatthias Ringwald uint8_t opcode = lower_transport_pdu[0]; 151*77ba3d3fSMatthias Ringwald if (mesh_control_message_handler){ 152*77ba3d3fSMatthias Ringwald mesh_control_message_handler((mesh_pdu_t*) network_pdu); 153*77ba3d3fSMatthias Ringwald } else { 154*77ba3d3fSMatthias Ringwald printf("[!] Unhandled Control message with opcode %02x\n", opcode); 155*77ba3d3fSMatthias Ringwald // done 156*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *) network_pdu); 157*77ba3d3fSMatthias Ringwald } 158*77ba3d3fSMatthias Ringwald } 159*77ba3d3fSMatthias Ringwald 160*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_process_unsegmented_message_done(mesh_network_pdu_t *network_pdu){ 161*77ba3d3fSMatthias Ringwald crypto_active = 0; 162*77ba3d3fSMatthias Ringwald if (mesh_network_control(network_pdu)) { 163*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *) network_pdu); 164*77ba3d3fSMatthias Ringwald } else { 165*77ba3d3fSMatthias Ringwald mesh_network_pdu_free(network_pdu); 166*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *) network_pdu_in_validation); 167*77ba3d3fSMatthias Ringwald network_pdu_in_validation = NULL; 168*77ba3d3fSMatthias Ringwald } 169*77ba3d3fSMatthias Ringwald mesh_transport_run(); 170*77ba3d3fSMatthias Ringwald } 171*77ba3d3fSMatthias Ringwald 172*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_process_segmented_message_done(mesh_transport_pdu_t *transport_pdu){ 173*77ba3d3fSMatthias Ringwald crypto_active = 0; 174*77ba3d3fSMatthias Ringwald if (mesh_transport_ctl(transport_pdu)) { 175*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *)transport_pdu); 176*77ba3d3fSMatthias Ringwald } else { 177*77ba3d3fSMatthias Ringwald mesh_transport_pdu_free(transport_pdu); 178*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *)transport_pdu_in_validation); 179*77ba3d3fSMatthias Ringwald transport_pdu_in_validation = NULL; 180*77ba3d3fSMatthias Ringwald } 181*77ba3d3fSMatthias Ringwald mesh_transport_run(); 182*77ba3d3fSMatthias Ringwald } 183*77ba3d3fSMatthias Ringwald 184*77ba3d3fSMatthias Ringwald static uint32_t iv_index_for_ivi_nid(uint8_t ivi_nid){ 185*77ba3d3fSMatthias Ringwald // get IV Index and IVI 186*77ba3d3fSMatthias Ringwald uint32_t iv_index = mesh_get_iv_index(); 187*77ba3d3fSMatthias Ringwald int ivi = ivi_nid >> 7; 188*77ba3d3fSMatthias Ringwald 189*77ba3d3fSMatthias Ringwald // if least significant bit differs, use previous IV Index 190*77ba3d3fSMatthias Ringwald if ((iv_index & 1 ) ^ ivi){ 191*77ba3d3fSMatthias Ringwald iv_index--; 192*77ba3d3fSMatthias Ringwald } 193*77ba3d3fSMatthias Ringwald return iv_index; 194*77ba3d3fSMatthias Ringwald } 195*77ba3d3fSMatthias Ringwald 196*77ba3d3fSMatthias Ringwald static void transport_unsegmented_setup_nonce(uint8_t * nonce, const mesh_network_pdu_t * network_pdu){ 197*77ba3d3fSMatthias Ringwald nonce[1] = 0x00; // SZMIC if a Segmented Access message or 0 for all other message formats 198*77ba3d3fSMatthias Ringwald memcpy(&nonce[2], &network_pdu->data[2], 7); 199*77ba3d3fSMatthias Ringwald big_endian_store_32(nonce, 9, iv_index_for_ivi_nid(network_pdu->data[0])); 200*77ba3d3fSMatthias Ringwald } 201*77ba3d3fSMatthias Ringwald 202*77ba3d3fSMatthias Ringwald static void transport_segmented_setup_nonce(uint8_t * nonce, const mesh_transport_pdu_t * transport_pdu){ 203*77ba3d3fSMatthias Ringwald nonce[1] = transport_pdu->transmic_len == 8 ? 0x80 : 0x00; 204*77ba3d3fSMatthias Ringwald memcpy(&nonce[2], &transport_pdu->network_header[2], 7); 205*77ba3d3fSMatthias Ringwald big_endian_store_32(nonce, 9, iv_index_for_ivi_nid(transport_pdu->network_header[0])); 206*77ba3d3fSMatthias Ringwald } 207*77ba3d3fSMatthias Ringwald 208*77ba3d3fSMatthias Ringwald static void transport_unsegmented_setup_application_nonce(uint8_t * nonce, const mesh_network_pdu_t * network_pdu){ 209*77ba3d3fSMatthias Ringwald nonce[0] = 0x01; 210*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_nonce(nonce, network_pdu); 211*77ba3d3fSMatthias Ringwald mesh_print_hex("AppNonce", nonce, 13); 212*77ba3d3fSMatthias Ringwald } 213*77ba3d3fSMatthias Ringwald 214*77ba3d3fSMatthias Ringwald static void transport_unsegmented_setup_device_nonce(uint8_t * nonce, const mesh_network_pdu_t * network_pdu){ 215*77ba3d3fSMatthias Ringwald nonce[0] = 0x02; 216*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_nonce(nonce, network_pdu); 217*77ba3d3fSMatthias Ringwald mesh_print_hex("DeviceNonce", nonce, 13); 218*77ba3d3fSMatthias Ringwald } 219*77ba3d3fSMatthias Ringwald 220*77ba3d3fSMatthias Ringwald static void transport_segmented_setup_application_nonce(uint8_t * nonce, const mesh_transport_pdu_t * transport_pdu){ 221*77ba3d3fSMatthias Ringwald nonce[0] = 0x01; 222*77ba3d3fSMatthias Ringwald transport_segmented_setup_nonce(nonce, transport_pdu); 223*77ba3d3fSMatthias Ringwald mesh_print_hex("AppNonce", nonce, 13); 224*77ba3d3fSMatthias Ringwald } 225*77ba3d3fSMatthias Ringwald 226*77ba3d3fSMatthias Ringwald static void transport_segmented_setup_device_nonce(uint8_t * nonce, const mesh_transport_pdu_t * transport_pdu){ 227*77ba3d3fSMatthias Ringwald nonce[0] = 0x02; 228*77ba3d3fSMatthias Ringwald transport_segmented_setup_nonce(nonce, transport_pdu); 229*77ba3d3fSMatthias Ringwald mesh_print_hex("DeviceNonce", nonce, 13); 230*77ba3d3fSMatthias Ringwald } 231*77ba3d3fSMatthias Ringwald 232*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_unsegmented_message_ccm(void * arg){ 233*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 234*77ba3d3fSMatthias Ringwald 235*77ba3d3fSMatthias Ringwald uint8_t * lower_transport_pdu = mesh_network_pdu_data(network_pdu); 236*77ba3d3fSMatthias Ringwald uint8_t trans_mic_len = 4; 237*77ba3d3fSMatthias Ringwald 238*77ba3d3fSMatthias Ringwald // store TransMIC 239*77ba3d3fSMatthias Ringwald uint8_t trans_mic[8]; 240*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_get_authentication_value(&ccm, trans_mic); 241*77ba3d3fSMatthias Ringwald mesh_print_hex("TransMIC", trans_mic, trans_mic_len); 242*77ba3d3fSMatthias Ringwald 243*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu = mesh_network_pdu_data(network_pdu) + 1; 244*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = mesh_network_pdu_len(network_pdu) - 1; 245*77ba3d3fSMatthias Ringwald 246*77ba3d3fSMatthias Ringwald mesh_print_hex("Decryted PDU", upper_transport_pdu, upper_transport_pdu_len - trans_mic_len); 247*77ba3d3fSMatthias Ringwald 248*77ba3d3fSMatthias Ringwald if (memcmp(trans_mic, &upper_transport_pdu[upper_transport_pdu_len - trans_mic_len], trans_mic_len) == 0){ 249*77ba3d3fSMatthias Ringwald printf("TransMIC matches\n"); 250*77ba3d3fSMatthias Ringwald 251*77ba3d3fSMatthias Ringwald // remove TransMIC from payload 252*77ba3d3fSMatthias Ringwald network_pdu->len -= trans_mic_len; 253*77ba3d3fSMatthias Ringwald 254*77ba3d3fSMatthias Ringwald // if virtual address, update dst to pseudo_dst 255*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(mesh_network_dst(network_pdu))){ 256*77ba3d3fSMatthias Ringwald big_endian_store_16(network_pdu->data, 7, mesh_transport_key_it.address->pseudo_dst); 257*77ba3d3fSMatthias Ringwald } 258*77ba3d3fSMatthias Ringwald 259*77ba3d3fSMatthias Ringwald // pass to upper layer 260*77ba3d3fSMatthias Ringwald if (mesh_access_message_handler){ 261*77ba3d3fSMatthias Ringwald mesh_access_message_handler((mesh_pdu_t*) network_pdu); 262*77ba3d3fSMatthias Ringwald } else { 263*77ba3d3fSMatthias Ringwald printf("[!] Unhandled Unsegmented Access message\n"); 264*77ba3d3fSMatthias Ringwald // done 265*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_unsegmented_message_done(network_pdu); 266*77ba3d3fSMatthias Ringwald } 267*77ba3d3fSMatthias Ringwald 268*77ba3d3fSMatthias Ringwald printf("\n"); 269*77ba3d3fSMatthias Ringwald } else { 270*77ba3d3fSMatthias Ringwald uint8_t afk = lower_transport_pdu[0] & 0x40; 271*77ba3d3fSMatthias Ringwald if (afk){ 272*77ba3d3fSMatthias Ringwald printf("TransMIC does not match, try next key\n"); 273*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_unsegmented_message(network_pdu); 274*77ba3d3fSMatthias Ringwald } else { 275*77ba3d3fSMatthias Ringwald printf("TransMIC does not match device key, done\n"); 276*77ba3d3fSMatthias Ringwald // done 277*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_unsegmented_message_done(network_pdu); 278*77ba3d3fSMatthias Ringwald } 279*77ba3d3fSMatthias Ringwald } 280*77ba3d3fSMatthias Ringwald } 281*77ba3d3fSMatthias Ringwald 282*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_segmented_message_ccm(void * arg){ 283*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) arg; 284*77ba3d3fSMatthias Ringwald 285*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu = transport_pdu->data; 286*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = transport_pdu->len - transport_pdu->transmic_len; 287*77ba3d3fSMatthias Ringwald 288*77ba3d3fSMatthias Ringwald mesh_print_hex("Decrypted PDU", upper_transport_pdu, upper_transport_pdu_len); 289*77ba3d3fSMatthias Ringwald 290*77ba3d3fSMatthias Ringwald // store TransMIC 291*77ba3d3fSMatthias Ringwald uint8_t trans_mic[8]; 292*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_get_authentication_value(&ccm, trans_mic); 293*77ba3d3fSMatthias Ringwald mesh_print_hex("TransMIC", trans_mic, transport_pdu->transmic_len); 294*77ba3d3fSMatthias Ringwald 295*77ba3d3fSMatthias Ringwald if (memcmp(trans_mic, &upper_transport_pdu[upper_transport_pdu_len], transport_pdu->transmic_len) == 0){ 296*77ba3d3fSMatthias Ringwald printf("TransMIC matches\n"); 297*77ba3d3fSMatthias Ringwald 298*77ba3d3fSMatthias Ringwald // remove TransMIC from payload 299*77ba3d3fSMatthias Ringwald transport_pdu->len -= transport_pdu->transmic_len; 300*77ba3d3fSMatthias Ringwald 301*77ba3d3fSMatthias Ringwald // if virtual address, update dst to pseudo_dst 302*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(mesh_transport_dst(transport_pdu))){ 303*77ba3d3fSMatthias Ringwald big_endian_store_16(transport_pdu->network_header, 7, mesh_transport_key_it.address->pseudo_dst); 304*77ba3d3fSMatthias Ringwald } 305*77ba3d3fSMatthias Ringwald 306*77ba3d3fSMatthias Ringwald // pass to upper layer 307*77ba3d3fSMatthias Ringwald if (mesh_access_message_handler){ 308*77ba3d3fSMatthias Ringwald mesh_access_message_handler((mesh_pdu_t*) transport_pdu); 309*77ba3d3fSMatthias Ringwald } else { 310*77ba3d3fSMatthias Ringwald printf("[!] Unhandled Segmented Access/Control message\n"); 311*77ba3d3fSMatthias Ringwald // done 312*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_segmented_message_done(transport_pdu); 313*77ba3d3fSMatthias Ringwald } 314*77ba3d3fSMatthias Ringwald 315*77ba3d3fSMatthias Ringwald printf("\n"); 316*77ba3d3fSMatthias Ringwald 317*77ba3d3fSMatthias Ringwald } else { 318*77ba3d3fSMatthias Ringwald uint8_t akf = transport_pdu->akf_aid & 0x40; 319*77ba3d3fSMatthias Ringwald if (akf){ 320*77ba3d3fSMatthias Ringwald printf("TransMIC does not match, try next key\n"); 321*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_segmented_message(transport_pdu); 322*77ba3d3fSMatthias Ringwald } else { 323*77ba3d3fSMatthias Ringwald printf("TransMIC does not match device key, done\n"); 324*77ba3d3fSMatthias Ringwald // done 325*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_segmented_message_done(transport_pdu); 326*77ba3d3fSMatthias Ringwald } 327*77ba3d3fSMatthias Ringwald } 328*77ba3d3fSMatthias Ringwald } 329*77ba3d3fSMatthias Ringwald 330*77ba3d3fSMatthias Ringwald void mesh_upper_transport_message_processed_by_higher_layer(mesh_pdu_t * pdu){ 331*77ba3d3fSMatthias Ringwald crypto_active = 0; 332*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 333*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 334*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_unsegmented_message_done((mesh_network_pdu_t *) pdu); 335*77ba3d3fSMatthias Ringwald break; 336*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 337*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_segmented_message_done((mesh_transport_pdu_t *) pdu); 338*77ba3d3fSMatthias Ringwald break; 339*77ba3d3fSMatthias Ringwald default: 340*77ba3d3fSMatthias Ringwald break; 341*77ba3d3fSMatthias Ringwald } 342*77ba3d3fSMatthias Ringwald } 343*77ba3d3fSMatthias Ringwald 344*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_segmented_message_digest(void * arg){ 345*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t*) arg; 346*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = transport_pdu_in_validation->len - transport_pdu_in_validation->transmic_len; 347*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data_in = transport_pdu_in_validation->data; 348*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data_out = transport_pdu->data; 349*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_decrypt_block(&ccm, upper_transport_pdu_len, upper_transport_pdu_data_in, upper_transport_pdu_data_out, &mesh_upper_transport_validate_segmented_message_ccm, transport_pdu); 350*77ba3d3fSMatthias Ringwald } 351*77ba3d3fSMatthias Ringwald 352*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_unsegmented_message_digest(void * arg){ 353*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 354*77ba3d3fSMatthias Ringwald uint8_t trans_mic_len = 4; 355*77ba3d3fSMatthias Ringwald uint8_t lower_transport_pdu_len = network_pdu_in_validation->len - 9; 356*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data_in = &network_pdu_in_validation->data[10]; 357*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data_out = &network_pdu->data[10]; 358*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = lower_transport_pdu_len - 1 - trans_mic_len; 359*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_decrypt_block(&ccm, upper_transport_pdu_len, upper_transport_pdu_data_in, upper_transport_pdu_data_out, &mesh_upper_transport_validate_unsegmented_message_ccm, network_pdu); 360*77ba3d3fSMatthias Ringwald } 361*77ba3d3fSMatthias Ringwald 362*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_unsegmented_message(mesh_network_pdu_t * network_pdu){ 363*77ba3d3fSMatthias Ringwald 364*77ba3d3fSMatthias Ringwald if (!mesh_transport_key_and_virtual_address_iterator_has_more(&mesh_transport_key_it)){ 365*77ba3d3fSMatthias Ringwald printf("No valid transport key found\n"); 366*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_unsegmented_message_done(network_pdu); 367*77ba3d3fSMatthias Ringwald return; 368*77ba3d3fSMatthias Ringwald } 369*77ba3d3fSMatthias Ringwald mesh_transport_key_and_virtual_address_iterator_next(&mesh_transport_key_it); 370*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * message_key = mesh_transport_key_it.key; 371*77ba3d3fSMatthias Ringwald 372*77ba3d3fSMatthias Ringwald if (message_key->akf){ 373*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_application_nonce(application_nonce, network_pdu_in_validation); 374*77ba3d3fSMatthias Ringwald } else { 375*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_device_nonce(application_nonce, network_pdu_in_validation); 376*77ba3d3fSMatthias Ringwald } 377*77ba3d3fSMatthias Ringwald 378*77ba3d3fSMatthias Ringwald // store application / device key index 379*77ba3d3fSMatthias Ringwald mesh_print_hex("AppOrDevKey", message_key->key, 16); 380*77ba3d3fSMatthias Ringwald network_pdu->appkey_index = message_key->appkey_index; 381*77ba3d3fSMatthias Ringwald 382*77ba3d3fSMatthias Ringwald // unsegmented message have TransMIC of 32 bit 383*77ba3d3fSMatthias Ringwald uint8_t trans_mic_len = 4; 384*77ba3d3fSMatthias Ringwald printf("Unsegmented Access message with TransMIC len 4\n"); 385*77ba3d3fSMatthias Ringwald 386*77ba3d3fSMatthias Ringwald uint8_t lower_transport_pdu_len = network_pdu_in_validation->len - 9; 387*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data = &network_pdu_in_validation->data[10]; 388*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = lower_transport_pdu_len - 1 - trans_mic_len; 389*77ba3d3fSMatthias Ringwald 390*77ba3d3fSMatthias Ringwald mesh_print_hex("EncAccessPayload", upper_transport_pdu_data, upper_transport_pdu_len); 391*77ba3d3fSMatthias Ringwald 392*77ba3d3fSMatthias Ringwald // decrypt ccm 393*77ba3d3fSMatthias Ringwald crypto_active = 1; 394*77ba3d3fSMatthias Ringwald uint16_t aad_len = 0; 395*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(mesh_network_dst(network_pdu))){ 396*77ba3d3fSMatthias Ringwald aad_len = 16; 397*77ba3d3fSMatthias Ringwald } 398*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_init(&ccm, message_key->key, application_nonce, upper_transport_pdu_len, aad_len, trans_mic_len); 399*77ba3d3fSMatthias Ringwald if (aad_len){ 400*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_digest(&ccm, (uint8_t*) mesh_transport_key_it.address->label_uuid, aad_len, &mesh_upper_transport_validate_unsegmented_message_digest, network_pdu); 401*77ba3d3fSMatthias Ringwald } else { 402*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_unsegmented_message_digest(network_pdu); 403*77ba3d3fSMatthias Ringwald } 404*77ba3d3fSMatthias Ringwald } 405*77ba3d3fSMatthias Ringwald 406*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_validate_segmented_message(mesh_transport_pdu_t * transport_pdu){ 407*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu_data = transport_pdu->data; 408*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = transport_pdu->len - transport_pdu->transmic_len; 409*77ba3d3fSMatthias Ringwald 410*77ba3d3fSMatthias Ringwald if (!mesh_transport_key_and_virtual_address_iterator_has_more(&mesh_transport_key_it)){ 411*77ba3d3fSMatthias Ringwald printf("No valid transport key found\n"); 412*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_segmented_message_done(transport_pdu); 413*77ba3d3fSMatthias Ringwald return; 414*77ba3d3fSMatthias Ringwald } 415*77ba3d3fSMatthias Ringwald mesh_transport_key_and_virtual_address_iterator_next(&mesh_transport_key_it); 416*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * message_key = mesh_transport_key_it.key; 417*77ba3d3fSMatthias Ringwald 418*77ba3d3fSMatthias Ringwald if (message_key->akf){ 419*77ba3d3fSMatthias Ringwald transport_segmented_setup_application_nonce(application_nonce, transport_pdu_in_validation); 420*77ba3d3fSMatthias Ringwald } else { 421*77ba3d3fSMatthias Ringwald transport_segmented_setup_device_nonce(application_nonce, transport_pdu_in_validation); 422*77ba3d3fSMatthias Ringwald } 423*77ba3d3fSMatthias Ringwald 424*77ba3d3fSMatthias Ringwald // store application / device key index 425*77ba3d3fSMatthias Ringwald mesh_print_hex("AppOrDevKey", message_key->key, 16); 426*77ba3d3fSMatthias Ringwald transport_pdu->appkey_index = message_key->appkey_index; 427*77ba3d3fSMatthias Ringwald 428*77ba3d3fSMatthias Ringwald mesh_print_hex("EncAccessPayload", upper_transport_pdu_data, upper_transport_pdu_len); 429*77ba3d3fSMatthias Ringwald 430*77ba3d3fSMatthias Ringwald // decrypt ccm 431*77ba3d3fSMatthias Ringwald crypto_active = 1; 432*77ba3d3fSMatthias Ringwald uint16_t aad_len = 0; 433*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(mesh_transport_dst(transport_pdu))){ 434*77ba3d3fSMatthias Ringwald aad_len = 16; 435*77ba3d3fSMatthias Ringwald } 436*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_init(&ccm, message_key->key, application_nonce, upper_transport_pdu_len, aad_len, transport_pdu->transmic_len); 437*77ba3d3fSMatthias Ringwald 438*77ba3d3fSMatthias Ringwald if (aad_len){ 439*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_digest(&ccm, (uint8_t *) mesh_transport_key_it.address->label_uuid, aad_len, &mesh_upper_transport_validate_segmented_message_digest, transport_pdu); 440*77ba3d3fSMatthias Ringwald } else { 441*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_segmented_message_digest(transport_pdu); 442*77ba3d3fSMatthias Ringwald } 443*77ba3d3fSMatthias Ringwald } 444*77ba3d3fSMatthias Ringwald 445*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_process_unsegmented_access_message(mesh_network_pdu_t *network_pdu){ 446*77ba3d3fSMatthias Ringwald // copy original pdu 447*77ba3d3fSMatthias Ringwald network_pdu->len = network_pdu_in_validation->len; 448*77ba3d3fSMatthias Ringwald memcpy(network_pdu->data, network_pdu_in_validation->data, network_pdu->len); 449*77ba3d3fSMatthias Ringwald 450*77ba3d3fSMatthias Ringwald // 451*77ba3d3fSMatthias Ringwald uint8_t * lower_transport_pdu = &network_pdu_in_validation->data[9]; 452*77ba3d3fSMatthias Ringwald uint8_t lower_transport_pdu_len = network_pdu_in_validation->len - 9; 453*77ba3d3fSMatthias Ringwald 454*77ba3d3fSMatthias Ringwald mesh_print_hex("Lower Transport network pdu", &network_pdu_in_validation->data[9], lower_transport_pdu_len); 455*77ba3d3fSMatthias Ringwald 456*77ba3d3fSMatthias Ringwald uint8_t aid = lower_transport_pdu[0] & 0x3f; 457*77ba3d3fSMatthias Ringwald uint8_t akf = (lower_transport_pdu[0] & 0x40) >> 6; 458*77ba3d3fSMatthias Ringwald printf("AKF: %u\n", akf); 459*77ba3d3fSMatthias Ringwald printf("AID: %02x\n", aid); 460*77ba3d3fSMatthias Ringwald 461*77ba3d3fSMatthias Ringwald mesh_transport_key_and_virtual_address_iterator_init(&mesh_transport_key_it, mesh_network_dst(network_pdu), 462*77ba3d3fSMatthias Ringwald network_pdu->netkey_index, akf, aid); 463*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_unsegmented_message(network_pdu); 464*77ba3d3fSMatthias Ringwald } 465*77ba3d3fSMatthias Ringwald 466*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_process_message(mesh_transport_pdu_t * transport_pdu){ 467*77ba3d3fSMatthias Ringwald // copy original pdu 468*77ba3d3fSMatthias Ringwald transport_pdu->len = transport_pdu_in_validation->len; 469*77ba3d3fSMatthias Ringwald memcpy(transport_pdu, transport_pdu_in_validation, sizeof(mesh_transport_pdu_t)); 470*77ba3d3fSMatthias Ringwald 471*77ba3d3fSMatthias Ringwald // 472*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu = transport_pdu->data; 473*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = transport_pdu->len - transport_pdu->transmic_len; 474*77ba3d3fSMatthias Ringwald mesh_print_hex("Upper Transport pdu", upper_transport_pdu, upper_transport_pdu_len); 475*77ba3d3fSMatthias Ringwald 476*77ba3d3fSMatthias Ringwald uint8_t aid = transport_pdu->akf_aid & 0x3f; 477*77ba3d3fSMatthias Ringwald uint8_t akf = (transport_pdu->akf_aid & 0x40) >> 6; 478*77ba3d3fSMatthias Ringwald 479*77ba3d3fSMatthias Ringwald printf("AKF: %u\n", akf); 480*77ba3d3fSMatthias Ringwald printf("AID: %02x\n", aid); 481*77ba3d3fSMatthias Ringwald 482*77ba3d3fSMatthias Ringwald mesh_transport_key_and_virtual_address_iterator_init(&mesh_transport_key_it, mesh_transport_dst(transport_pdu), 483*77ba3d3fSMatthias Ringwald transport_pdu->netkey_index, akf, aid); 484*77ba3d3fSMatthias Ringwald mesh_upper_transport_validate_segmented_message(transport_pdu); 485*77ba3d3fSMatthias Ringwald } 486*77ba3d3fSMatthias Ringwald 487*77ba3d3fSMatthias Ringwald void mesh_upper_transport_message_received(mesh_pdu_t * pdu){ 488*77ba3d3fSMatthias Ringwald btstack_linked_list_add_tail(&upper_transport_incoming, (btstack_linked_item_t*) pdu); 489*77ba3d3fSMatthias Ringwald mesh_transport_run(); 490*77ba3d3fSMatthias Ringwald } 491*77ba3d3fSMatthias Ringwald 492*77ba3d3fSMatthias Ringwald void mesh_upper_transport_pdu_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){ 493*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu; 494*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu; 495*77ba3d3fSMatthias Ringwald switch (callback_type){ 496*77ba3d3fSMatthias Ringwald case MESH_TRANSPORT_PDU_RECEIVED: 497*77ba3d3fSMatthias Ringwald mesh_upper_transport_message_received(pdu); 498*77ba3d3fSMatthias Ringwald break; 499*77ba3d3fSMatthias Ringwald case MESH_TRANSPORT_PDU_SENT: 500*77ba3d3fSMatthias Ringwald // notify upper layer (or just free pdu) 501*77ba3d3fSMatthias Ringwald if (higher_layer_handler){ 502*77ba3d3fSMatthias Ringwald higher_layer_handler(callback_type, status, pdu); 503*77ba3d3fSMatthias Ringwald } else { 504*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type) { 505*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 506*77ba3d3fSMatthias Ringwald network_pdu = (mesh_network_pdu_t *) pdu; 507*77ba3d3fSMatthias Ringwald mesh_network_pdu_free(network_pdu); 508*77ba3d3fSMatthias Ringwald break; 509*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 510*77ba3d3fSMatthias Ringwald transport_pdu = (mesh_transport_pdu_t *) pdu; 511*77ba3d3fSMatthias Ringwald mesh_transport_pdu_free(transport_pdu); 512*77ba3d3fSMatthias Ringwald break; 513*77ba3d3fSMatthias Ringwald default: 514*77ba3d3fSMatthias Ringwald break; 515*77ba3d3fSMatthias Ringwald } 516*77ba3d3fSMatthias Ringwald } 517*77ba3d3fSMatthias Ringwald break; 518*77ba3d3fSMatthias Ringwald default: 519*77ba3d3fSMatthias Ringwald break; 520*77ba3d3fSMatthias Ringwald } 521*77ba3d3fSMatthias Ringwald } 522*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_unsegmented_access_pdu_ccm(void * arg){ 523*77ba3d3fSMatthias Ringwald crypto_active = 0; 524*77ba3d3fSMatthias Ringwald 525*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 526*77ba3d3fSMatthias Ringwald uint8_t * upper_transport_pdu = mesh_network_pdu_data(network_pdu) + 1; 527*77ba3d3fSMatthias Ringwald uint8_t upper_transport_pdu_len = mesh_network_pdu_len(network_pdu) - 1; 528*77ba3d3fSMatthias Ringwald mesh_print_hex("EncAccessPayload", upper_transport_pdu, upper_transport_pdu_len); 529*77ba3d3fSMatthias Ringwald // store TransMIC 530*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_get_authentication_value(&ccm, &upper_transport_pdu[upper_transport_pdu_len]); 531*77ba3d3fSMatthias Ringwald mesh_print_hex("TransMIC", &upper_transport_pdu[upper_transport_pdu_len], 4); 532*77ba3d3fSMatthias Ringwald network_pdu->len += 4; 533*77ba3d3fSMatthias Ringwald // send network pdu 534*77ba3d3fSMatthias Ringwald mesh_lower_transport_send_pdu((mesh_pdu_t*) network_pdu); 535*77ba3d3fSMatthias Ringwald } 536*77ba3d3fSMatthias Ringwald 537*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_segmented_access_pdu_ccm(void * arg){ 538*77ba3d3fSMatthias Ringwald crypto_active = 0; 539*77ba3d3fSMatthias Ringwald 540*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) arg; 541*77ba3d3fSMatthias Ringwald mesh_print_hex("EncAccessPayload", transport_pdu->data, transport_pdu->len); 542*77ba3d3fSMatthias Ringwald // store TransMIC 543*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_get_authentication_value(&ccm, &transport_pdu->data[transport_pdu->len]); 544*77ba3d3fSMatthias Ringwald mesh_print_hex("TransMIC", &transport_pdu->data[transport_pdu->len], transport_pdu->transmic_len); 545*77ba3d3fSMatthias Ringwald transport_pdu->len += transport_pdu->transmic_len; 546*77ba3d3fSMatthias Ringwald mesh_lower_transport_send_pdu((mesh_pdu_t*) transport_pdu); 547*77ba3d3fSMatthias Ringwald } 548*77ba3d3fSMatthias Ringwald 549*77ba3d3fSMatthias Ringwald static 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, 550*77ba3d3fSMatthias Ringwald const uint8_t * control_pdu_data, uint16_t control_pdu_len){ 551*77ba3d3fSMatthias Ringwald 552*77ba3d3fSMatthias Ringwald printf("[+] Upper transport, setup unsegmented Control PDU (opcode %02x): \n", opcode); 553*77ba3d3fSMatthias Ringwald printf_hexdump(control_pdu_data, control_pdu_len); 554*77ba3d3fSMatthias Ringwald 555*77ba3d3fSMatthias Ringwald if (control_pdu_len > 11) return 1; 556*77ba3d3fSMatthias Ringwald 557*77ba3d3fSMatthias Ringwald const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); 558*77ba3d3fSMatthias Ringwald if (!network_key) return 1; 559*77ba3d3fSMatthias Ringwald 560*77ba3d3fSMatthias Ringwald uint8_t transport_pdu_data[12]; 561*77ba3d3fSMatthias Ringwald transport_pdu_data[0] = opcode; 562*77ba3d3fSMatthias Ringwald memcpy(&transport_pdu_data[1], control_pdu_data, control_pdu_len); 563*77ba3d3fSMatthias Ringwald uint16_t transport_pdu_len = control_pdu_len + 1; 564*77ba3d3fSMatthias Ringwald 565*77ba3d3fSMatthias Ringwald mesh_print_hex("LowerTransportPDU", transport_pdu_data, transport_pdu_len); 566*77ba3d3fSMatthias Ringwald // setup network_pdu 567*77ba3d3fSMatthias Ringwald mesh_network_setup_pdu(network_pdu, netkey_index, network_key->nid, 1, ttl, mesh_lower_transport_next_seq(), src, dest, transport_pdu_data, transport_pdu_len); 568*77ba3d3fSMatthias Ringwald 569*77ba3d3fSMatthias Ringwald return 0; 570*77ba3d3fSMatthias Ringwald } 571*77ba3d3fSMatthias Ringwald 572*77ba3d3fSMatthias Ringwald static uint8_t mesh_upper_transport_setup_segmented_control_pdu(mesh_transport_pdu_t * transport_pdu, uint16_t netkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t opcode, 573*77ba3d3fSMatthias Ringwald const uint8_t * control_pdu_data, uint16_t control_pdu_len){ 574*77ba3d3fSMatthias Ringwald 575*77ba3d3fSMatthias Ringwald printf("[+] Upper transport, setup segmented Control PDU (opcode %02x): \n", opcode); 576*77ba3d3fSMatthias Ringwald printf_hexdump(control_pdu_data, control_pdu_len); 577*77ba3d3fSMatthias Ringwald 578*77ba3d3fSMatthias Ringwald if (control_pdu_len > 256) return 1; 579*77ba3d3fSMatthias Ringwald 580*77ba3d3fSMatthias Ringwald const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); 581*77ba3d3fSMatthias Ringwald if (!network_key) return 1; 582*77ba3d3fSMatthias Ringwald 583*77ba3d3fSMatthias Ringwald uint32_t seq = mesh_lower_transport_peek_seq(); 584*77ba3d3fSMatthias Ringwald 585*77ba3d3fSMatthias Ringwald memcpy(transport_pdu->data, control_pdu_data, control_pdu_len); 586*77ba3d3fSMatthias Ringwald transport_pdu->len = control_pdu_len; 587*77ba3d3fSMatthias Ringwald transport_pdu->netkey_index = netkey_index; 588*77ba3d3fSMatthias Ringwald transport_pdu->akf_aid = opcode; 589*77ba3d3fSMatthias Ringwald transport_pdu->transmic_len = 0; // no TransMIC for control 590*77ba3d3fSMatthias Ringwald mesh_transport_set_nid_ivi(transport_pdu, network_key->nid); 591*77ba3d3fSMatthias Ringwald mesh_transport_set_seq(transport_pdu, seq); 592*77ba3d3fSMatthias Ringwald mesh_transport_set_src(transport_pdu, src); 593*77ba3d3fSMatthias Ringwald mesh_transport_set_dest(transport_pdu, dest); 594*77ba3d3fSMatthias Ringwald mesh_transport_set_ctl_ttl(transport_pdu, 0x80 | ttl); 595*77ba3d3fSMatthias Ringwald 596*77ba3d3fSMatthias Ringwald return 0; 597*77ba3d3fSMatthias Ringwald } 598*77ba3d3fSMatthias Ringwald 599*77ba3d3fSMatthias Ringwald uint8_t mesh_upper_transport_setup_control_pdu(mesh_pdu_t * pdu, uint16_t netkey_index, 600*77ba3d3fSMatthias Ringwald uint8_t ttl, uint16_t src, uint16_t dest, uint8_t opcode, const uint8_t * control_pdu_data, uint16_t control_pdu_len){ 601*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 602*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 603*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_unsegmented_control_pdu((mesh_network_pdu_t *) pdu, netkey_index, ttl, src, dest, opcode, control_pdu_data, control_pdu_len); 604*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 605*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_segmented_control_pdu((mesh_transport_pdu_t *) pdu, netkey_index, ttl, src, dest, opcode, control_pdu_data, control_pdu_len); 606*77ba3d3fSMatthias Ringwald default: 607*77ba3d3fSMatthias Ringwald return 1; 608*77ba3d3fSMatthias Ringwald } 609*77ba3d3fSMatthias Ringwald } 610*77ba3d3fSMatthias Ringwald 611*77ba3d3fSMatthias Ringwald static uint8_t mesh_upper_transport_setup_unsegmented_access_pdu_header(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, 612*77ba3d3fSMatthias Ringwald uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest){ 613*77ba3d3fSMatthias Ringwald 614*77ba3d3fSMatthias Ringwald // get app or device key 615*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * appkey; 616*77ba3d3fSMatthias Ringwald appkey = mesh_transport_key_get(appkey_index); 617*77ba3d3fSMatthias Ringwald if (appkey == NULL){ 618*77ba3d3fSMatthias Ringwald printf("appkey_index %x unknown\n", appkey_index); 619*77ba3d3fSMatthias Ringwald return 1; 620*77ba3d3fSMatthias Ringwald } 621*77ba3d3fSMatthias Ringwald uint8_t akf_aid = (appkey->akf << 6) | appkey->aid; 622*77ba3d3fSMatthias Ringwald 623*77ba3d3fSMatthias Ringwald // lookup network by netkey_index 624*77ba3d3fSMatthias Ringwald const mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index); 625*77ba3d3fSMatthias Ringwald if (!network_key) return 1; 626*77ba3d3fSMatthias Ringwald 627*77ba3d3fSMatthias Ringwald network_pdu->data[9] = akf_aid; 628*77ba3d3fSMatthias Ringwald // setup network_pdu 629*77ba3d3fSMatthias Ringwald mesh_network_setup_pdu_header(network_pdu, netkey_index, network_key->nid, 0, ttl, mesh_lower_transport_next_seq(), src, dest); 630*77ba3d3fSMatthias Ringwald network_pdu->appkey_index = appkey_index; 631*77ba3d3fSMatthias Ringwald return 0; 632*77ba3d3fSMatthias Ringwald } 633*77ba3d3fSMatthias Ringwald 634*77ba3d3fSMatthias Ringwald static uint8_t mesh_upper_transport_setup_unsegmented_access_pdu(mesh_network_pdu_t * network_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, 635*77ba3d3fSMatthias Ringwald const uint8_t * access_pdu_data, uint8_t access_pdu_len){ 636*77ba3d3fSMatthias Ringwald 637*77ba3d3fSMatthias Ringwald int status = mesh_upper_transport_setup_unsegmented_access_pdu_header(network_pdu, netkey_index, appkey_index, ttl, src, dest); 638*77ba3d3fSMatthias Ringwald if (status) return status; 639*77ba3d3fSMatthias Ringwald 640*77ba3d3fSMatthias Ringwald printf("[+] Upper transport, setup unsegmented Access PDU - seq %06x\n", mesh_network_seq(network_pdu)); 641*77ba3d3fSMatthias Ringwald mesh_print_hex("Access Payload", access_pdu_data, access_pdu_len); 642*77ba3d3fSMatthias Ringwald 643*77ba3d3fSMatthias Ringwald // store in transport pdu 644*77ba3d3fSMatthias Ringwald memcpy(&network_pdu->data[10], access_pdu_data, access_pdu_len); 645*77ba3d3fSMatthias Ringwald network_pdu->len = 10 + access_pdu_len; 646*77ba3d3fSMatthias Ringwald return 0; 647*77ba3d3fSMatthias Ringwald } 648*77ba3d3fSMatthias Ringwald 649*77ba3d3fSMatthias Ringwald static uint8_t mesh_upper_transport_setup_segmented_access_pdu_header(mesh_transport_pdu_t * transport_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, 650*77ba3d3fSMatthias Ringwald uint8_t szmic){ 651*77ba3d3fSMatthias Ringwald uint32_t seq = mesh_lower_transport_peek_seq(); 652*77ba3d3fSMatthias Ringwald 653*77ba3d3fSMatthias Ringwald printf("[+] Upper transport, setup segmented Access PDU - seq %06x, szmic %u, iv_index %08x\n", seq, szmic, 654*77ba3d3fSMatthias Ringwald mesh_get_iv_index()); 655*77ba3d3fSMatthias Ringwald mesh_print_hex("Access Payload", transport_pdu->data, transport_pdu->len); 656*77ba3d3fSMatthias Ringwald 657*77ba3d3fSMatthias Ringwald // get app or device key 658*77ba3d3fSMatthias Ringwald const mesh_transport_key_t *appkey; 659*77ba3d3fSMatthias Ringwald appkey = mesh_transport_key_get(appkey_index); 660*77ba3d3fSMatthias Ringwald if (appkey == NULL) { 661*77ba3d3fSMatthias Ringwald printf("appkey_index %x unknown\n", appkey_index); 662*77ba3d3fSMatthias Ringwald return 1; 663*77ba3d3fSMatthias Ringwald } 664*77ba3d3fSMatthias Ringwald uint8_t akf_aid = (appkey->akf << 6) | appkey->aid; 665*77ba3d3fSMatthias Ringwald 666*77ba3d3fSMatthias Ringwald // lookup network by netkey_index 667*77ba3d3fSMatthias Ringwald const mesh_network_key_t *network_key = mesh_network_key_list_get(netkey_index); 668*77ba3d3fSMatthias Ringwald if (!network_key) return 1; 669*77ba3d3fSMatthias Ringwald 670*77ba3d3fSMatthias Ringwald const uint8_t trans_mic_len = szmic ? 8 : 4; 671*77ba3d3fSMatthias Ringwald 672*77ba3d3fSMatthias Ringwald // store in transport pdu 673*77ba3d3fSMatthias Ringwald transport_pdu->transmic_len = trans_mic_len; 674*77ba3d3fSMatthias Ringwald transport_pdu->netkey_index = netkey_index; 675*77ba3d3fSMatthias Ringwald transport_pdu->appkey_index = appkey_index; 676*77ba3d3fSMatthias Ringwald transport_pdu->akf_aid = akf_aid; 677*77ba3d3fSMatthias Ringwald mesh_transport_set_nid_ivi(transport_pdu, network_key->nid | ((mesh_get_iv_index() & 1) << 7)); 678*77ba3d3fSMatthias Ringwald mesh_transport_set_seq(transport_pdu, seq); 679*77ba3d3fSMatthias Ringwald mesh_transport_set_src(transport_pdu, src); 680*77ba3d3fSMatthias Ringwald mesh_transport_set_dest(transport_pdu, dest); 681*77ba3d3fSMatthias Ringwald mesh_transport_set_ctl_ttl(transport_pdu, ttl); 682*77ba3d3fSMatthias Ringwald return 0; 683*77ba3d3fSMatthias Ringwald } 684*77ba3d3fSMatthias Ringwald 685*77ba3d3fSMatthias Ringwald 686*77ba3d3fSMatthias Ringwald static uint8_t mesh_upper_transport_setup_segmented_access_pdu(mesh_transport_pdu_t * transport_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, 687*77ba3d3fSMatthias Ringwald uint8_t szmic, const uint8_t * access_pdu_data, uint8_t access_pdu_len){ 688*77ba3d3fSMatthias Ringwald int status = mesh_upper_transport_setup_segmented_access_pdu_header(transport_pdu, netkey_index, appkey_index, ttl, src, dest, szmic); 689*77ba3d3fSMatthias Ringwald if (status) return status; 690*77ba3d3fSMatthias Ringwald 691*77ba3d3fSMatthias Ringwald // store in transport pdu 692*77ba3d3fSMatthias Ringwald memcpy(transport_pdu->data, access_pdu_data, access_pdu_len); 693*77ba3d3fSMatthias Ringwald transport_pdu->len = access_pdu_len; 694*77ba3d3fSMatthias Ringwald return 0; 695*77ba3d3fSMatthias Ringwald } 696*77ba3d3fSMatthias Ringwald uint8_t mesh_upper_transport_setup_access_pdu_header(mesh_pdu_t * pdu, uint16_t netkey_index, uint16_t appkey_index, 697*77ba3d3fSMatthias Ringwald uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic){ 698*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 699*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 700*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_unsegmented_access_pdu_header((mesh_network_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest); 701*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 702*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_segmented_access_pdu_header((mesh_transport_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest, szmic); 703*77ba3d3fSMatthias Ringwald default: 704*77ba3d3fSMatthias Ringwald return 1; 705*77ba3d3fSMatthias Ringwald } 706*77ba3d3fSMatthias Ringwald } 707*77ba3d3fSMatthias Ringwald 708*77ba3d3fSMatthias Ringwald uint8_t mesh_upper_transport_setup_access_pdu(mesh_pdu_t * pdu, uint16_t netkey_index, uint16_t appkey_index, 709*77ba3d3fSMatthias Ringwald uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic, 710*77ba3d3fSMatthias Ringwald const uint8_t * access_pdu_data, uint8_t access_pdu_len){ 711*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 712*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 713*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_unsegmented_access_pdu((mesh_network_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest, access_pdu_data, access_pdu_len); 714*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 715*77ba3d3fSMatthias Ringwald return mesh_upper_transport_setup_segmented_access_pdu((mesh_transport_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest, szmic, access_pdu_data, access_pdu_len); 716*77ba3d3fSMatthias Ringwald default: 717*77ba3d3fSMatthias Ringwald return 1; 718*77ba3d3fSMatthias Ringwald } 719*77ba3d3fSMatthias Ringwald } 720*77ba3d3fSMatthias Ringwald 721*77ba3d3fSMatthias Ringwald void mesh_upper_transport_send_control_pdu(mesh_pdu_t * pdu){ 722*77ba3d3fSMatthias Ringwald mesh_lower_transport_send_pdu((mesh_pdu_t*) pdu); 723*77ba3d3fSMatthias Ringwald } 724*77ba3d3fSMatthias Ringwald 725*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_unsegmented_access_pdu_digest(void * arg){ 726*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) arg; 727*77ba3d3fSMatthias Ringwald uint8_t * access_pdu_data = mesh_network_pdu_data(network_pdu) + 1; 728*77ba3d3fSMatthias Ringwald uint16_t access_pdu_len = mesh_network_pdu_len(network_pdu) - 1; 729*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_encrypt_block(&ccm, access_pdu_len, access_pdu_data, access_pdu_data, &mesh_upper_transport_send_unsegmented_access_pdu_ccm, network_pdu); 730*77ba3d3fSMatthias Ringwald } 731*77ba3d3fSMatthias Ringwald 732*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_unsegmented_access_pdu(mesh_network_pdu_t * network_pdu){ 733*77ba3d3fSMatthias Ringwald 734*77ba3d3fSMatthias Ringwald // if dst is virtual address, lookup label uuid and hash 735*77ba3d3fSMatthias Ringwald uint16_t aad_len = 0; 736*77ba3d3fSMatthias Ringwald mesh_virtual_address_t * virtual_address = NULL; 737*77ba3d3fSMatthias Ringwald uint16_t dst = mesh_network_dst(network_pdu); 738*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(dst)){ 739*77ba3d3fSMatthias Ringwald virtual_address = mesh_virtual_address_for_pseudo_dst(dst); 740*77ba3d3fSMatthias Ringwald if (!virtual_address){ 741*77ba3d3fSMatthias Ringwald printf("No virtual address register for pseudo dst %4x\n", dst); 742*77ba3d3fSMatthias Ringwald btstack_memory_mesh_network_pdu_free(network_pdu); 743*77ba3d3fSMatthias Ringwald return; 744*77ba3d3fSMatthias Ringwald } 745*77ba3d3fSMatthias Ringwald aad_len = 16; 746*77ba3d3fSMatthias Ringwald big_endian_store_16(network_pdu->data, 7, virtual_address->hash); 747*77ba3d3fSMatthias Ringwald } 748*77ba3d3fSMatthias Ringwald 749*77ba3d3fSMatthias Ringwald // setup nonce 750*77ba3d3fSMatthias Ringwald uint16_t appkey_index = network_pdu->appkey_index; 751*77ba3d3fSMatthias Ringwald if (appkey_index == MESH_DEVICE_KEY_INDEX){ 752*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_device_nonce(application_nonce, network_pdu); 753*77ba3d3fSMatthias Ringwald } else { 754*77ba3d3fSMatthias Ringwald transport_unsegmented_setup_application_nonce(application_nonce, network_pdu); 755*77ba3d3fSMatthias Ringwald } 756*77ba3d3fSMatthias Ringwald 757*77ba3d3fSMatthias Ringwald // get app or device key 758*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * appkey = mesh_transport_key_get(appkey_index); 759*77ba3d3fSMatthias Ringwald mesh_print_hex("AppOrDevKey", appkey->key, 16); 760*77ba3d3fSMatthias Ringwald 761*77ba3d3fSMatthias Ringwald // encrypt ccm 762*77ba3d3fSMatthias Ringwald uint8_t trans_mic_len = 4; 763*77ba3d3fSMatthias Ringwald uint16_t access_pdu_len = mesh_network_pdu_len(network_pdu) - 1; 764*77ba3d3fSMatthias Ringwald crypto_active = 1; 765*77ba3d3fSMatthias Ringwald 766*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_init(&ccm, appkey->key, application_nonce, access_pdu_len, aad_len, trans_mic_len); 767*77ba3d3fSMatthias Ringwald if (virtual_address){ 768*77ba3d3fSMatthias Ringwald mesh_print_hex("LabelUUID", virtual_address->label_uuid, 16); 769*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_digest(&ccm, virtual_address->label_uuid, 16, &mesh_upper_transport_send_unsegmented_access_pdu_digest, network_pdu); 770*77ba3d3fSMatthias Ringwald } else { 771*77ba3d3fSMatthias Ringwald mesh_upper_transport_send_unsegmented_access_pdu_digest(network_pdu); 772*77ba3d3fSMatthias Ringwald } 773*77ba3d3fSMatthias Ringwald } 774*77ba3d3fSMatthias Ringwald 775*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_segmented_access_pdu_digest(void *arg){ 776*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu = (mesh_transport_pdu_t *) arg; 777*77ba3d3fSMatthias Ringwald uint16_t access_pdu_len = transport_pdu->len; 778*77ba3d3fSMatthias Ringwald uint8_t * access_pdu_data = transport_pdu->data; 779*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_encrypt_block(&ccm, access_pdu_len,access_pdu_data, access_pdu_data, &mesh_upper_transport_send_segmented_access_pdu_ccm, transport_pdu); 780*77ba3d3fSMatthias Ringwald } 781*77ba3d3fSMatthias Ringwald 782*77ba3d3fSMatthias Ringwald static void mesh_upper_transport_send_segmented_access_pdu(mesh_transport_pdu_t * transport_pdu){ 783*77ba3d3fSMatthias Ringwald 784*77ba3d3fSMatthias Ringwald // if dst is virtual address, lookup label uuid and hash 785*77ba3d3fSMatthias Ringwald uint16_t aad_len = 0; 786*77ba3d3fSMatthias Ringwald mesh_virtual_address_t * virtual_address = NULL; 787*77ba3d3fSMatthias Ringwald uint16_t dst = mesh_transport_dst(transport_pdu); 788*77ba3d3fSMatthias Ringwald if (mesh_network_address_virtual(dst)){ 789*77ba3d3fSMatthias Ringwald virtual_address = mesh_virtual_address_for_pseudo_dst(dst); 790*77ba3d3fSMatthias Ringwald if (!virtual_address){ 791*77ba3d3fSMatthias Ringwald printf("No virtual address register for pseudo dst %4x\n", dst); 792*77ba3d3fSMatthias Ringwald btstack_memory_mesh_transport_pdu_free(transport_pdu); 793*77ba3d3fSMatthias Ringwald return; 794*77ba3d3fSMatthias Ringwald } 795*77ba3d3fSMatthias Ringwald // printf("Using hash %4x with LabelUUID: ", virtual_address->hash); 796*77ba3d3fSMatthias Ringwald // printf_hexdump(virtual_address->label_uuid, 16); 797*77ba3d3fSMatthias Ringwald aad_len = 16; 798*77ba3d3fSMatthias Ringwald big_endian_store_16(transport_pdu->network_header, 7, virtual_address->hash); 799*77ba3d3fSMatthias Ringwald } 800*77ba3d3fSMatthias Ringwald 801*77ba3d3fSMatthias Ringwald // setup nonce - uses dst, so after pseudo address translation 802*77ba3d3fSMatthias Ringwald uint16_t appkey_index = transport_pdu->appkey_index; 803*77ba3d3fSMatthias Ringwald if (appkey_index == MESH_DEVICE_KEY_INDEX){ 804*77ba3d3fSMatthias Ringwald transport_segmented_setup_device_nonce(application_nonce, transport_pdu); 805*77ba3d3fSMatthias Ringwald } else { 806*77ba3d3fSMatthias Ringwald transport_segmented_setup_application_nonce(application_nonce, transport_pdu); 807*77ba3d3fSMatthias Ringwald } 808*77ba3d3fSMatthias Ringwald 809*77ba3d3fSMatthias Ringwald // get app or device key 810*77ba3d3fSMatthias Ringwald const mesh_transport_key_t * appkey = mesh_transport_key_get(appkey_index); 811*77ba3d3fSMatthias Ringwald mesh_print_hex("AppOrDevKey", appkey->key, 16); 812*77ba3d3fSMatthias Ringwald 813*77ba3d3fSMatthias Ringwald // encrypt ccm 814*77ba3d3fSMatthias Ringwald uint8_t transmic_len = transport_pdu->transmic_len; 815*77ba3d3fSMatthias Ringwald uint16_t access_pdu_len = transport_pdu->len; 816*77ba3d3fSMatthias Ringwald crypto_active = 1; 817*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_init(&ccm, appkey->key, application_nonce, access_pdu_len, aad_len, transmic_len); 818*77ba3d3fSMatthias Ringwald if (virtual_address){ 819*77ba3d3fSMatthias Ringwald mesh_print_hex("LabelUUID", virtual_address->label_uuid, 16); 820*77ba3d3fSMatthias Ringwald btstack_crypto_ccm_digest(&ccm, virtual_address->label_uuid, 16, &mesh_upper_transport_send_segmented_access_pdu_digest, transport_pdu); 821*77ba3d3fSMatthias Ringwald } else { 822*77ba3d3fSMatthias Ringwald mesh_upper_transport_send_segmented_access_pdu_digest(transport_pdu); 823*77ba3d3fSMatthias Ringwald } 824*77ba3d3fSMatthias Ringwald } 825*77ba3d3fSMatthias Ringwald 826*77ba3d3fSMatthias Ringwald void mesh_upper_transport_send_access_pdu(mesh_pdu_t * pdu){ 827*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 828*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 829*77ba3d3fSMatthias Ringwald mesh_upper_transport_send_unsegmented_access_pdu((mesh_network_pdu_t *) pdu); 830*77ba3d3fSMatthias Ringwald break; 831*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 832*77ba3d3fSMatthias Ringwald mesh_upper_transport_send_segmented_access_pdu((mesh_transport_pdu_t *) pdu); 833*77ba3d3fSMatthias Ringwald break; 834*77ba3d3fSMatthias Ringwald default: 835*77ba3d3fSMatthias Ringwald break; 836*77ba3d3fSMatthias Ringwald } 837*77ba3d3fSMatthias Ringwald } 838*77ba3d3fSMatthias Ringwald 839*77ba3d3fSMatthias Ringwald void mesh_upper_transport_set_primary_element_address(uint16_t unicast_address){ 840*77ba3d3fSMatthias Ringwald primary_element_address = unicast_address; 841*77ba3d3fSMatthias Ringwald } 842*77ba3d3fSMatthias Ringwald 843*77ba3d3fSMatthias Ringwald 844*77ba3d3fSMatthias Ringwald void mesh_upper_transport_register_access_message_handler(void (*callback)(mesh_pdu_t *pdu)){ 845*77ba3d3fSMatthias Ringwald mesh_access_message_handler = callback; 846*77ba3d3fSMatthias Ringwald } 847*77ba3d3fSMatthias Ringwald 848*77ba3d3fSMatthias Ringwald void mesh_upper_transport_register_control_message_handler(void (*callback)(mesh_pdu_t *pdu)){ 849*77ba3d3fSMatthias Ringwald mesh_control_message_handler = callback; 850*77ba3d3fSMatthias Ringwald } 851*77ba3d3fSMatthias Ringwald 852*77ba3d3fSMatthias Ringwald void mesh_upper_transport_set_higher_layer_handler(void (*pdu_handler)( mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu)){ 853*77ba3d3fSMatthias Ringwald higher_layer_handler = pdu_handler; 854*77ba3d3fSMatthias Ringwald } 855*77ba3d3fSMatthias Ringwald 856*77ba3d3fSMatthias Ringwald void mesh_transport_init(){ 857*77ba3d3fSMatthias Ringwald mesh_lower_transport_init(); 858*77ba3d3fSMatthias Ringwald mesh_lower_transport_set_higher_layer_handler(&mesh_upper_transport_pdu_handler); 859*77ba3d3fSMatthias Ringwald } 860*77ba3d3fSMatthias Ringwald 861*77ba3d3fSMatthias Ringwald static void mesh_transport_run(void){ 862*77ba3d3fSMatthias Ringwald while(!btstack_linked_list_empty(&upper_transport_incoming)){ 863*77ba3d3fSMatthias Ringwald 864*77ba3d3fSMatthias Ringwald if (crypto_active) return; 865*77ba3d3fSMatthias Ringwald 866*77ba3d3fSMatthias Ringwald // peek at next message 867*77ba3d3fSMatthias Ringwald mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_get_first_item(&upper_transport_incoming); 868*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu; 869*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * network_pdu; 870*77ba3d3fSMatthias Ringwald switch (pdu->pdu_type){ 871*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_NETWORK: 872*77ba3d3fSMatthias Ringwald network_pdu = (mesh_network_pdu_t *) pdu; 873*77ba3d3fSMatthias Ringwald // control? 874*77ba3d3fSMatthias Ringwald if (mesh_network_control(network_pdu)) { 875*77ba3d3fSMatthias Ringwald (void) btstack_linked_list_pop(&upper_transport_incoming); 876*77ba3d3fSMatthias Ringwald mesh_upper_unsegmented_control_message_received(network_pdu); 877*77ba3d3fSMatthias Ringwald } else { 878*77ba3d3fSMatthias Ringwald mesh_network_pdu_t * decode_pdu = mesh_network_pdu_get(); 879*77ba3d3fSMatthias Ringwald if (!decode_pdu) return; 880*77ba3d3fSMatthias Ringwald // get encoded network pdu and start processing 881*77ba3d3fSMatthias Ringwald network_pdu_in_validation = network_pdu; 882*77ba3d3fSMatthias Ringwald (void) btstack_linked_list_pop(&upper_transport_incoming); 883*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_unsegmented_access_message(decode_pdu); 884*77ba3d3fSMatthias Ringwald } 885*77ba3d3fSMatthias Ringwald break; 886*77ba3d3fSMatthias Ringwald case MESH_PDU_TYPE_TRANSPORT: 887*77ba3d3fSMatthias Ringwald transport_pdu = (mesh_transport_pdu_t *) pdu; 888*77ba3d3fSMatthias Ringwald uint8_t ctl = mesh_transport_ctl(transport_pdu); 889*77ba3d3fSMatthias Ringwald if (ctl){ 890*77ba3d3fSMatthias Ringwald printf("Ignoring Segmented Control Message\n"); 891*77ba3d3fSMatthias Ringwald (void) btstack_linked_list_pop(&upper_transport_incoming); 892*77ba3d3fSMatthias Ringwald mesh_lower_transport_message_processed_by_higher_layer((mesh_pdu_t *) transport_pdu); 893*77ba3d3fSMatthias Ringwald } else { 894*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * decode_pdu = mesh_transport_pdu_get(); 895*77ba3d3fSMatthias Ringwald if (!decode_pdu) return; 896*77ba3d3fSMatthias Ringwald // get encoded transport pdu and start processing 897*77ba3d3fSMatthias Ringwald transport_pdu_in_validation = transport_pdu; 898*77ba3d3fSMatthias Ringwald (void) btstack_linked_list_pop(&upper_transport_incoming); 899*77ba3d3fSMatthias Ringwald mesh_upper_transport_process_message(decode_pdu); 900*77ba3d3fSMatthias Ringwald } 901*77ba3d3fSMatthias Ringwald break; 902*77ba3d3fSMatthias Ringwald default: 903*77ba3d3fSMatthias Ringwald break; 904*77ba3d3fSMatthias Ringwald } 905*77ba3d3fSMatthias Ringwald } 906*77ba3d3fSMatthias Ringwald } 907*77ba3d3fSMatthias Ringwald 908*77ba3d3fSMatthias Ringwald // buffer pool 909*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * mesh_transport_pdu_get(void){ 910*77ba3d3fSMatthias Ringwald mesh_transport_pdu_t * transport_pdu = btstack_memory_mesh_transport_pdu_get(); 911*77ba3d3fSMatthias Ringwald if (transport_pdu) { 912*77ba3d3fSMatthias Ringwald memset(transport_pdu, 0, sizeof(mesh_transport_pdu_t)); 913*77ba3d3fSMatthias Ringwald transport_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_TRANSPORT; 914*77ba3d3fSMatthias Ringwald } 915*77ba3d3fSMatthias Ringwald return transport_pdu; 916*77ba3d3fSMatthias Ringwald } 917*77ba3d3fSMatthias Ringwald 918*77ba3d3fSMatthias Ringwald void mesh_transport_pdu_free(mesh_transport_pdu_t * transport_pdu){ 919*77ba3d3fSMatthias Ringwald btstack_memory_mesh_transport_pdu_free(transport_pdu); 920*77ba3d3fSMatthias Ringwald } 921