xref: /btstack/src/mesh/pb_adv.c (revision 1765fb5d3432641a4e75315c1b908ee26bd432de)
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
2377ba3d3fSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2477ba3d3fSMatthias Ringwald  * RINGWALD 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 
4277ba3d3fSMatthias Ringwald #include <stdint.h>
4377ba3d3fSMatthias Ringwald #include <stdio.h>
4477ba3d3fSMatthias Ringwald #include <stdlib.h>
4577ba3d3fSMatthias Ringwald #include <string.h>
46f4854a5eSMatthias Ringwald 
47f4854a5eSMatthias Ringwald #include "btstack_debug.h"
48f4854a5eSMatthias Ringwald #include "btstack_event.h"
49f4854a5eSMatthias Ringwald #include "btstack_util.h"
50f4854a5eSMatthias Ringwald 
5177ba3d3fSMatthias Ringwald #include "mesh/adv_bearer.h"
5277ba3d3fSMatthias Ringwald #include "mesh/beacon.h"
538936a143SMatthias Ringwald #include "mesh/mesh_node.h"
54f4854a5eSMatthias Ringwald #include "mesh/provisioning.h"
5577ba3d3fSMatthias Ringwald 
5677ba3d3fSMatthias Ringwald #define PB_ADV_LINK_OPEN_RETRANSMIT_MS 1000
57d16ad46bSMatthias Ringwald #define PB_ADV_LINK_OPEN_TIMEOUT_MS   60000
58d16ad46bSMatthias Ringwald #define PB_ADV_LINK_OPEN_RETRIES (PB_ADV_LINK_OPEN_TIMEOUT_MS / PB_ADV_LINK_OPEN_RETRANSMIT_MS)
5977ba3d3fSMatthias Ringwald static void pb_adv_run(void);
6077ba3d3fSMatthias Ringwald 
6177ba3d3fSMatthias Ringwald /* taps: 32 31 29 1; characteristic polynomial: x^32 + x^31 + x^29 + x + 1 */
6277ba3d3fSMatthias Ringwald #define LFSR(a) ((a >> 1) ^ (uint32_t)((0 - (a & 1u)) & 0xd0000001u))
6377ba3d3fSMatthias Ringwald 
6477ba3d3fSMatthias Ringwald // PB-ADV - Provisioning Bearer using Advertisement Bearer
6577ba3d3fSMatthias Ringwald 
6677ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_OPEN              0x00
6777ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_ACK               0x01
6877ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_LINK_CLOSE             0x02
6977ba3d3fSMatthias Ringwald 
7077ba3d3fSMatthias Ringwald #define MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS 30000
7177ba3d3fSMatthias Ringwald 
7277ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_PDU_SIZE  100
7377ba3d3fSMatthias Ringwald #define MESH_PB_ADV_MAX_SEGMENTS    8
7477ba3d3fSMatthias Ringwald #define MESH_PB_ADV_START_PAYLOAD  20
7577ba3d3fSMatthias Ringwald #define MESH_PB_ADV_CONT_PAYLOAD   23
7677ba3d3fSMatthias Ringwald 
7777ba3d3fSMatthias Ringwald typedef enum mesh_gpcf_format {
7877ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_START = 0,
7977ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_ACK,
8077ba3d3fSMatthias Ringwald     MESH_GPCF_TRANSACTION_CONT,
8177ba3d3fSMatthias Ringwald     MESH_GPCF_PROV_BEARER_CONTROL,
8277ba3d3fSMatthias Ringwald } mesh_gpcf_format_t;
8377ba3d3fSMatthias Ringwald 
8477ba3d3fSMatthias Ringwald typedef enum {
8577ba3d3fSMatthias Ringwald     LINK_STATE_W4_OPEN,
8677ba3d3fSMatthias Ringwald     LINK_STATE_W2_SEND_ACK,
8777ba3d3fSMatthias Ringwald     LINK_STATE_W4_ACK,
8877ba3d3fSMatthias Ringwald     LINK_STATE_OPEN,
8977ba3d3fSMatthias Ringwald     LINK_STATE_CLOSING,
9077ba3d3fSMatthias Ringwald } link_state_t;
9177ba3d3fSMatthias Ringwald static link_state_t link_state;
9277ba3d3fSMatthias Ringwald 
9377ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
9477ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_peer_device_uuid;
95d16ad46bSMatthias Ringwald static uint8_t pb_adv_provisioner_open_countdown;
9677ba3d3fSMatthias Ringwald #endif
9777ba3d3fSMatthias Ringwald 
9877ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_buffer[MESH_PB_ADV_MAX_PDU_SIZE];   // TODO: how large are prov messages?
9977ba3d3fSMatthias Ringwald 
10077ba3d3fSMatthias Ringwald // single adv link
10177ba3d3fSMatthias Ringwald static uint16_t pb_adv_cid = 1;
10277ba3d3fSMatthias Ringwald static uint8_t  pb_adv_provisioner_role;
10377ba3d3fSMatthias Ringwald 
10477ba3d3fSMatthias Ringwald // link state
10577ba3d3fSMatthias Ringwald static uint32_t pb_adv_link_id;
10677ba3d3fSMatthias Ringwald static uint8_t  pb_adv_link_close_reason;
10777ba3d3fSMatthias Ringwald static uint8_t  pb_adv_link_close_countdown;
108*1765fb5dSMatthias Ringwald static bool     pb_adv_link_establish_timer_active;
10977ba3d3fSMatthias Ringwald 
11077ba3d3fSMatthias Ringwald // random delay for outgoing packets
11177ba3d3fSMatthias Ringwald static uint32_t pb_adv_lfsr;
11277ba3d3fSMatthias Ringwald static uint8_t  pb_adv_random_delay_active;
113*1765fb5dSMatthias Ringwald 
114*1765fb5dSMatthias Ringwald // adv link timer used for
115*1765fb5dSMatthias Ringwald // establishment:
116*1765fb5dSMatthias Ringwald // - device: 60s timeout after receiving link open and sending link ack until first provisioning PDU
117*1765fb5dSMatthias Ringwald // - provisioner: 1s timer to send link open messages
118*1765fb5dSMatthias Ringwald // open: random delay
119*1765fb5dSMatthias Ringwald static btstack_timer_source_t pb_adv_link_timer;
12077ba3d3fSMatthias Ringwald 
12177ba3d3fSMatthias Ringwald // incoming message
12277ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_transaction_nr_prev;
12377ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_in_len;   //
12477ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_fcs;
12577ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_last_segment;
12677ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_segments_missing; // bitfield for segmentes 1-n
12777ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_transaction_nr;
12877ba3d3fSMatthias Ringwald static uint8_t  pb_adv_msg_in_send_ack;
12977ba3d3fSMatthias Ringwald 
1304a72aacaSMatthias Ringwald // outgoing message
13177ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_active;
13277ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_transaction_nr;
13377ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_completed_transaction_nr;
13477ba3d3fSMatthias Ringwald static uint16_t        pb_adv_msg_out_len;
13577ba3d3fSMatthias Ringwald static uint16_t        pb_adv_msg_out_pos;
13677ba3d3fSMatthias Ringwald static uint8_t         pb_adv_msg_out_seg;
13777ba3d3fSMatthias Ringwald static uint32_t        pb_adv_msg_out_start;
13877ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_msg_out_buffer;
13977ba3d3fSMatthias Ringwald 
14077ba3d3fSMatthias Ringwald static btstack_packet_handler_t pb_adv_packet_handler;
14177ba3d3fSMatthias Ringwald 
14277ba3d3fSMatthias Ringwald // poor man's random number generator
14377ba3d3fSMatthias Ringwald static uint32_t pb_adv_random(void){
14477ba3d3fSMatthias Ringwald     pb_adv_lfsr = LFSR(pb_adv_lfsr);
14577ba3d3fSMatthias Ringwald     return pb_adv_lfsr;
14677ba3d3fSMatthias Ringwald }
14777ba3d3fSMatthias Ringwald 
14877ba3d3fSMatthias Ringwald static void pb_adv_emit_pdu_sent(uint8_t status){
14977ba3d3fSMatthias Ringwald     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
15077ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
15177ba3d3fSMatthias Ringwald }
15277ba3d3fSMatthias Ringwald 
153f8962c62SMatthias Ringwald static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_transport_cid){
15477ba3d3fSMatthias Ringwald     uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status};
155f8962c62SMatthias Ringwald     little_endian_store_16(event, 4, pb_transport_cid);
15630a044b0SMilanka Ringwald     event[6] = MESH_PB_TYPE_ADV;
15777ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
15877ba3d3fSMatthias Ringwald }
15977ba3d3fSMatthias Ringwald 
160f8962c62SMatthias Ringwald static void pb_adv_emit_link_close(uint16_t pb_transport_cid, uint8_t reason){
161f8962c62SMatthias Ringwald     uint8_t event[6] = { HCI_EVENT_MESH_META, 3, MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED};
162f8962c62SMatthias Ringwald     little_endian_store_16(event, 3, pb_transport_cid);
163f8962c62SMatthias Ringwald     event[5] = reason;
16477ba3d3fSMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
16577ba3d3fSMatthias Ringwald }
16677ba3d3fSMatthias Ringwald 
1674a72aacaSMatthias Ringwald static void pb_adv_device_link_timeout(btstack_timer_source_t * ts){
1684a72aacaSMatthias Ringwald     UNUSED(ts);
1694a72aacaSMatthias Ringwald     // timeout occured
1704a72aacaSMatthias Ringwald     link_state = LINK_STATE_W4_OPEN;
1714a72aacaSMatthias Ringwald     log_info("link timeout, %08x", pb_adv_link_id);
1724a72aacaSMatthias Ringwald     printf("PB-ADV: Link timeout %08x\n", pb_adv_link_id);
1734a72aacaSMatthias Ringwald     pb_adv_emit_link_close(pb_adv_cid, ERROR_CODE_PAGE_TIMEOUT);
1744a72aacaSMatthias Ringwald }
1754a72aacaSMatthias Ringwald 
17677ba3d3fSMatthias Ringwald static void pb_adv_handle_bearer_control(uint32_t link_id, uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
177f843ee5dSMatthias Ringwald     UNUSED(transaction_nr);
178f843ee5dSMatthias Ringwald     UNUSED(size);
179f843ee5dSMatthias Ringwald 
18077ba3d3fSMatthias Ringwald     uint8_t bearer_opcode = pdu[0] >> 2;
18177ba3d3fSMatthias Ringwald     uint8_t reason;
1828936a143SMatthias Ringwald     const uint8_t * own_device_uuid;
18377ba3d3fSMatthias Ringwald     switch (bearer_opcode){
18477ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_OPEN: // Open a session on a bearer with a device
18577ba3d3fSMatthias Ringwald             // does it match our device_uuid?
1868936a143SMatthias Ringwald             own_device_uuid = mesh_node_get_device_uuid();
1878936a143SMatthias Ringwald             if (!own_device_uuid) break;
1888936a143SMatthias Ringwald             if (memcmp(&pdu[1], own_device_uuid, 16) != 0) break;
189*1765fb5dSMatthias Ringwald             btstack_run_loop_remove_timer(&pb_adv_link_timer);
190*1765fb5dSMatthias Ringwald             btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_TIMEOUT_MS);
191*1765fb5dSMatthias Ringwald             btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_device_link_timeout);
192*1765fb5dSMatthias Ringwald             btstack_run_loop_add_timer(&pb_adv_link_timer);
193*1765fb5dSMatthias Ringwald             pb_adv_link_establish_timer_active = true;
19477ba3d3fSMatthias Ringwald             switch(link_state){
19577ba3d3fSMatthias Ringwald                 case LINK_STATE_W4_OPEN:
19677ba3d3fSMatthias Ringwald                     pb_adv_link_id = link_id;
19777ba3d3fSMatthias Ringwald                     pb_adv_provisioner_role = 0;
19877ba3d3fSMatthias Ringwald                     pb_adv_msg_in_transaction_nr = 0xff;  // first transaction nr will be 0x00
19977ba3d3fSMatthias Ringwald                     pb_adv_msg_in_transaction_nr_prev = 0xff;
20077ba3d3fSMatthias Ringwald                     log_info("link open, id %08x", pb_adv_link_id);
20177ba3d3fSMatthias Ringwald                     printf("PB-ADV: Link Open %08x\n", pb_adv_link_id);
20277ba3d3fSMatthias Ringwald                     link_state = LINK_STATE_W2_SEND_ACK;
2034662af4aSMatthias Ringwald                     adv_bearer_request_can_send_now_for_provisioning_pdu();
204d16ad46bSMatthias Ringwald                     pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid);
20577ba3d3fSMatthias Ringwald                     break;
20677ba3d3fSMatthias Ringwald                 case LINK_STATE_OPEN:
20777ba3d3fSMatthias Ringwald                     if (pb_adv_link_id != link_id) break;
20877ba3d3fSMatthias Ringwald                     log_info("link open, resend ACK");
20977ba3d3fSMatthias Ringwald                     link_state = LINK_STATE_W2_SEND_ACK;
2104662af4aSMatthias Ringwald                     adv_bearer_request_can_send_now_for_provisioning_pdu();
21177ba3d3fSMatthias Ringwald                     break;
21277ba3d3fSMatthias Ringwald                 default:
21377ba3d3fSMatthias Ringwald                     break;
21477ba3d3fSMatthias Ringwald             }
21577ba3d3fSMatthias Ringwald             break;
21677ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
21777ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_ACK:   // Acknowledge a session on a bearer
21877ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_W4_ACK) break;
21977ba3d3fSMatthias Ringwald             link_state = LINK_STATE_OPEN;
22077ba3d3fSMatthias Ringwald             pb_adv_msg_out_transaction_nr = 0;
22177ba3d3fSMatthias Ringwald             pb_adv_msg_in_transaction_nr = 0x7f;    // first transaction nr will be 0x80
22277ba3d3fSMatthias Ringwald             pb_adv_msg_in_transaction_nr_prev = 0x7f;
223*1765fb5dSMatthias Ringwald             btstack_run_loop_remove_timer(&pb_adv_link_timer);
22477ba3d3fSMatthias Ringwald             log_info("link open, id %08x", pb_adv_link_id);
22577ba3d3fSMatthias Ringwald             printf("PB-ADV: Link Open %08x\n", pb_adv_link_id);
226d16ad46bSMatthias Ringwald             pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid);
22777ba3d3fSMatthias Ringwald             break;
22877ba3d3fSMatthias Ringwald #endif
22977ba3d3fSMatthias Ringwald         case MESH_GENERIC_PROVISIONING_LINK_CLOSE: // Close a session on a bearer
23077ba3d3fSMatthias Ringwald             // does it match link id
23177ba3d3fSMatthias Ringwald             if (link_id != pb_adv_link_id) break;
2322e9a36a1SMatthias Ringwald             if (link_state == LINK_STATE_W4_OPEN) break;
233*1765fb5dSMatthias Ringwald             btstack_run_loop_remove_timer(&pb_adv_link_timer);
23477ba3d3fSMatthias Ringwald             reason = pdu[1];
23577ba3d3fSMatthias Ringwald             link_state = LINK_STATE_W4_OPEN;
23677ba3d3fSMatthias Ringwald             log_info("link close, reason %x", reason);
23777ba3d3fSMatthias Ringwald             pb_adv_emit_link_close(pb_adv_cid, reason);
23877ba3d3fSMatthias Ringwald             break;
23977ba3d3fSMatthias Ringwald         default:
24077ba3d3fSMatthias Ringwald             log_info("BearerOpcode %x reserved for future use\n", bearer_opcode);
24177ba3d3fSMatthias Ringwald             break;
24277ba3d3fSMatthias Ringwald     }
24377ba3d3fSMatthias Ringwald }
24477ba3d3fSMatthias Ringwald 
24577ba3d3fSMatthias Ringwald static void pb_adv_pdu_complete(void){
24677ba3d3fSMatthias Ringwald 
24777ba3d3fSMatthias Ringwald     // Verify FCS
24877ba3d3fSMatthias Ringwald     uint8_t pdu_crc = btstack_crc8_calc((uint8_t*)pb_adv_msg_in_buffer, pb_adv_msg_in_len);
24977ba3d3fSMatthias Ringwald     if (pdu_crc != pb_adv_msg_in_fcs){
25077ba3d3fSMatthias 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));
25177ba3d3fSMatthias Ringwald         return;
25277ba3d3fSMatthias Ringwald     }
25377ba3d3fSMatthias Ringwald 
25477ba3d3fSMatthias Ringwald     printf("PB-ADV: %02x complete\n", pb_adv_msg_in_transaction_nr);
25577ba3d3fSMatthias Ringwald 
25677ba3d3fSMatthias Ringwald     // transaction complete
25777ba3d3fSMatthias Ringwald     pb_adv_msg_in_transaction_nr_prev = pb_adv_msg_in_transaction_nr;
25877ba3d3fSMatthias Ringwald     if (pb_adv_provisioner_role){
25977ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = 0x7f;    // invalid
26077ba3d3fSMatthias Ringwald     } else {
26177ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = 0xff;    // invalid
26277ba3d3fSMatthias Ringwald     }
26377ba3d3fSMatthias Ringwald 
26477ba3d3fSMatthias Ringwald     // Ack Transaction
26577ba3d3fSMatthias Ringwald     pb_adv_msg_in_send_ack = 1;
26677ba3d3fSMatthias Ringwald     pb_adv_run();
26777ba3d3fSMatthias Ringwald 
26877ba3d3fSMatthias Ringwald     // Forward to Provisioning
26977ba3d3fSMatthias Ringwald     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, pb_adv_msg_in_buffer, pb_adv_msg_in_len);
27077ba3d3fSMatthias Ringwald }
27177ba3d3fSMatthias Ringwald 
27277ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_start(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
27377ba3d3fSMatthias Ringwald 
27477ba3d3fSMatthias Ringwald     // resend ack if packet from previous transaction received
27577ba3d3fSMatthias Ringwald     if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
27677ba3d3fSMatthias Ringwald         printf("PB_ADV: %02x transaction complete, resending ack \n", transaction_nr);
27777ba3d3fSMatthias Ringwald         pb_adv_msg_in_send_ack = 1;
27877ba3d3fSMatthias Ringwald         return;
27977ba3d3fSMatthias Ringwald     }
28077ba3d3fSMatthias Ringwald 
28177ba3d3fSMatthias Ringwald     // new transaction?
28277ba3d3fSMatthias Ringwald     if (transaction_nr != pb_adv_msg_in_transaction_nr){
28377ba3d3fSMatthias Ringwald 
28477ba3d3fSMatthias Ringwald         // check len
28577ba3d3fSMatthias Ringwald         uint16_t msg_len = big_endian_read_16(pdu, 1);
28677ba3d3fSMatthias Ringwald         if (msg_len > MESH_PB_ADV_MAX_PDU_SIZE){
28777ba3d3fSMatthias Ringwald             // abort transaction
28877ba3d3fSMatthias Ringwald             return;
28977ba3d3fSMatthias Ringwald         }
29077ba3d3fSMatthias Ringwald 
29177ba3d3fSMatthias Ringwald         // check num segments
29277ba3d3fSMatthias Ringwald         uint8_t last_segment = pdu[0] >> 2;
29377ba3d3fSMatthias Ringwald         if (last_segment >= MESH_PB_ADV_MAX_SEGMENTS){
29477ba3d3fSMatthias Ringwald             // abort transaction
29577ba3d3fSMatthias Ringwald             return;
29677ba3d3fSMatthias Ringwald         }
29777ba3d3fSMatthias Ringwald 
29877ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x started\n", transaction_nr);
29977ba3d3fSMatthias Ringwald 
30077ba3d3fSMatthias Ringwald         pb_adv_msg_in_transaction_nr = transaction_nr;
30177ba3d3fSMatthias Ringwald         pb_adv_msg_in_len            = msg_len;
30277ba3d3fSMatthias Ringwald         pb_adv_msg_in_fcs            = pdu[3];
30377ba3d3fSMatthias Ringwald         pb_adv_msg_in_last_segment   = last_segment;
30477ba3d3fSMatthias Ringwald 
30577ba3d3fSMatthias Ringwald         // set bits for  segments 1..n (segment 0 already received in this message)
30677ba3d3fSMatthias Ringwald         pb_adv_msg_in_segments_missing = (1 << last_segment) - 1;
30777ba3d3fSMatthias Ringwald 
30877ba3d3fSMatthias Ringwald         // store payload
30977ba3d3fSMatthias Ringwald         uint16_t payload_len = size - 4;
3106535961aSMatthias Ringwald         (void)memcpy(pb_adv_msg_in_buffer, &pdu[4], payload_len);
31177ba3d3fSMatthias Ringwald 
31277ba3d3fSMatthias Ringwald         // complete?
31377ba3d3fSMatthias Ringwald         if (pb_adv_msg_in_segments_missing == 0){
31477ba3d3fSMatthias Ringwald             pb_adv_pdu_complete();
31577ba3d3fSMatthias Ringwald         }
31677ba3d3fSMatthias Ringwald     }
31777ba3d3fSMatthias Ringwald }
31877ba3d3fSMatthias Ringwald 
31977ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_cont(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
32077ba3d3fSMatthias Ringwald 
32177ba3d3fSMatthias Ringwald     // check transaction nr
32277ba3d3fSMatthias Ringwald     if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
32377ba3d3fSMatthias Ringwald         printf("PB_ADV: %02x transaction complete, resending resending ack\n", transaction_nr);
32477ba3d3fSMatthias Ringwald         pb_adv_msg_in_send_ack = 1;
32577ba3d3fSMatthias Ringwald         return;
32677ba3d3fSMatthias Ringwald     }
32777ba3d3fSMatthias Ringwald 
32877ba3d3fSMatthias Ringwald     if (transaction_nr != pb_adv_msg_in_transaction_nr){
32977ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x received msg for transaction nr %x\n", pb_adv_msg_in_transaction_nr, transaction_nr);
33077ba3d3fSMatthias Ringwald         return;
33177ba3d3fSMatthias Ringwald     }
33277ba3d3fSMatthias Ringwald 
33377ba3d3fSMatthias Ringwald     // validate seg nr
33477ba3d3fSMatthias Ringwald     uint8_t seg = pdu[0] >> 2;
33577ba3d3fSMatthias Ringwald     if (seg >= MESH_PB_ADV_MAX_SEGMENTS || seg == 0){
33677ba3d3fSMatthias Ringwald         return;
33777ba3d3fSMatthias Ringwald     }
33877ba3d3fSMatthias Ringwald 
33977ba3d3fSMatthias Ringwald     // check if segment already received
34077ba3d3fSMatthias Ringwald     uint8_t seg_mask = 1 << (seg-1);
34177ba3d3fSMatthias Ringwald     if ((pb_adv_msg_in_segments_missing & seg_mask) == 0){
34277ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x, segment %u already received\n", transaction_nr, seg);
34377ba3d3fSMatthias Ringwald         return;
34477ba3d3fSMatthias Ringwald     }
34577ba3d3fSMatthias Ringwald     printf("PB-ADV: %02x, segment %u stored\n", transaction_nr, seg);
34677ba3d3fSMatthias Ringwald 
34777ba3d3fSMatthias Ringwald     // calculate offset and fragment size
34877ba3d3fSMatthias Ringwald     uint16_t msg_pos = MESH_PB_ADV_START_PAYLOAD + (seg-1) * MESH_PB_ADV_CONT_PAYLOAD;
34977ba3d3fSMatthias Ringwald     uint16_t fragment_size = size - 1;
35077ba3d3fSMatthias Ringwald 
35177ba3d3fSMatthias Ringwald     // check size if last segment
35277ba3d3fSMatthias Ringwald     if (seg == pb_adv_msg_in_last_segment && (msg_pos + fragment_size) != pb_adv_msg_in_len){
35377ba3d3fSMatthias Ringwald         // last segment has invalid size
35477ba3d3fSMatthias Ringwald         return;
35577ba3d3fSMatthias Ringwald     }
35677ba3d3fSMatthias Ringwald 
35777ba3d3fSMatthias Ringwald     // store segment and mark as received
3586535961aSMatthias Ringwald     (void)memcpy(&pb_adv_msg_in_buffer[msg_pos], &pdu[1], fragment_size);
35977ba3d3fSMatthias Ringwald     pb_adv_msg_in_segments_missing &= ~seg_mask;
36077ba3d3fSMatthias Ringwald 
36177ba3d3fSMatthias Ringwald      // last segment
36277ba3d3fSMatthias Ringwald      if (pb_adv_msg_in_segments_missing == 0){
36377ba3d3fSMatthias Ringwald         pb_adv_pdu_complete();
36477ba3d3fSMatthias Ringwald     }
36577ba3d3fSMatthias Ringwald }
36677ba3d3fSMatthias Ringwald 
3674a72aacaSMatthias Ringwald static void pb_adv_outgoing_transaction_complete(uint8_t status){
36877ba3d3fSMatthias Ringwald     // stop sending
36977ba3d3fSMatthias Ringwald     pb_adv_msg_out_active = 0;
37077ba3d3fSMatthias Ringwald     // emit done
37177ba3d3fSMatthias Ringwald     pb_adv_emit_pdu_sent(status);
37277ba3d3fSMatthias Ringwald     // keep track of ack'ed transactions
37377ba3d3fSMatthias Ringwald     pb_adv_msg_out_completed_transaction_nr = pb_adv_msg_out_transaction_nr;
37477ba3d3fSMatthias Ringwald     // increment outgoing transaction nr
37577ba3d3fSMatthias Ringwald     pb_adv_msg_out_transaction_nr++;
37677ba3d3fSMatthias Ringwald     if (pb_adv_msg_out_transaction_nr == 0x00){
37777ba3d3fSMatthias Ringwald         // Device role
37877ba3d3fSMatthias Ringwald         pb_adv_msg_out_transaction_nr = 0x80;
37977ba3d3fSMatthias Ringwald     }
38077ba3d3fSMatthias Ringwald     if (pb_adv_msg_out_transaction_nr == 0x80){
38177ba3d3fSMatthias Ringwald         // Provisioner role
38277ba3d3fSMatthias Ringwald         pb_adv_msg_out_transaction_nr = 0x00;
38377ba3d3fSMatthias Ringwald     }
38477ba3d3fSMatthias Ringwald }
38577ba3d3fSMatthias Ringwald 
38677ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_ack(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
387f843ee5dSMatthias Ringwald     UNUSED(pdu);
388f843ee5dSMatthias Ringwald     UNUSED(size);
38977ba3d3fSMatthias Ringwald     if (transaction_nr == pb_adv_msg_out_transaction_nr){
39077ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x ACK received\n", transaction_nr);
3914a72aacaSMatthias Ringwald         pb_adv_outgoing_transaction_complete(ERROR_CODE_SUCCESS);
39277ba3d3fSMatthias Ringwald     } else if (transaction_nr == pb_adv_msg_out_completed_transaction_nr){
39377ba3d3fSMatthias Ringwald         // Transaction ack received again
39477ba3d3fSMatthias Ringwald     } else {
39577ba3d3fSMatthias Ringwald         printf("PB-ADV: %02x unexpected Transaction ACK %x recevied\n", pb_adv_msg_out_transaction_nr, transaction_nr);
39677ba3d3fSMatthias Ringwald     }
39777ba3d3fSMatthias Ringwald }
39877ba3d3fSMatthias Ringwald 
39977ba3d3fSMatthias Ringwald static int pb_adv_packet_to_send(void){
40077ba3d3fSMatthias Ringwald     return pb_adv_msg_in_send_ack || pb_adv_msg_out_active || (link_state == LINK_STATE_W4_ACK);
40177ba3d3fSMatthias Ringwald }
40277ba3d3fSMatthias Ringwald 
40377ba3d3fSMatthias Ringwald static void pb_adv_timer_handler(btstack_timer_source_t * ts){
4042983fbcbSMatthias Ringwald     UNUSED(ts);
40577ba3d3fSMatthias Ringwald     pb_adv_random_delay_active = 0;
40677ba3d3fSMatthias Ringwald     if (!pb_adv_packet_to_send()) return;
4074662af4aSMatthias Ringwald     adv_bearer_request_can_send_now_for_provisioning_pdu();
40877ba3d3fSMatthias Ringwald }
40977ba3d3fSMatthias Ringwald 
41077ba3d3fSMatthias Ringwald static void pb_adv_run(void){
41177ba3d3fSMatthias Ringwald     if (!pb_adv_packet_to_send()) return;
41277ba3d3fSMatthias Ringwald     if (pb_adv_random_delay_active) return;
41377ba3d3fSMatthias Ringwald 
41477ba3d3fSMatthias Ringwald     // spec recommends 20-50 ms, we use 20-51 ms
41577ba3d3fSMatthias Ringwald     pb_adv_random_delay_active = 1;
41677ba3d3fSMatthias Ringwald     uint16_t random_delay_ms = 20 + (pb_adv_random() & 0x1f);
41777ba3d3fSMatthias Ringwald     log_info("random delay %u ms", random_delay_ms);
418*1765fb5dSMatthias Ringwald     btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler);
419*1765fb5dSMatthias Ringwald     btstack_run_loop_set_timer(&pb_adv_link_timer, random_delay_ms);
420*1765fb5dSMatthias Ringwald     btstack_run_loop_add_timer(&pb_adv_link_timer);
42177ba3d3fSMatthias Ringwald }
42277ba3d3fSMatthias Ringwald 
42377ba3d3fSMatthias Ringwald static void pb_adv_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
4242983fbcbSMatthias Ringwald     UNUSED(channel);
4252983fbcbSMatthias Ringwald 
42677ba3d3fSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
42777ba3d3fSMatthias Ringwald     const uint8_t * data;
42877ba3d3fSMatthias Ringwald     uint8_t  length;
42977ba3d3fSMatthias Ringwald     uint32_t link_id;
43077ba3d3fSMatthias Ringwald     uint8_t  transaction_nr;
43177ba3d3fSMatthias Ringwald     uint8_t  generic_provisioning_control;
43277ba3d3fSMatthias Ringwald     switch(packet[0]){
43377ba3d3fSMatthias Ringwald         case GAP_EVENT_ADVERTISING_REPORT:
434f843ee5dSMatthias Ringwald             // data starts at offset 12
435f843ee5dSMatthias Ringwald             data = &packet[12];
43677ba3d3fSMatthias Ringwald             // PDB ADV PDU
43777ba3d3fSMatthias Ringwald             length = data[0];
438f843ee5dSMatthias Ringwald 
439f843ee5dSMatthias Ringwald             // validate length field
440f843ee5dSMatthias Ringwald             if ((12 + length) > size) return;
441f843ee5dSMatthias Ringwald 
44277ba3d3fSMatthias Ringwald             link_id = big_endian_read_32(data, 2);
44377ba3d3fSMatthias Ringwald             transaction_nr = data[6];
44477ba3d3fSMatthias Ringwald             // generic provision PDU
44577ba3d3fSMatthias Ringwald             generic_provisioning_control = data[7];
44677ba3d3fSMatthias Ringwald             mesh_gpcf_format_t generic_provisioning_control_format = (mesh_gpcf_format_t) generic_provisioning_control & 3;
44777ba3d3fSMatthias Ringwald 
44877ba3d3fSMatthias Ringwald             // unless, we're waiting for LINK_OPEN, check link_id
44977ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_W4_OPEN){
45077ba3d3fSMatthias Ringwald                 if (link_id != pb_adv_link_id) break;
45177ba3d3fSMatthias Ringwald             }
45277ba3d3fSMatthias Ringwald 
45377ba3d3fSMatthias Ringwald             if (generic_provisioning_control_format == MESH_GPCF_PROV_BEARER_CONTROL){
45477ba3d3fSMatthias Ringwald                 pb_adv_handle_bearer_control(link_id, transaction_nr, &data[7], length-6);
45577ba3d3fSMatthias Ringwald                 break;
45677ba3d3fSMatthias Ringwald             }
45777ba3d3fSMatthias Ringwald 
45877ba3d3fSMatthias Ringwald             // verify link id and link state
45977ba3d3fSMatthias Ringwald             if (link_state != LINK_STATE_OPEN) break;
46077ba3d3fSMatthias Ringwald 
4614a72aacaSMatthias Ringwald             // stop link establishment timer
462*1765fb5dSMatthias Ringwald             if (pb_adv_link_establish_timer_active) {
463*1765fb5dSMatthias Ringwald                 pb_adv_link_establish_timer_active = false;
464*1765fb5dSMatthias Ringwald                 btstack_run_loop_remove_timer(&pb_adv_link_timer);
465*1765fb5dSMatthias Ringwald             }
4664a72aacaSMatthias Ringwald 
46777ba3d3fSMatthias Ringwald             switch (generic_provisioning_control_format){
46877ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_START:
46977ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_start(transaction_nr, &data[7], length-6);
47077ba3d3fSMatthias Ringwald                     break;
47177ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_CONT:
47277ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_cont(transaction_nr, &data[7], length-6);
47377ba3d3fSMatthias Ringwald                     break;
47477ba3d3fSMatthias Ringwald                 case MESH_GPCF_TRANSACTION_ACK:
47577ba3d3fSMatthias Ringwald                     pb_adv_handle_transaction_ack(transaction_nr, &data[7], length-6);
47677ba3d3fSMatthias Ringwald                     break;
47777ba3d3fSMatthias Ringwald                 default:
47877ba3d3fSMatthias Ringwald                     break;
47977ba3d3fSMatthias Ringwald             }
48077ba3d3fSMatthias Ringwald             pb_adv_run();
48177ba3d3fSMatthias Ringwald             break;
48277ba3d3fSMatthias Ringwald         case HCI_EVENT_MESH_META:
48377ba3d3fSMatthias Ringwald             switch(packet[2]){
48477ba3d3fSMatthias Ringwald                 case MESH_SUBEVENT_CAN_SEND_NOW:
485480ff3cbSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
48677ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_W4_ACK){
487d16ad46bSMatthias Ringwald                         pb_adv_provisioner_open_countdown--;
488d16ad46bSMatthias Ringwald                         if (pb_adv_provisioner_open_countdown == 0){
489d16ad46bSMatthias Ringwald                             pb_adv_emit_link_open(ERROR_CODE_PAGE_TIMEOUT, pb_adv_cid);
490d16ad46bSMatthias Ringwald                             break;
491d16ad46bSMatthias Ringwald                         }
49277ba3d3fSMatthias Ringwald                         // build packet
49377ba3d3fSMatthias Ringwald                         uint8_t buffer[22];
49477ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
49577ba3d3fSMatthias Ringwald                         buffer[4] = 0;            // Transaction ID = 0
49677ba3d3fSMatthias Ringwald                         buffer[5] = (0 << 2) | 3; // Link Open | Provisioning Bearer Control
4976535961aSMatthias Ringwald                         (void)memcpy(&buffer[6], pb_adv_peer_device_uuid, 16);
4984662af4aSMatthias Ringwald                         adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
49977ba3d3fSMatthias Ringwald                         log_info("link open %08x", pb_adv_link_id);
50077ba3d3fSMatthias Ringwald                         printf("PB-ADV: Sending Link Open for device uuid: ");
50177ba3d3fSMatthias Ringwald                         printf_hexdump(pb_adv_peer_device_uuid, 16);
502*1765fb5dSMatthias Ringwald                         btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler);
503*1765fb5dSMatthias Ringwald                         btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_RETRANSMIT_MS);
504*1765fb5dSMatthias Ringwald                         btstack_run_loop_add_timer(&pb_adv_link_timer);
50577ba3d3fSMatthias Ringwald                         break;
50677ba3d3fSMatthias Ringwald                     }
507480ff3cbSMatthias Ringwald #endif
50877ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_CLOSING){
50977ba3d3fSMatthias Ringwald                         log_info("link close %08x", pb_adv_link_id);
5104a72aacaSMatthias Ringwald                         printf("PB-ADV: Sending Link Close %08x\n", pb_adv_link_id);
51177ba3d3fSMatthias Ringwald                         // build packet
51277ba3d3fSMatthias Ringwald                         uint8_t buffer[7];
51377ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
51477ba3d3fSMatthias Ringwald                         buffer[4] = 0;            // Transaction ID = 0
51577ba3d3fSMatthias Ringwald                         buffer[5] = (2 << 2) | 3; // Link Close | Provisioning Bearer Control
51677ba3d3fSMatthias Ringwald                         buffer[6] = pb_adv_link_close_reason;
5174662af4aSMatthias Ringwald                         adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
51877ba3d3fSMatthias Ringwald                         pb_adv_link_close_countdown--;
51977ba3d3fSMatthias Ringwald                         if (pb_adv_link_close_countdown) {
5204662af4aSMatthias Ringwald                             adv_bearer_request_can_send_now_for_provisioning_pdu();
52177ba3d3fSMatthias Ringwald                         } else {
52277ba3d3fSMatthias Ringwald                             link_state = LINK_STATE_W4_OPEN;
52377ba3d3fSMatthias Ringwald                         }
52477ba3d3fSMatthias Ringwald                         break;
52577ba3d3fSMatthias Ringwald                     }
52677ba3d3fSMatthias Ringwald                     if (link_state == LINK_STATE_W2_SEND_ACK){
52777ba3d3fSMatthias Ringwald                         link_state = LINK_STATE_OPEN;
52877ba3d3fSMatthias Ringwald                         pb_adv_msg_out_transaction_nr = 0x80;
52977ba3d3fSMatthias Ringwald                         // build packet
53077ba3d3fSMatthias Ringwald                         uint8_t buffer[6];
53177ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
53277ba3d3fSMatthias Ringwald                         buffer[4] = 0;
53377ba3d3fSMatthias Ringwald                         buffer[5] = (1 << 2) | 3; // Link Ack | Provisioning Bearer Control
5344662af4aSMatthias Ringwald                         adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
53577ba3d3fSMatthias Ringwald                         log_info("link ack %08x", pb_adv_link_id);
5364a72aacaSMatthias Ringwald                         printf("PB-ADV: Sending Link Open Ack %08x\n", pb_adv_link_id);
53777ba3d3fSMatthias Ringwald                         break;
53877ba3d3fSMatthias Ringwald                     }
53977ba3d3fSMatthias Ringwald                     if (pb_adv_msg_in_send_ack){
54077ba3d3fSMatthias Ringwald                         pb_adv_msg_in_send_ack = 0;
54177ba3d3fSMatthias Ringwald                         uint8_t buffer[6];
54277ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
54377ba3d3fSMatthias Ringwald                         buffer[4] = pb_adv_msg_in_transaction_nr_prev;
54477ba3d3fSMatthias Ringwald                         buffer[5] = MESH_GPCF_TRANSACTION_ACK;
5454662af4aSMatthias Ringwald                         adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
54677ba3d3fSMatthias Ringwald                         log_info("transaction ack %08x", pb_adv_link_id);
54777ba3d3fSMatthias Ringwald                         printf("PB-ADV: %02x sending ACK\n", pb_adv_msg_in_transaction_nr_prev);
54877ba3d3fSMatthias Ringwald                         pb_adv_run();
54977ba3d3fSMatthias Ringwald                         break;
55077ba3d3fSMatthias Ringwald                     }
55177ba3d3fSMatthias Ringwald                     if (pb_adv_msg_out_active){
55277ba3d3fSMatthias Ringwald 
55377ba3d3fSMatthias Ringwald                         // check timeout for outgoing message
55477ba3d3fSMatthias Ringwald                         // since uint32_t is used and time now must be greater than pb_adv_msg_out_start,
55577ba3d3fSMatthias Ringwald                         // this claculation is correct even when the run loop time overruns
55677ba3d3fSMatthias Ringwald                         uint32_t transaction_time_ms = btstack_run_loop_get_time_ms() - pb_adv_msg_out_start;
55777ba3d3fSMatthias Ringwald                         if (transaction_time_ms >= MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS){
5584a72aacaSMatthias Ringwald                             pb_adv_outgoing_transaction_complete(ERROR_CODE_CONNECTION_TIMEOUT);
55977ba3d3fSMatthias Ringwald                             return;
56077ba3d3fSMatthias Ringwald                         }
56177ba3d3fSMatthias Ringwald 
56277ba3d3fSMatthias Ringwald                         uint8_t buffer[29]; // ADV MTU
56377ba3d3fSMatthias Ringwald                         big_endian_store_32(buffer, 0, pb_adv_link_id);
56477ba3d3fSMatthias Ringwald                         buffer[4] = pb_adv_msg_out_transaction_nr;
56577ba3d3fSMatthias Ringwald                         uint16_t bytes_left;
56677ba3d3fSMatthias Ringwald                         uint16_t pos;
56777ba3d3fSMatthias Ringwald                         if (pb_adv_msg_out_pos == 0){
56877ba3d3fSMatthias Ringwald                             // Transaction start
56977ba3d3fSMatthias Ringwald                             int seg_n = pb_adv_msg_out_len / 24;
57077ba3d3fSMatthias Ringwald                             pb_adv_msg_out_seg = 0;
57177ba3d3fSMatthias Ringwald                             buffer[5] = seg_n << 2 | MESH_GPCF_TRANSACTION_START;
57277ba3d3fSMatthias Ringwald                             big_endian_store_16(buffer, 6, pb_adv_msg_out_len);
57377ba3d3fSMatthias Ringwald                             buffer[8] = btstack_crc8_calc((uint8_t*)pb_adv_msg_out_buffer, pb_adv_msg_out_len);
57477ba3d3fSMatthias Ringwald                             pos = 9;
57577ba3d3fSMatthias Ringwald                             bytes_left = 24 - 4;
57677ba3d3fSMatthias Ringwald                             printf("PB-ADV: %02x Sending Start: ", pb_adv_msg_out_transaction_nr);
57777ba3d3fSMatthias Ringwald                         } else {
57877ba3d3fSMatthias Ringwald                             // Transaction continue
57977ba3d3fSMatthias Ringwald                             buffer[5] = pb_adv_msg_out_seg << 2 | MESH_GPCF_TRANSACTION_CONT;
58077ba3d3fSMatthias Ringwald                             pos = 6;
58177ba3d3fSMatthias Ringwald                             bytes_left = 24 - 1;
58277ba3d3fSMatthias Ringwald                             printf("PB-ADV: %02x Sending Cont:  ", pb_adv_msg_out_transaction_nr);
58377ba3d3fSMatthias Ringwald                         }
58477ba3d3fSMatthias Ringwald                         pb_adv_msg_out_seg++;
58577ba3d3fSMatthias Ringwald                         uint16_t bytes_to_copy = btstack_min(bytes_left, pb_adv_msg_out_len - pb_adv_msg_out_pos);
5866535961aSMatthias Ringwald                         (void)memcpy(&buffer[pos],
5876535961aSMatthias Ringwald                                      &pb_adv_msg_out_buffer[pb_adv_msg_out_pos],
5886535961aSMatthias Ringwald                                      bytes_to_copy);
58977ba3d3fSMatthias Ringwald                         pos += bytes_to_copy;
59077ba3d3fSMatthias Ringwald                         printf("bytes %02u, pos %02u, len %02u: ", bytes_to_copy, pb_adv_msg_out_pos, pb_adv_msg_out_len);
59177ba3d3fSMatthias Ringwald                         printf_hexdump(buffer, pos);
59277ba3d3fSMatthias Ringwald                         pb_adv_msg_out_pos += bytes_to_copy;
59377ba3d3fSMatthias Ringwald 
59477ba3d3fSMatthias Ringwald                         if (pb_adv_msg_out_pos == pb_adv_msg_out_len){
59577ba3d3fSMatthias Ringwald                             // done
59677ba3d3fSMatthias Ringwald                             pb_adv_msg_out_pos = 0;
59777ba3d3fSMatthias Ringwald                         }
5984662af4aSMatthias Ringwald                         adv_bearer_send_provisioning_pdu(buffer, pos);
59977ba3d3fSMatthias Ringwald                         pb_adv_run();
60077ba3d3fSMatthias Ringwald                         break;
60177ba3d3fSMatthias Ringwald                     }
60277ba3d3fSMatthias Ringwald                     break;
60377ba3d3fSMatthias Ringwald                 default:
60477ba3d3fSMatthias Ringwald                     break;
60577ba3d3fSMatthias Ringwald             }
60677ba3d3fSMatthias Ringwald         default:
60777ba3d3fSMatthias Ringwald             break;
60877ba3d3fSMatthias Ringwald     }
60977ba3d3fSMatthias Ringwald }
61077ba3d3fSMatthias Ringwald 
6118936a143SMatthias Ringwald void pb_adv_init(void){
6124662af4aSMatthias Ringwald     adv_bearer_register_for_provisioning_pdu(&pb_adv_handler);
61377ba3d3fSMatthias Ringwald     pb_adv_lfsr = 0x12345678;
61477ba3d3fSMatthias Ringwald     pb_adv_random();
61577ba3d3fSMatthias Ringwald }
61677ba3d3fSMatthias Ringwald 
61777ba3d3fSMatthias Ringwald void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
61877ba3d3fSMatthias Ringwald     pb_adv_packet_handler = packet_handler;
61977ba3d3fSMatthias Ringwald }
62077ba3d3fSMatthias Ringwald 
621f8962c62SMatthias Ringwald void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
622f8962c62SMatthias Ringwald     UNUSED(pb_transport_cid);
62377ba3d3fSMatthias Ringwald     printf("PB-ADV: Send packet ");
62477ba3d3fSMatthias Ringwald     printf_hexdump(pdu, size);
62577ba3d3fSMatthias Ringwald     pb_adv_msg_out_buffer = pdu;
62677ba3d3fSMatthias Ringwald     pb_adv_msg_out_len    = size;
62777ba3d3fSMatthias Ringwald     pb_adv_msg_out_pos = 0;
62877ba3d3fSMatthias Ringwald     pb_adv_msg_out_start = btstack_run_loop_get_time_ms();
62977ba3d3fSMatthias Ringwald     pb_adv_msg_out_active = 1;
63077ba3d3fSMatthias Ringwald     pb_adv_run();
63177ba3d3fSMatthias Ringwald }
63277ba3d3fSMatthias Ringwald 
63377ba3d3fSMatthias Ringwald /**
63477ba3d3fSMatthias Ringwald  * Close Link
635f8962c62SMatthias Ringwald  * @param pb_transport_cid
63677ba3d3fSMatthias Ringwald  */
637f8962c62SMatthias Ringwald void pb_adv_close_link(uint16_t pb_transport_cid, uint8_t reason){
63877ba3d3fSMatthias Ringwald     switch (link_state){
63977ba3d3fSMatthias Ringwald         case LINK_STATE_W4_ACK:
64077ba3d3fSMatthias Ringwald         case LINK_STATE_OPEN:
64177ba3d3fSMatthias Ringwald         case LINK_STATE_W2_SEND_ACK:
642f8962c62SMatthias Ringwald             pb_adv_emit_link_close(pb_transport_cid, 0);
64377ba3d3fSMatthias Ringwald             link_state = LINK_STATE_CLOSING;
64477ba3d3fSMatthias Ringwald             pb_adv_link_close_countdown = 3;
64577ba3d3fSMatthias Ringwald             pb_adv_link_close_reason = reason;
6464662af4aSMatthias Ringwald             adv_bearer_request_can_send_now_for_provisioning_pdu();
64777ba3d3fSMatthias Ringwald             break;
64877ba3d3fSMatthias Ringwald         case LINK_STATE_W4_OPEN:
64977ba3d3fSMatthias Ringwald         case LINK_STATE_CLOSING:
65077ba3d3fSMatthias Ringwald             // nothing to do
65177ba3d3fSMatthias Ringwald             break;
65277ba3d3fSMatthias Ringwald     }
65377ba3d3fSMatthias Ringwald }
65477ba3d3fSMatthias Ringwald 
65577ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
65677ba3d3fSMatthias Ringwald uint16_t pb_adv_create_link(const uint8_t * device_uuid){
65777ba3d3fSMatthias Ringwald     if (link_state != LINK_STATE_W4_OPEN) return 0;
65877ba3d3fSMatthias Ringwald 
65977ba3d3fSMatthias Ringwald     pb_adv_peer_device_uuid = device_uuid;
66077ba3d3fSMatthias Ringwald     pb_adv_provisioner_role = 1;
661d16ad46bSMatthias Ringwald     pb_adv_provisioner_open_countdown = PB_ADV_LINK_OPEN_RETRIES;
66277ba3d3fSMatthias Ringwald 
66377ba3d3fSMatthias Ringwald     // create new 32-bit link id
66477ba3d3fSMatthias Ringwald     pb_adv_link_id = pb_adv_random();
66577ba3d3fSMatthias Ringwald 
66677ba3d3fSMatthias Ringwald     // after sending OPEN, we wait for an ACK
66777ba3d3fSMatthias Ringwald     link_state = LINK_STATE_W4_ACK;
66877ba3d3fSMatthias Ringwald 
66977ba3d3fSMatthias Ringwald     // request outgoing
6704662af4aSMatthias Ringwald     adv_bearer_request_can_send_now_for_provisioning_pdu();
67177ba3d3fSMatthias Ringwald 
67277ba3d3fSMatthias Ringwald     // dummy pb_adv_cid
67377ba3d3fSMatthias Ringwald     return pb_adv_cid;
67477ba3d3fSMatthias Ringwald }
67577ba3d3fSMatthias Ringwald #endif
67677ba3d3fSMatthias Ringwald 
677