177ba3d3fSMatthias Ringwald /* 277ba3d3fSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 377ba3d3fSMatthias Ringwald * 477ba3d3fSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 577ba3d3fSMatthias Ringwald * modification, are permitted provided that the following conditions 677ba3d3fSMatthias Ringwald * are met: 777ba3d3fSMatthias Ringwald * 877ba3d3fSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 977ba3d3fSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1077ba3d3fSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1177ba3d3fSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1277ba3d3fSMatthias Ringwald * documentation and/or other materials provided with the distribution. 1377ba3d3fSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1477ba3d3fSMatthias Ringwald * contributors may be used to endorse or promote products derived 1577ba3d3fSMatthias Ringwald * from this software without specific prior written permission. 1677ba3d3fSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1777ba3d3fSMatthias Ringwald * personal benefit and not for any commercial purpose or for 1877ba3d3fSMatthias Ringwald * monetary gain. 1977ba3d3fSMatthias Ringwald * 2077ba3d3fSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2177ba3d3fSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2277ba3d3fSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2577ba3d3fSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2677ba3d3fSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2777ba3d3fSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2877ba3d3fSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2977ba3d3fSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3077ba3d3fSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3177ba3d3fSMatthias Ringwald * SUCH DAMAGE. 3277ba3d3fSMatthias Ringwald * 3377ba3d3fSMatthias Ringwald * Please inquire about commercial licensing options at 3477ba3d3fSMatthias Ringwald * [email protected] 3577ba3d3fSMatthias Ringwald * 3677ba3d3fSMatthias Ringwald */ 3777ba3d3fSMatthias Ringwald 382d4000d1SMatthias Ringwald #define BTSTACK_FILE__ "pb_adv.c" 3977ba3d3fSMatthias Ringwald 40f4854a5eSMatthias Ringwald #include "pb_adv.h" 41f4854a5eSMatthias Ringwald 42*cb7b3e6fSMatthias Ringwald #include <inttypes.h> 4377ba3d3fSMatthias Ringwald #include <stdint.h> 4477ba3d3fSMatthias Ringwald #include <stdio.h> 4577ba3d3fSMatthias Ringwald #include <stdlib.h> 4677ba3d3fSMatthias Ringwald #include <string.h> 47f4854a5eSMatthias Ringwald 48f4854a5eSMatthias Ringwald #include "btstack_debug.h" 49f4854a5eSMatthias Ringwald #include "btstack_event.h" 50f4854a5eSMatthias Ringwald #include "btstack_util.h" 51f4854a5eSMatthias Ringwald 5277ba3d3fSMatthias Ringwald #include "mesh/adv_bearer.h" 5377ba3d3fSMatthias Ringwald #include "mesh/beacon.h" 548936a143SMatthias Ringwald #include "mesh/mesh_node.h" 55f4854a5eSMatthias Ringwald #include "mesh/provisioning.h" 5677ba3d3fSMatthias Ringwald 5777ba3d3fSMatthias Ringwald #define PB_ADV_LINK_OPEN_RETRANSMIT_MS 1000 58d16ad46bSMatthias Ringwald #define PB_ADV_LINK_OPEN_TIMEOUT_MS 60000 59d16ad46bSMatthias Ringwald #define PB_ADV_LINK_OPEN_RETRIES (PB_ADV_LINK_OPEN_TIMEOUT_MS / PB_ADV_LINK_OPEN_RETRANSMIT_MS) 6077ba3d3fSMatthias Ringwald static void pb_adv_run(void); 6177ba3d3fSMatthias Ringwald 6277ba3d3fSMatthias Ringwald /* taps: 32 31 29 1; characteristic polynomial: x^32 + x^31 + x^29 + x + 1 */ 6377ba3d3fSMatthias Ringwald #define LFSR(a) ((a >> 1) ^ (uint32_t)((0 - (a & 1u)) & 0xd0000001u)) 6477ba3d3fSMatthias Ringwald 6577ba3d3fSMatthias Ringwald // PB-ADV - Provisioning Bearer using Advertisement Bearer 6677ba3d3fSMatthias Ringwald 6777ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_OPEN 0x00 6877ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_ACK 0x01 6977ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_CLOSE 0x02 7077ba3d3fSMatthias Ringwald 7177ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS 30000 7277ba3d3fSMatthias Ringwald 7377ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_PDU_SIZE 100 7477ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_SEGMENTS 8 7577ba3d3fSMatthias Ringwald #define MESH_PB_ADV_START_PAYLOAD 20 7677ba3d3fSMatthias Ringwald #define MESH_PB_ADV_CONT_PAYLOAD 23 7777ba3d3fSMatthias Ringwald 7877ba3d3fSMatthias Ringwald typedef enum mesh_gpcf_format { 7977ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_START = 0, 8077ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_ACK, 8177ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_CONT, 8277ba3d3fSMatthias Ringwald MESH_GPCF_PROV_BEARER_CONTROL, 8377ba3d3fSMatthias Ringwald } mesh_gpcf_format_t; 8477ba3d3fSMatthias Ringwald 8577ba3d3fSMatthias Ringwald typedef enum { 8677ba3d3fSMatthias Ringwald LINK_STATE_W4_OPEN, 8777ba3d3fSMatthias Ringwald LINK_STATE_W2_SEND_ACK, 8877ba3d3fSMatthias Ringwald LINK_STATE_W4_ACK, 8977ba3d3fSMatthias Ringwald LINK_STATE_OPEN, 9077ba3d3fSMatthias Ringwald LINK_STATE_CLOSING, 9177ba3d3fSMatthias Ringwald } link_state_t; 9277ba3d3fSMatthias Ringwald static link_state_t link_state; 9377ba3d3fSMatthias Ringwald 9477ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER 9577ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_peer_device_uuid; 96d16ad46bSMatthias Ringwald static uint8_t pb_adv_provisioner_open_countdown; 9777ba3d3fSMatthias Ringwald #endif 9877ba3d3fSMatthias Ringwald 9977ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_buffer[MESH_PB_ADV_MAX_PDU_SIZE]; // TODO: how large are prov messages? 10077ba3d3fSMatthias Ringwald 10194d617e4SMatthias Ringwald // single adv link, roles: provisioner = 1, device = 0 10277ba3d3fSMatthias Ringwald static uint16_t pb_adv_cid = 1; 10377ba3d3fSMatthias Ringwald static uint8_t pb_adv_provisioner_role; 10477ba3d3fSMatthias Ringwald 10577ba3d3fSMatthias Ringwald // link state 10677ba3d3fSMatthias Ringwald static uint32_t pb_adv_link_id; 10777ba3d3fSMatthias Ringwald static uint8_t pb_adv_link_close_reason; 10877ba3d3fSMatthias Ringwald static uint8_t pb_adv_link_close_countdown; 1091765fb5dSMatthias Ringwald static bool pb_adv_link_establish_timer_active; 11077ba3d3fSMatthias Ringwald 11177ba3d3fSMatthias Ringwald // random delay for outgoing packets 11277ba3d3fSMatthias Ringwald static uint32_t pb_adv_lfsr; 11377ba3d3fSMatthias Ringwald static uint8_t pb_adv_random_delay_active; 1141765fb5dSMatthias Ringwald 1151765fb5dSMatthias Ringwald // adv link timer used for 1161765fb5dSMatthias Ringwald // establishment: 1171765fb5dSMatthias Ringwald // - device: 60s timeout after receiving link open and sending link ack until first provisioning PDU 1181765fb5dSMatthias Ringwald // - provisioner: 1s timer to send link open messages 1191765fb5dSMatthias Ringwald // open: random delay 1201765fb5dSMatthias Ringwald static btstack_timer_source_t pb_adv_link_timer; 12177ba3d3fSMatthias Ringwald 12277ba3d3fSMatthias Ringwald // incoming message 12377ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_transaction_nr_prev; 12477ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_in_len; // 12577ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_fcs; 12677ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_last_segment; 12777ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_segments_missing; // bitfield for segmentes 1-n 12877ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_transaction_nr; 12977ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_send_ack; 13077ba3d3fSMatthias Ringwald 1314a72aacaSMatthias Ringwald // outgoing message 13277ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_active; 13377ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_transaction_nr; 13477ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_completed_transaction_nr; 13577ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_out_len; 13677ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_out_pos; 13777ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_seg; 13877ba3d3fSMatthias Ringwald static uint32_t pb_adv_msg_out_start; 13977ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_msg_out_buffer; 14077ba3d3fSMatthias Ringwald 14194d617e4SMatthias Ringwald static btstack_packet_handler_t pb_adv_device_packet_handler; 14294d617e4SMatthias Ringwald static btstack_packet_handler_t pb_adv_provisioner_packet_handler; 14377ba3d3fSMatthias Ringwald 14477ba3d3fSMatthias Ringwald // poor man's random number generator 14577ba3d3fSMatthias Ringwald static uint32_t pb_adv_random(void){ 14677ba3d3fSMatthias Ringwald pb_adv_lfsr = LFSR(pb_adv_lfsr); 14777ba3d3fSMatthias Ringwald return pb_adv_lfsr; 14877ba3d3fSMatthias Ringwald } 14977ba3d3fSMatthias Ringwald 15094d617e4SMatthias Ringwald static void pb_adv_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){ 15194d617e4SMatthias Ringwald if (pb_adv_provisioner_role == 0){ 15294d617e4SMatthias Ringwald (*pb_adv_device_packet_handler)(packet_type, channel, packet, size); 15394d617e4SMatthias Ringwald } else { 15494d617e4SMatthias Ringwald (*pb_adv_provisioner_packet_handler)(packet_type, channel, packet, size); 15594d617e4SMatthias Ringwald } 15694d617e4SMatthias Ringwald } 15794d617e4SMatthias Ringwald 15877ba3d3fSMatthias Ringwald static void pb_adv_emit_pdu_sent(uint8_t status){ 15977ba3d3fSMatthias Ringwald uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 16077ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 16177ba3d3fSMatthias Ringwald } 16277ba3d3fSMatthias Ringwald 163f8962c62SMatthias Ringwald static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_transport_cid){ 16477ba3d3fSMatthias Ringwald uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status}; 165f8962c62SMatthias Ringwald little_endian_store_16(event, 4, pb_transport_cid); 16630a044b0SMilanka Ringwald event[6] = MESH_PB_TYPE_ADV; 16777ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 16877ba3d3fSMatthias Ringwald } 16977ba3d3fSMatthias Ringwald 170f8962c62SMatthias Ringwald static void pb_adv_emit_link_close(uint16_t pb_transport_cid, uint8_t reason){ 171f8962c62SMatthias Ringwald uint8_t event[6] = { HCI_EVENT_MESH_META, 3, MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED}; 172f8962c62SMatthias Ringwald little_endian_store_16(event, 3, pb_transport_cid); 173f8962c62SMatthias Ringwald event[5] = reason; 17477ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 17577ba3d3fSMatthias Ringwald } 17677ba3d3fSMatthias Ringwald 1774a72aacaSMatthias Ringwald static void pb_adv_device_link_timeout(btstack_timer_source_t * ts){ 1784a72aacaSMatthias Ringwald UNUSED(ts); 1794a72aacaSMatthias Ringwald // timeout occured 1804a72aacaSMatthias Ringwald link_state = LINK_STATE_W4_OPEN; 181*cb7b3e6fSMatthias Ringwald log_info("link timeout, %08" PRIx32, pb_adv_link_id); 182*cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link timeout %08" PRIx32 "\n", pb_adv_link_id); 1834a72aacaSMatthias Ringwald pb_adv_emit_link_close(pb_adv_cid, ERROR_CODE_PAGE_TIMEOUT); 1844a72aacaSMatthias Ringwald } 1854a72aacaSMatthias Ringwald 18677ba3d3fSMatthias Ringwald static void pb_adv_handle_bearer_control(uint32_t link_id, uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){ 187f843ee5dSMatthias Ringwald UNUSED(transaction_nr); 188f843ee5dSMatthias Ringwald UNUSED(size); 189f843ee5dSMatthias Ringwald 19077ba3d3fSMatthias Ringwald uint8_t bearer_opcode = pdu[0] >> 2; 19177ba3d3fSMatthias Ringwald uint8_t reason; 1928936a143SMatthias Ringwald const uint8_t * own_device_uuid; 19377ba3d3fSMatthias Ringwald switch (bearer_opcode){ 19477ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_OPEN: // Open a session on a bearer with a device 19577ba3d3fSMatthias Ringwald // does it match our device_uuid? 1968936a143SMatthias Ringwald own_device_uuid = mesh_node_get_device_uuid(); 1978936a143SMatthias Ringwald if (!own_device_uuid) break; 1988936a143SMatthias Ringwald if (memcmp(&pdu[1], own_device_uuid, 16) != 0) break; 1991765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer); 2001765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_TIMEOUT_MS); 2011765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_device_link_timeout); 2021765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer); 2031765fb5dSMatthias Ringwald pb_adv_link_establish_timer_active = true; 20477ba3d3fSMatthias Ringwald switch(link_state){ 20577ba3d3fSMatthias Ringwald case LINK_STATE_W4_OPEN: 20677ba3d3fSMatthias Ringwald pb_adv_link_id = link_id; 20777ba3d3fSMatthias Ringwald pb_adv_provisioner_role = 0; 20877ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0xff; // first transaction nr will be 0x00 20977ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = 0xff; 210*cb7b3e6fSMatthias Ringwald log_info("link open, id %08" PRIx32, pb_adv_link_id); 211*cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link Open %08" PRIx32 "\n", pb_adv_link_id); 21277ba3d3fSMatthias Ringwald link_state = LINK_STATE_W2_SEND_ACK; 2134662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 214d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid); 21577ba3d3fSMatthias Ringwald break; 21677ba3d3fSMatthias Ringwald case LINK_STATE_OPEN: 21777ba3d3fSMatthias Ringwald if (pb_adv_link_id != link_id) break; 21877ba3d3fSMatthias Ringwald log_info("link open, resend ACK"); 21977ba3d3fSMatthias Ringwald link_state = LINK_STATE_W2_SEND_ACK; 2204662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 22177ba3d3fSMatthias Ringwald break; 22277ba3d3fSMatthias Ringwald default: 22377ba3d3fSMatthias Ringwald break; 22477ba3d3fSMatthias Ringwald } 22577ba3d3fSMatthias Ringwald break; 22677ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER 22777ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_ACK: // Acknowledge a session on a bearer 22877ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_ACK) break; 22977ba3d3fSMatthias Ringwald link_state = LINK_STATE_OPEN; 23077ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0; 23177ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0x7f; // first transaction nr will be 0x80 23277ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = 0x7f; 2331765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer); 234*cb7b3e6fSMatthias Ringwald log_info("link open, id %08" PRIx32, pb_adv_link_id); 235*cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link Open %08" PRIx32 "\n", pb_adv_link_id); 236d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid); 23777ba3d3fSMatthias Ringwald break; 23877ba3d3fSMatthias Ringwald #endif 23977ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_CLOSE: // Close a session on a bearer 24077ba3d3fSMatthias Ringwald // does it match link id 24177ba3d3fSMatthias Ringwald if (link_id != pb_adv_link_id) break; 2422e9a36a1SMatthias Ringwald if (link_state == LINK_STATE_W4_OPEN) break; 2431765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer); 24477ba3d3fSMatthias Ringwald reason = pdu[1]; 24577ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_OPEN; 24677ba3d3fSMatthias Ringwald log_info("link close, reason %x", reason); 24777ba3d3fSMatthias Ringwald pb_adv_emit_link_close(pb_adv_cid, reason); 24877ba3d3fSMatthias Ringwald break; 24977ba3d3fSMatthias Ringwald default: 25077ba3d3fSMatthias Ringwald log_info("BearerOpcode %x reserved for future use\n", bearer_opcode); 25177ba3d3fSMatthias Ringwald break; 25277ba3d3fSMatthias Ringwald } 25377ba3d3fSMatthias Ringwald } 25477ba3d3fSMatthias Ringwald 25577ba3d3fSMatthias Ringwald static void pb_adv_pdu_complete(void){ 25677ba3d3fSMatthias Ringwald 25777ba3d3fSMatthias Ringwald // Verify FCS 25877ba3d3fSMatthias Ringwald uint8_t pdu_crc = btstack_crc8_calc((uint8_t*)pb_adv_msg_in_buffer, pb_adv_msg_in_len); 25977ba3d3fSMatthias Ringwald if (pdu_crc != pb_adv_msg_in_fcs){ 26077ba3d3fSMatthias Ringwald printf("Incoming PDU: fcs %02x, calculated %02x -> drop packet\n", pb_adv_msg_in_fcs, btstack_crc8_calc(pb_adv_msg_in_buffer, pb_adv_msg_in_len)); 26177ba3d3fSMatthias Ringwald return; 26277ba3d3fSMatthias Ringwald } 26377ba3d3fSMatthias Ringwald 26477ba3d3fSMatthias Ringwald printf("PB-ADV: %02x complete\n", pb_adv_msg_in_transaction_nr); 26577ba3d3fSMatthias Ringwald 26677ba3d3fSMatthias Ringwald // transaction complete 26777ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = pb_adv_msg_in_transaction_nr; 26877ba3d3fSMatthias Ringwald if (pb_adv_provisioner_role){ 26977ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0x7f; // invalid 27077ba3d3fSMatthias Ringwald } else { 27177ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0xff; // invalid 27277ba3d3fSMatthias Ringwald } 27377ba3d3fSMatthias Ringwald 27477ba3d3fSMatthias Ringwald // Ack Transaction 27577ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1; 27677ba3d3fSMatthias Ringwald pb_adv_run(); 27777ba3d3fSMatthias Ringwald 27877ba3d3fSMatthias Ringwald // Forward to Provisioning 27977ba3d3fSMatthias Ringwald pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, pb_adv_msg_in_buffer, pb_adv_msg_in_len); 28077ba3d3fSMatthias Ringwald } 28177ba3d3fSMatthias Ringwald 28277ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_start(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){ 28377ba3d3fSMatthias Ringwald 28477ba3d3fSMatthias Ringwald // resend ack if packet from previous transaction received 28577ba3d3fSMatthias Ringwald if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){ 28677ba3d3fSMatthias Ringwald printf("PB_ADV: %02x transaction complete, resending ack \n", transaction_nr); 28777ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1; 28877ba3d3fSMatthias Ringwald return; 28977ba3d3fSMatthias Ringwald } 29077ba3d3fSMatthias Ringwald 29177ba3d3fSMatthias Ringwald // new transaction? 29277ba3d3fSMatthias Ringwald if (transaction_nr != pb_adv_msg_in_transaction_nr){ 29377ba3d3fSMatthias Ringwald 29477ba3d3fSMatthias Ringwald // check len 295205dc738SMatthias Ringwald if (size < 4) return; 296205dc738SMatthias Ringwald 297205dc738SMatthias Ringwald // check len 29877ba3d3fSMatthias Ringwald uint16_t msg_len = big_endian_read_16(pdu, 1); 29977ba3d3fSMatthias Ringwald if (msg_len > MESH_PB_ADV_MAX_PDU_SIZE){ 30077ba3d3fSMatthias Ringwald // abort transaction 30177ba3d3fSMatthias Ringwald return; 30277ba3d3fSMatthias Ringwald } 30377ba3d3fSMatthias Ringwald 30477ba3d3fSMatthias Ringwald // check num segments 30577ba3d3fSMatthias Ringwald uint8_t last_segment = pdu[0] >> 2; 30677ba3d3fSMatthias Ringwald if (last_segment >= MESH_PB_ADV_MAX_SEGMENTS){ 30777ba3d3fSMatthias Ringwald // abort transaction 30877ba3d3fSMatthias Ringwald return; 30977ba3d3fSMatthias Ringwald } 31077ba3d3fSMatthias Ringwald 31177ba3d3fSMatthias Ringwald printf("PB-ADV: %02x started\n", transaction_nr); 31277ba3d3fSMatthias Ringwald 31377ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = transaction_nr; 31477ba3d3fSMatthias Ringwald pb_adv_msg_in_len = msg_len; 31577ba3d3fSMatthias Ringwald pb_adv_msg_in_fcs = pdu[3]; 31677ba3d3fSMatthias Ringwald pb_adv_msg_in_last_segment = last_segment; 31777ba3d3fSMatthias Ringwald 31877ba3d3fSMatthias Ringwald // set bits for segments 1..n (segment 0 already received in this message) 31977ba3d3fSMatthias Ringwald pb_adv_msg_in_segments_missing = (1 << last_segment) - 1; 32077ba3d3fSMatthias Ringwald 32177ba3d3fSMatthias Ringwald // store payload 32277ba3d3fSMatthias Ringwald uint16_t payload_len = size - 4; 3236535961aSMatthias Ringwald (void)memcpy(pb_adv_msg_in_buffer, &pdu[4], payload_len); 32477ba3d3fSMatthias Ringwald 32577ba3d3fSMatthias Ringwald // complete? 32677ba3d3fSMatthias Ringwald if (pb_adv_msg_in_segments_missing == 0){ 32777ba3d3fSMatthias Ringwald pb_adv_pdu_complete(); 32877ba3d3fSMatthias Ringwald } 32977ba3d3fSMatthias Ringwald } 33077ba3d3fSMatthias Ringwald } 33177ba3d3fSMatthias Ringwald 33277ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_cont(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){ 33377ba3d3fSMatthias Ringwald 33477ba3d3fSMatthias Ringwald // check transaction nr 33577ba3d3fSMatthias Ringwald if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){ 33677ba3d3fSMatthias Ringwald printf("PB_ADV: %02x transaction complete, resending resending ack\n", transaction_nr); 33777ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1; 33877ba3d3fSMatthias Ringwald return; 33977ba3d3fSMatthias Ringwald } 34077ba3d3fSMatthias Ringwald 34177ba3d3fSMatthias Ringwald if (transaction_nr != pb_adv_msg_in_transaction_nr){ 34277ba3d3fSMatthias Ringwald printf("PB-ADV: %02x received msg for transaction nr %x\n", pb_adv_msg_in_transaction_nr, transaction_nr); 34377ba3d3fSMatthias Ringwald return; 34477ba3d3fSMatthias Ringwald } 34577ba3d3fSMatthias Ringwald 34677ba3d3fSMatthias Ringwald // validate seg nr 34777ba3d3fSMatthias Ringwald uint8_t seg = pdu[0] >> 2; 34877ba3d3fSMatthias Ringwald if (seg >= MESH_PB_ADV_MAX_SEGMENTS || seg == 0){ 34977ba3d3fSMatthias Ringwald return; 35077ba3d3fSMatthias Ringwald } 35177ba3d3fSMatthias Ringwald 35277ba3d3fSMatthias Ringwald // check if segment already received 35377ba3d3fSMatthias Ringwald uint8_t seg_mask = 1 << (seg-1); 35477ba3d3fSMatthias Ringwald if ((pb_adv_msg_in_segments_missing & seg_mask) == 0){ 35577ba3d3fSMatthias Ringwald printf("PB-ADV: %02x, segment %u already received\n", transaction_nr, seg); 35677ba3d3fSMatthias Ringwald return; 35777ba3d3fSMatthias Ringwald } 35877ba3d3fSMatthias Ringwald printf("PB-ADV: %02x, segment %u stored\n", transaction_nr, seg); 35977ba3d3fSMatthias Ringwald 36077ba3d3fSMatthias Ringwald // calculate offset and fragment size 36177ba3d3fSMatthias Ringwald uint16_t msg_pos = MESH_PB_ADV_START_PAYLOAD + (seg-1) * MESH_PB_ADV_CONT_PAYLOAD; 36277ba3d3fSMatthias Ringwald uint16_t fragment_size = size - 1; 36377ba3d3fSMatthias Ringwald 36477ba3d3fSMatthias Ringwald // check size if last segment 36577ba3d3fSMatthias Ringwald if (seg == pb_adv_msg_in_last_segment && (msg_pos + fragment_size) != pb_adv_msg_in_len){ 36677ba3d3fSMatthias Ringwald // last segment has invalid size 36777ba3d3fSMatthias Ringwald return; 36877ba3d3fSMatthias Ringwald } 36977ba3d3fSMatthias Ringwald 37077ba3d3fSMatthias Ringwald // store segment and mark as received 3716535961aSMatthias Ringwald (void)memcpy(&pb_adv_msg_in_buffer[msg_pos], &pdu[1], fragment_size); 37277ba3d3fSMatthias Ringwald pb_adv_msg_in_segments_missing &= ~seg_mask; 37377ba3d3fSMatthias Ringwald 37477ba3d3fSMatthias Ringwald // last segment 37577ba3d3fSMatthias Ringwald if (pb_adv_msg_in_segments_missing == 0){ 37677ba3d3fSMatthias Ringwald pb_adv_pdu_complete(); 37777ba3d3fSMatthias Ringwald } 37877ba3d3fSMatthias Ringwald } 37977ba3d3fSMatthias Ringwald 3804a72aacaSMatthias Ringwald static void pb_adv_outgoing_transaction_complete(uint8_t status){ 38177ba3d3fSMatthias Ringwald // stop sending 38277ba3d3fSMatthias Ringwald pb_adv_msg_out_active = 0; 38377ba3d3fSMatthias Ringwald // emit done 38477ba3d3fSMatthias Ringwald pb_adv_emit_pdu_sent(status); 38577ba3d3fSMatthias Ringwald // keep track of ack'ed transactions 38677ba3d3fSMatthias Ringwald pb_adv_msg_out_completed_transaction_nr = pb_adv_msg_out_transaction_nr; 38777ba3d3fSMatthias Ringwald // increment outgoing transaction nr 38877ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr++; 38977ba3d3fSMatthias Ringwald if (pb_adv_msg_out_transaction_nr == 0x00){ 39077ba3d3fSMatthias Ringwald // Device role 39177ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x80; 39277ba3d3fSMatthias Ringwald } 39377ba3d3fSMatthias Ringwald if (pb_adv_msg_out_transaction_nr == 0x80){ 39477ba3d3fSMatthias Ringwald // Provisioner role 39577ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x00; 39677ba3d3fSMatthias Ringwald } 39777ba3d3fSMatthias Ringwald } 39877ba3d3fSMatthias Ringwald 39977ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_ack(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){ 400f843ee5dSMatthias Ringwald UNUSED(pdu); 401f843ee5dSMatthias Ringwald UNUSED(size); 40277ba3d3fSMatthias Ringwald if (transaction_nr == pb_adv_msg_out_transaction_nr){ 40377ba3d3fSMatthias Ringwald printf("PB-ADV: %02x ACK received\n", transaction_nr); 4044a72aacaSMatthias Ringwald pb_adv_outgoing_transaction_complete(ERROR_CODE_SUCCESS); 40577ba3d3fSMatthias Ringwald } else if (transaction_nr == pb_adv_msg_out_completed_transaction_nr){ 40677ba3d3fSMatthias Ringwald // Transaction ack received again 40777ba3d3fSMatthias Ringwald } else { 40877ba3d3fSMatthias Ringwald printf("PB-ADV: %02x unexpected Transaction ACK %x recevied\n", pb_adv_msg_out_transaction_nr, transaction_nr); 40977ba3d3fSMatthias Ringwald } 41077ba3d3fSMatthias Ringwald } 41177ba3d3fSMatthias Ringwald 41277ba3d3fSMatthias Ringwald static int pb_adv_packet_to_send(void){ 41377ba3d3fSMatthias Ringwald return pb_adv_msg_in_send_ack || pb_adv_msg_out_active || (link_state == LINK_STATE_W4_ACK); 41477ba3d3fSMatthias Ringwald } 41577ba3d3fSMatthias Ringwald 41677ba3d3fSMatthias Ringwald static void pb_adv_timer_handler(btstack_timer_source_t * ts){ 4172983fbcbSMatthias Ringwald UNUSED(ts); 41877ba3d3fSMatthias Ringwald pb_adv_random_delay_active = 0; 41977ba3d3fSMatthias Ringwald if (!pb_adv_packet_to_send()) return; 4204662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 42177ba3d3fSMatthias Ringwald } 42277ba3d3fSMatthias Ringwald 42377ba3d3fSMatthias Ringwald static void pb_adv_run(void){ 42477ba3d3fSMatthias Ringwald if (!pb_adv_packet_to_send()) return; 42577ba3d3fSMatthias Ringwald if (pb_adv_random_delay_active) return; 42677ba3d3fSMatthias Ringwald 42777ba3d3fSMatthias Ringwald // spec recommends 20-50 ms, we use 20-51 ms 42877ba3d3fSMatthias Ringwald pb_adv_random_delay_active = 1; 42977ba3d3fSMatthias Ringwald uint16_t random_delay_ms = 20 + (pb_adv_random() & 0x1f); 43077ba3d3fSMatthias Ringwald log_info("random delay %u ms", random_delay_ms); 4311765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler); 4321765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, random_delay_ms); 4331765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer); 43477ba3d3fSMatthias Ringwald } 43577ba3d3fSMatthias Ringwald 43677ba3d3fSMatthias Ringwald static void pb_adv_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 4372983fbcbSMatthias Ringwald UNUSED(channel); 4382983fbcbSMatthias Ringwald 43977ba3d3fSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 440205dc738SMatthias Ringwald if (size < 3) return; 441205dc738SMatthias Ringwald 44277ba3d3fSMatthias Ringwald const uint8_t * data; 44377ba3d3fSMatthias Ringwald uint8_t length; 44477ba3d3fSMatthias Ringwald uint32_t link_id; 44577ba3d3fSMatthias Ringwald uint8_t transaction_nr; 44677ba3d3fSMatthias Ringwald uint8_t generic_provisioning_control; 44777ba3d3fSMatthias Ringwald switch(packet[0]){ 44877ba3d3fSMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT: 449205dc738SMatthias Ringwald // check minimal size 450205dc738SMatthias Ringwald if (size < (12 + 8)) return; 451205dc738SMatthias Ringwald 452f843ee5dSMatthias Ringwald // data starts at offset 12 453f843ee5dSMatthias Ringwald data = &packet[12]; 45477ba3d3fSMatthias Ringwald // PDB ADV PDU 45577ba3d3fSMatthias Ringwald length = data[0]; 456f843ee5dSMatthias Ringwald 457f843ee5dSMatthias Ringwald // validate length field 458f843ee5dSMatthias Ringwald if ((12 + length) > size) return; 459f843ee5dSMatthias Ringwald 46077ba3d3fSMatthias Ringwald link_id = big_endian_read_32(data, 2); 46177ba3d3fSMatthias Ringwald transaction_nr = data[6]; 46277ba3d3fSMatthias Ringwald // generic provision PDU 46377ba3d3fSMatthias Ringwald generic_provisioning_control = data[7]; 46477ba3d3fSMatthias Ringwald mesh_gpcf_format_t generic_provisioning_control_format = (mesh_gpcf_format_t) generic_provisioning_control & 3; 46577ba3d3fSMatthias Ringwald 46677ba3d3fSMatthias Ringwald // unless, we're waiting for LINK_OPEN, check link_id 46777ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_OPEN){ 46877ba3d3fSMatthias Ringwald if (link_id != pb_adv_link_id) break; 46977ba3d3fSMatthias Ringwald } 47077ba3d3fSMatthias Ringwald 47177ba3d3fSMatthias Ringwald if (generic_provisioning_control_format == MESH_GPCF_PROV_BEARER_CONTROL){ 47277ba3d3fSMatthias Ringwald pb_adv_handle_bearer_control(link_id, transaction_nr, &data[7], length-6); 47377ba3d3fSMatthias Ringwald break; 47477ba3d3fSMatthias Ringwald } 47577ba3d3fSMatthias Ringwald 47677ba3d3fSMatthias Ringwald // verify link id and link state 47777ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_OPEN) break; 47877ba3d3fSMatthias Ringwald 4794a72aacaSMatthias Ringwald // stop link establishment timer 4801765fb5dSMatthias Ringwald if (pb_adv_link_establish_timer_active) { 4811765fb5dSMatthias Ringwald pb_adv_link_establish_timer_active = false; 4821765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer); 4831765fb5dSMatthias Ringwald } 4844a72aacaSMatthias Ringwald 48577ba3d3fSMatthias Ringwald switch (generic_provisioning_control_format){ 48677ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_START: 48777ba3d3fSMatthias Ringwald pb_adv_handle_transaction_start(transaction_nr, &data[7], length-6); 48877ba3d3fSMatthias Ringwald break; 48977ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_CONT: 49077ba3d3fSMatthias Ringwald pb_adv_handle_transaction_cont(transaction_nr, &data[7], length-6); 49177ba3d3fSMatthias Ringwald break; 49277ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_ACK: 49377ba3d3fSMatthias Ringwald pb_adv_handle_transaction_ack(transaction_nr, &data[7], length-6); 49477ba3d3fSMatthias Ringwald break; 49577ba3d3fSMatthias Ringwald default: 49677ba3d3fSMatthias Ringwald break; 49777ba3d3fSMatthias Ringwald } 49877ba3d3fSMatthias Ringwald pb_adv_run(); 49977ba3d3fSMatthias Ringwald break; 50077ba3d3fSMatthias Ringwald case HCI_EVENT_MESH_META: 50177ba3d3fSMatthias Ringwald switch(packet[2]){ 50277ba3d3fSMatthias Ringwald case MESH_SUBEVENT_CAN_SEND_NOW: 503480ff3cbSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER 50477ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_W4_ACK){ 505d16ad46bSMatthias Ringwald pb_adv_provisioner_open_countdown--; 506d16ad46bSMatthias Ringwald if (pb_adv_provisioner_open_countdown == 0){ 507d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_PAGE_TIMEOUT, pb_adv_cid); 508d16ad46bSMatthias Ringwald break; 509d16ad46bSMatthias Ringwald } 51077ba3d3fSMatthias Ringwald // build packet 51177ba3d3fSMatthias Ringwald uint8_t buffer[22]; 51277ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id); 51377ba3d3fSMatthias Ringwald buffer[4] = 0; // Transaction ID = 0 51477ba3d3fSMatthias Ringwald buffer[5] = (0 << 2) | 3; // Link Open | Provisioning Bearer Control 5156535961aSMatthias Ringwald (void)memcpy(&buffer[6], pb_adv_peer_device_uuid, 16); 5164662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer)); 517*cb7b3e6fSMatthias Ringwald log_info("link open %08" PRIx32, pb_adv_link_id); 51877ba3d3fSMatthias Ringwald printf("PB-ADV: Sending Link Open for device uuid: "); 51977ba3d3fSMatthias Ringwald printf_hexdump(pb_adv_peer_device_uuid, 16); 5201765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler); 5211765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_RETRANSMIT_MS); 5221765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer); 52377ba3d3fSMatthias Ringwald break; 52477ba3d3fSMatthias Ringwald } 525480ff3cbSMatthias Ringwald #endif 52677ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_CLOSING){ 527*cb7b3e6fSMatthias Ringwald log_info("link close %08" PRIx32, pb_adv_link_id); 528*cb7b3e6fSMatthias Ringwald printf("PB-ADV: Sending Link Close %08" PRIx32 "\n", pb_adv_link_id); 52977ba3d3fSMatthias Ringwald // build packet 53077ba3d3fSMatthias Ringwald uint8_t buffer[7]; 53177ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id); 53277ba3d3fSMatthias Ringwald buffer[4] = 0; // Transaction ID = 0 53377ba3d3fSMatthias Ringwald buffer[5] = (2 << 2) | 3; // Link Close | Provisioning Bearer Control 53477ba3d3fSMatthias Ringwald buffer[6] = pb_adv_link_close_reason; 5354662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer)); 53677ba3d3fSMatthias Ringwald pb_adv_link_close_countdown--; 53777ba3d3fSMatthias Ringwald if (pb_adv_link_close_countdown) { 5384662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 53977ba3d3fSMatthias Ringwald } else { 54077ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_OPEN; 54177ba3d3fSMatthias Ringwald } 54277ba3d3fSMatthias Ringwald break; 54377ba3d3fSMatthias Ringwald } 54477ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_W2_SEND_ACK){ 54577ba3d3fSMatthias Ringwald link_state = LINK_STATE_OPEN; 54677ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x80; 54777ba3d3fSMatthias Ringwald // build packet 54877ba3d3fSMatthias Ringwald uint8_t buffer[6]; 54977ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id); 55077ba3d3fSMatthias Ringwald buffer[4] = 0; 55177ba3d3fSMatthias Ringwald buffer[5] = (1 << 2) | 3; // Link Ack | Provisioning Bearer Control 5524662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer)); 553*cb7b3e6fSMatthias Ringwald log_info("link ack %08" PRIx32, pb_adv_link_id); 554*cb7b3e6fSMatthias Ringwald printf("PB-ADV: Sending Link Open Ack %08" PRIx32 "\n", pb_adv_link_id); 55577ba3d3fSMatthias Ringwald break; 55677ba3d3fSMatthias Ringwald } 55777ba3d3fSMatthias Ringwald if (pb_adv_msg_in_send_ack){ 55877ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 0; 55977ba3d3fSMatthias Ringwald uint8_t buffer[6]; 56077ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id); 56177ba3d3fSMatthias Ringwald buffer[4] = pb_adv_msg_in_transaction_nr_prev; 56277ba3d3fSMatthias Ringwald buffer[5] = MESH_GPCF_TRANSACTION_ACK; 5634662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer)); 564*cb7b3e6fSMatthias Ringwald log_info("transaction ack %08" PRIx32, pb_adv_link_id); 56577ba3d3fSMatthias Ringwald printf("PB-ADV: %02x sending ACK\n", pb_adv_msg_in_transaction_nr_prev); 56677ba3d3fSMatthias Ringwald pb_adv_run(); 56777ba3d3fSMatthias Ringwald break; 56877ba3d3fSMatthias Ringwald } 56977ba3d3fSMatthias Ringwald if (pb_adv_msg_out_active){ 57077ba3d3fSMatthias Ringwald 57177ba3d3fSMatthias Ringwald // check timeout for outgoing message 57277ba3d3fSMatthias Ringwald // since uint32_t is used and time now must be greater than pb_adv_msg_out_start, 57377ba3d3fSMatthias Ringwald // this claculation is correct even when the run loop time overruns 57477ba3d3fSMatthias Ringwald uint32_t transaction_time_ms = btstack_run_loop_get_time_ms() - pb_adv_msg_out_start; 57577ba3d3fSMatthias Ringwald if (transaction_time_ms >= MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS){ 5764a72aacaSMatthias Ringwald pb_adv_outgoing_transaction_complete(ERROR_CODE_CONNECTION_TIMEOUT); 57777ba3d3fSMatthias Ringwald return; 57877ba3d3fSMatthias Ringwald } 57977ba3d3fSMatthias Ringwald 58077ba3d3fSMatthias Ringwald uint8_t buffer[29]; // ADV MTU 58177ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id); 58277ba3d3fSMatthias Ringwald buffer[4] = pb_adv_msg_out_transaction_nr; 58377ba3d3fSMatthias Ringwald uint16_t bytes_left; 58477ba3d3fSMatthias Ringwald uint16_t pos; 58577ba3d3fSMatthias Ringwald if (pb_adv_msg_out_pos == 0){ 58677ba3d3fSMatthias Ringwald // Transaction start 58777ba3d3fSMatthias Ringwald int seg_n = pb_adv_msg_out_len / 24; 58877ba3d3fSMatthias Ringwald pb_adv_msg_out_seg = 0; 58977ba3d3fSMatthias Ringwald buffer[5] = seg_n << 2 | MESH_GPCF_TRANSACTION_START; 59077ba3d3fSMatthias Ringwald big_endian_store_16(buffer, 6, pb_adv_msg_out_len); 59177ba3d3fSMatthias Ringwald buffer[8] = btstack_crc8_calc((uint8_t*)pb_adv_msg_out_buffer, pb_adv_msg_out_len); 59277ba3d3fSMatthias Ringwald pos = 9; 59377ba3d3fSMatthias Ringwald bytes_left = 24 - 4; 59477ba3d3fSMatthias Ringwald printf("PB-ADV: %02x Sending Start: ", pb_adv_msg_out_transaction_nr); 59577ba3d3fSMatthias Ringwald } else { 59677ba3d3fSMatthias Ringwald // Transaction continue 59777ba3d3fSMatthias Ringwald buffer[5] = pb_adv_msg_out_seg << 2 | MESH_GPCF_TRANSACTION_CONT; 59877ba3d3fSMatthias Ringwald pos = 6; 59977ba3d3fSMatthias Ringwald bytes_left = 24 - 1; 60077ba3d3fSMatthias Ringwald printf("PB-ADV: %02x Sending Cont: ", pb_adv_msg_out_transaction_nr); 60177ba3d3fSMatthias Ringwald } 60277ba3d3fSMatthias Ringwald pb_adv_msg_out_seg++; 60377ba3d3fSMatthias Ringwald uint16_t bytes_to_copy = btstack_min(bytes_left, pb_adv_msg_out_len - pb_adv_msg_out_pos); 6046535961aSMatthias Ringwald (void)memcpy(&buffer[pos], 6056535961aSMatthias Ringwald &pb_adv_msg_out_buffer[pb_adv_msg_out_pos], 6066535961aSMatthias Ringwald bytes_to_copy); 60777ba3d3fSMatthias Ringwald pos += bytes_to_copy; 60877ba3d3fSMatthias Ringwald printf("bytes %02u, pos %02u, len %02u: ", bytes_to_copy, pb_adv_msg_out_pos, pb_adv_msg_out_len); 60977ba3d3fSMatthias Ringwald printf_hexdump(buffer, pos); 61077ba3d3fSMatthias Ringwald pb_adv_msg_out_pos += bytes_to_copy; 61177ba3d3fSMatthias Ringwald 61277ba3d3fSMatthias Ringwald if (pb_adv_msg_out_pos == pb_adv_msg_out_len){ 61377ba3d3fSMatthias Ringwald // done 61477ba3d3fSMatthias Ringwald pb_adv_msg_out_pos = 0; 61577ba3d3fSMatthias Ringwald } 6164662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, pos); 61777ba3d3fSMatthias Ringwald pb_adv_run(); 61877ba3d3fSMatthias Ringwald break; 61977ba3d3fSMatthias Ringwald } 62077ba3d3fSMatthias Ringwald break; 62177ba3d3fSMatthias Ringwald default: 62277ba3d3fSMatthias Ringwald break; 62377ba3d3fSMatthias Ringwald } 62477ba3d3fSMatthias Ringwald default: 62577ba3d3fSMatthias Ringwald break; 62677ba3d3fSMatthias Ringwald } 62777ba3d3fSMatthias Ringwald } 62877ba3d3fSMatthias Ringwald 6298936a143SMatthias Ringwald void pb_adv_init(void){ 6304662af4aSMatthias Ringwald adv_bearer_register_for_provisioning_pdu(&pb_adv_handler); 63177ba3d3fSMatthias Ringwald pb_adv_lfsr = 0x12345678; 63277ba3d3fSMatthias Ringwald pb_adv_random(); 63377ba3d3fSMatthias Ringwald } 63477ba3d3fSMatthias Ringwald 63594d617e4SMatthias Ringwald void pb_adv_register_device_packet_handler(btstack_packet_handler_t packet_handler){ 63694d617e4SMatthias Ringwald pb_adv_device_packet_handler = packet_handler; 63794d617e4SMatthias Ringwald } 63894d617e4SMatthias Ringwald 63994d617e4SMatthias Ringwald void pb_adv_register_provisioner_packet_handler(btstack_packet_handler_t packet_handler){ 64094d617e4SMatthias Ringwald pb_adv_provisioner_packet_handler = packet_handler; 64177ba3d3fSMatthias Ringwald } 64277ba3d3fSMatthias Ringwald 643f8962c62SMatthias Ringwald void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 644f8962c62SMatthias Ringwald UNUSED(pb_transport_cid); 64577ba3d3fSMatthias Ringwald printf("PB-ADV: Send packet "); 64677ba3d3fSMatthias Ringwald printf_hexdump(pdu, size); 64777ba3d3fSMatthias Ringwald pb_adv_msg_out_buffer = pdu; 64877ba3d3fSMatthias Ringwald pb_adv_msg_out_len = size; 64977ba3d3fSMatthias Ringwald pb_adv_msg_out_pos = 0; 65077ba3d3fSMatthias Ringwald pb_adv_msg_out_start = btstack_run_loop_get_time_ms(); 65177ba3d3fSMatthias Ringwald pb_adv_msg_out_active = 1; 65277ba3d3fSMatthias Ringwald pb_adv_run(); 65377ba3d3fSMatthias Ringwald } 65477ba3d3fSMatthias Ringwald 65577ba3d3fSMatthias Ringwald /** 65677ba3d3fSMatthias Ringwald * Close Link 657f8962c62SMatthias Ringwald * @param pb_transport_cid 65877ba3d3fSMatthias Ringwald */ 659f8962c62SMatthias Ringwald void pb_adv_close_link(uint16_t pb_transport_cid, uint8_t reason){ 66077ba3d3fSMatthias Ringwald switch (link_state){ 66177ba3d3fSMatthias Ringwald case LINK_STATE_W4_ACK: 66277ba3d3fSMatthias Ringwald case LINK_STATE_OPEN: 66377ba3d3fSMatthias Ringwald case LINK_STATE_W2_SEND_ACK: 664f8962c62SMatthias Ringwald pb_adv_emit_link_close(pb_transport_cid, 0); 66577ba3d3fSMatthias Ringwald link_state = LINK_STATE_CLOSING; 66677ba3d3fSMatthias Ringwald pb_adv_link_close_countdown = 3; 66777ba3d3fSMatthias Ringwald pb_adv_link_close_reason = reason; 6684662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 66977ba3d3fSMatthias Ringwald break; 67077ba3d3fSMatthias Ringwald case LINK_STATE_W4_OPEN: 67177ba3d3fSMatthias Ringwald case LINK_STATE_CLOSING: 67277ba3d3fSMatthias Ringwald // nothing to do 67377ba3d3fSMatthias Ringwald break; 6747bbeb3adSMilanka Ringwald default: 6757bbeb3adSMilanka Ringwald btstack_assert(false); 6767bbeb3adSMilanka Ringwald break; 67777ba3d3fSMatthias Ringwald } 67877ba3d3fSMatthias Ringwald } 67977ba3d3fSMatthias Ringwald 68077ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER 68177ba3d3fSMatthias Ringwald uint16_t pb_adv_create_link(const uint8_t * device_uuid){ 68277ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_OPEN) return 0; 68377ba3d3fSMatthias Ringwald 68477ba3d3fSMatthias Ringwald pb_adv_peer_device_uuid = device_uuid; 68577ba3d3fSMatthias Ringwald pb_adv_provisioner_role = 1; 686d16ad46bSMatthias Ringwald pb_adv_provisioner_open_countdown = PB_ADV_LINK_OPEN_RETRIES; 68777ba3d3fSMatthias Ringwald 68877ba3d3fSMatthias Ringwald // create new 32-bit link id 68977ba3d3fSMatthias Ringwald pb_adv_link_id = pb_adv_random(); 69077ba3d3fSMatthias Ringwald 69177ba3d3fSMatthias Ringwald // after sending OPEN, we wait for an ACK 69277ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_ACK; 69377ba3d3fSMatthias Ringwald 69477ba3d3fSMatthias Ringwald // request outgoing 6954662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu(); 69677ba3d3fSMatthias Ringwald 69777ba3d3fSMatthias Ringwald // dummy pb_adv_cid 69877ba3d3fSMatthias Ringwald return pb_adv_cid; 69977ba3d3fSMatthias Ringwald } 70077ba3d3fSMatthias Ringwald #endif 70177ba3d3fSMatthias Ringwald 702