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
42cb7b3e6fSMatthias 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
73*864e2f2bSMatthias Ringwald // TODO: how large are prov messages? => how many segments are required?
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
77*864e2f2bSMatthias Ringwald #define MESH_PB_ADV_MAX_PDU_SIZE (MESH_PB_ADV_START_PAYLOAD + (MESH_PB_ADV_MAX_SEGMENTS-2) * MESH_PB_ADV_CONT_PAYLOAD)
78*864e2f2bSMatthias Ringwald
7977ba3d3fSMatthias Ringwald
8077ba3d3fSMatthias Ringwald typedef enum mesh_gpcf_format {
8177ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_START = 0,
8277ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_ACK,
8377ba3d3fSMatthias Ringwald MESH_GPCF_TRANSACTION_CONT,
8477ba3d3fSMatthias Ringwald MESH_GPCF_PROV_BEARER_CONTROL,
8577ba3d3fSMatthias Ringwald } mesh_gpcf_format_t;
8677ba3d3fSMatthias Ringwald
8777ba3d3fSMatthias Ringwald typedef enum {
8877ba3d3fSMatthias Ringwald LINK_STATE_W4_OPEN,
8977ba3d3fSMatthias Ringwald LINK_STATE_W2_SEND_ACK,
9077ba3d3fSMatthias Ringwald LINK_STATE_W4_ACK,
9177ba3d3fSMatthias Ringwald LINK_STATE_OPEN,
9277ba3d3fSMatthias Ringwald LINK_STATE_CLOSING,
9377ba3d3fSMatthias Ringwald } link_state_t;
9477ba3d3fSMatthias Ringwald static link_state_t link_state;
9577ba3d3fSMatthias Ringwald
9677ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
9777ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_peer_device_uuid;
98d16ad46bSMatthias Ringwald static uint8_t pb_adv_provisioner_open_countdown;
9977ba3d3fSMatthias Ringwald #endif
10077ba3d3fSMatthias Ringwald
101*864e2f2bSMatthias Ringwald static uint8_t pb_adv_msg_in_buffer[MESH_PB_ADV_MAX_PDU_SIZE];
10277ba3d3fSMatthias Ringwald
10394d617e4SMatthias Ringwald // single adv link, roles: provisioner = 1, device = 0
10477ba3d3fSMatthias Ringwald static uint16_t pb_adv_cid = 1;
10577ba3d3fSMatthias Ringwald static uint8_t pb_adv_provisioner_role;
10677ba3d3fSMatthias Ringwald
10777ba3d3fSMatthias Ringwald // link state
10877ba3d3fSMatthias Ringwald static uint32_t pb_adv_link_id;
10977ba3d3fSMatthias Ringwald static uint8_t pb_adv_link_close_reason;
11077ba3d3fSMatthias Ringwald static uint8_t pb_adv_link_close_countdown;
1111765fb5dSMatthias Ringwald static bool pb_adv_link_establish_timer_active;
11277ba3d3fSMatthias Ringwald
11377ba3d3fSMatthias Ringwald // random delay for outgoing packets
11477ba3d3fSMatthias Ringwald static uint32_t pb_adv_lfsr;
11577ba3d3fSMatthias Ringwald static uint8_t pb_adv_random_delay_active;
1161765fb5dSMatthias Ringwald
1171765fb5dSMatthias Ringwald // adv link timer used for
1181765fb5dSMatthias Ringwald // establishment:
1191765fb5dSMatthias Ringwald // - device: 60s timeout after receiving link open and sending link ack until first provisioning PDU
1201765fb5dSMatthias Ringwald // - provisioner: 1s timer to send link open messages
1211765fb5dSMatthias Ringwald // open: random delay
1221765fb5dSMatthias Ringwald static btstack_timer_source_t pb_adv_link_timer;
12377ba3d3fSMatthias Ringwald
12477ba3d3fSMatthias Ringwald // incoming message
12577ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_transaction_nr_prev;
12677ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_in_len; //
12777ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_fcs;
12877ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_last_segment;
12977ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_segments_missing; // bitfield for segmentes 1-n
13077ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_transaction_nr;
13177ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_in_send_ack;
13277ba3d3fSMatthias Ringwald
1334a72aacaSMatthias Ringwald // outgoing message
13477ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_active;
13577ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_transaction_nr;
13677ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_completed_transaction_nr;
13777ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_out_len;
13877ba3d3fSMatthias Ringwald static uint16_t pb_adv_msg_out_pos;
13977ba3d3fSMatthias Ringwald static uint8_t pb_adv_msg_out_seg;
14077ba3d3fSMatthias Ringwald static uint32_t pb_adv_msg_out_start;
14177ba3d3fSMatthias Ringwald static const uint8_t * pb_adv_msg_out_buffer;
14277ba3d3fSMatthias Ringwald
14394d617e4SMatthias Ringwald static btstack_packet_handler_t pb_adv_device_packet_handler;
14494d617e4SMatthias Ringwald static btstack_packet_handler_t pb_adv_provisioner_packet_handler;
14577ba3d3fSMatthias Ringwald
14677ba3d3fSMatthias Ringwald // poor man's random number generator
pb_adv_random(void)14777ba3d3fSMatthias Ringwald static uint32_t pb_adv_random(void){
14877ba3d3fSMatthias Ringwald pb_adv_lfsr = LFSR(pb_adv_lfsr);
14977ba3d3fSMatthias Ringwald return pb_adv_lfsr;
15077ba3d3fSMatthias Ringwald }
15177ba3d3fSMatthias Ringwald
pb_adv_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)15294d617e4SMatthias Ringwald static void pb_adv_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
15394d617e4SMatthias Ringwald if (pb_adv_provisioner_role == 0){
15494d617e4SMatthias Ringwald (*pb_adv_device_packet_handler)(packet_type, channel, packet, size);
15594d617e4SMatthias Ringwald } else {
15694d617e4SMatthias Ringwald (*pb_adv_provisioner_packet_handler)(packet_type, channel, packet, size);
15794d617e4SMatthias Ringwald }
15894d617e4SMatthias Ringwald }
15994d617e4SMatthias Ringwald
pb_adv_emit_pdu_sent(uint8_t status)16077ba3d3fSMatthias Ringwald static void pb_adv_emit_pdu_sent(uint8_t status){
16177ba3d3fSMatthias Ringwald uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
16277ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
16377ba3d3fSMatthias Ringwald }
16477ba3d3fSMatthias Ringwald
pb_adv_emit_link_open(uint8_t status,uint16_t pb_transport_cid)165f8962c62SMatthias Ringwald static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_transport_cid){
16677ba3d3fSMatthias Ringwald uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status};
167f8962c62SMatthias Ringwald little_endian_store_16(event, 4, pb_transport_cid);
16830a044b0SMilanka Ringwald event[6] = MESH_PB_TYPE_ADV;
16977ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
17077ba3d3fSMatthias Ringwald }
17177ba3d3fSMatthias Ringwald
pb_adv_emit_link_close(uint16_t pb_transport_cid,uint8_t reason)172f8962c62SMatthias Ringwald static void pb_adv_emit_link_close(uint16_t pb_transport_cid, uint8_t reason){
173f8962c62SMatthias Ringwald uint8_t event[6] = { HCI_EVENT_MESH_META, 3, MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED};
174f8962c62SMatthias Ringwald little_endian_store_16(event, 3, pb_transport_cid);
175f8962c62SMatthias Ringwald event[5] = reason;
17677ba3d3fSMatthias Ringwald pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
17777ba3d3fSMatthias Ringwald }
17877ba3d3fSMatthias Ringwald
pb_adv_device_link_timeout(btstack_timer_source_t * ts)1794a72aacaSMatthias Ringwald static void pb_adv_device_link_timeout(btstack_timer_source_t * ts){
1804a72aacaSMatthias Ringwald UNUSED(ts);
1814a72aacaSMatthias Ringwald // timeout occured
1824a72aacaSMatthias Ringwald link_state = LINK_STATE_W4_OPEN;
183cb7b3e6fSMatthias Ringwald log_info("link timeout, %08" PRIx32, pb_adv_link_id);
184cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link timeout %08" PRIx32 "\n", pb_adv_link_id);
1854a72aacaSMatthias Ringwald pb_adv_emit_link_close(pb_adv_cid, ERROR_CODE_PAGE_TIMEOUT);
1864a72aacaSMatthias Ringwald }
1874a72aacaSMatthias Ringwald
pb_adv_handle_bearer_control(uint32_t link_id,uint8_t transaction_nr,const uint8_t * pdu,uint16_t size)18877ba3d3fSMatthias Ringwald static void pb_adv_handle_bearer_control(uint32_t link_id, uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
189f843ee5dSMatthias Ringwald UNUSED(transaction_nr);
190f843ee5dSMatthias Ringwald UNUSED(size);
191f843ee5dSMatthias Ringwald
19277ba3d3fSMatthias Ringwald uint8_t bearer_opcode = pdu[0] >> 2;
19377ba3d3fSMatthias Ringwald uint8_t reason;
1948936a143SMatthias Ringwald const uint8_t * own_device_uuid;
19577ba3d3fSMatthias Ringwald switch (bearer_opcode){
19677ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_OPEN: // Open a session on a bearer with a device
19777ba3d3fSMatthias Ringwald // does it match our device_uuid?
1988936a143SMatthias Ringwald own_device_uuid = mesh_node_get_device_uuid();
1998936a143SMatthias Ringwald if (!own_device_uuid) break;
2008936a143SMatthias Ringwald if (memcmp(&pdu[1], own_device_uuid, 16) != 0) break;
2011765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer);
2021765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_TIMEOUT_MS);
2031765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_device_link_timeout);
2041765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer);
2051765fb5dSMatthias Ringwald pb_adv_link_establish_timer_active = true;
20677ba3d3fSMatthias Ringwald switch(link_state){
20777ba3d3fSMatthias Ringwald case LINK_STATE_W4_OPEN:
20877ba3d3fSMatthias Ringwald pb_adv_link_id = link_id;
20977ba3d3fSMatthias Ringwald pb_adv_provisioner_role = 0;
21077ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0xff; // first transaction nr will be 0x00
21177ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = 0xff;
212cb7b3e6fSMatthias Ringwald log_info("link open, id %08" PRIx32, pb_adv_link_id);
213cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link Open %08" PRIx32 "\n", pb_adv_link_id);
21477ba3d3fSMatthias Ringwald link_state = LINK_STATE_W2_SEND_ACK;
2154662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
216d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid);
21777ba3d3fSMatthias Ringwald break;
21877ba3d3fSMatthias Ringwald case LINK_STATE_OPEN:
21977ba3d3fSMatthias Ringwald if (pb_adv_link_id != link_id) break;
22077ba3d3fSMatthias Ringwald log_info("link open, resend ACK");
22177ba3d3fSMatthias Ringwald link_state = LINK_STATE_W2_SEND_ACK;
2224662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
22377ba3d3fSMatthias Ringwald break;
22477ba3d3fSMatthias Ringwald default:
22577ba3d3fSMatthias Ringwald break;
22677ba3d3fSMatthias Ringwald }
22777ba3d3fSMatthias Ringwald break;
22877ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
22977ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_ACK: // Acknowledge a session on a bearer
23077ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_ACK) break;
23177ba3d3fSMatthias Ringwald link_state = LINK_STATE_OPEN;
23277ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0;
23377ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0x7f; // first transaction nr will be 0x80
23477ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = 0x7f;
2351765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer);
236cb7b3e6fSMatthias Ringwald log_info("link open, id %08" PRIx32, pb_adv_link_id);
237cb7b3e6fSMatthias Ringwald printf("PB-ADV: Link Open %08" PRIx32 "\n", pb_adv_link_id);
238d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_SUCCESS, pb_adv_cid);
23977ba3d3fSMatthias Ringwald break;
24077ba3d3fSMatthias Ringwald #endif
24177ba3d3fSMatthias Ringwald case MESH_GENERIC_PROVISIONING_LINK_CLOSE: // Close a session on a bearer
24277ba3d3fSMatthias Ringwald // does it match link id
24377ba3d3fSMatthias Ringwald if (link_id != pb_adv_link_id) break;
2442e9a36a1SMatthias Ringwald if (link_state == LINK_STATE_W4_OPEN) break;
2451765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer);
24677ba3d3fSMatthias Ringwald reason = pdu[1];
24777ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_OPEN;
24877ba3d3fSMatthias Ringwald log_info("link close, reason %x", reason);
24977ba3d3fSMatthias Ringwald pb_adv_emit_link_close(pb_adv_cid, reason);
25077ba3d3fSMatthias Ringwald break;
25177ba3d3fSMatthias Ringwald default:
25277ba3d3fSMatthias Ringwald log_info("BearerOpcode %x reserved for future use\n", bearer_opcode);
25377ba3d3fSMatthias Ringwald break;
25477ba3d3fSMatthias Ringwald }
25577ba3d3fSMatthias Ringwald }
25677ba3d3fSMatthias Ringwald
pb_adv_pdu_complete(void)25777ba3d3fSMatthias Ringwald static void pb_adv_pdu_complete(void){
25877ba3d3fSMatthias Ringwald
25977ba3d3fSMatthias Ringwald // Verify FCS
26077ba3d3fSMatthias Ringwald uint8_t pdu_crc = btstack_crc8_calc((uint8_t*)pb_adv_msg_in_buffer, pb_adv_msg_in_len);
26177ba3d3fSMatthias Ringwald if (pdu_crc != pb_adv_msg_in_fcs){
26277ba3d3fSMatthias 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));
26377ba3d3fSMatthias Ringwald return;
26477ba3d3fSMatthias Ringwald }
26577ba3d3fSMatthias Ringwald
26677ba3d3fSMatthias Ringwald printf("PB-ADV: %02x complete\n", pb_adv_msg_in_transaction_nr);
26777ba3d3fSMatthias Ringwald
26877ba3d3fSMatthias Ringwald // transaction complete
26977ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr_prev = pb_adv_msg_in_transaction_nr;
27077ba3d3fSMatthias Ringwald if (pb_adv_provisioner_role){
27177ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0x7f; // invalid
27277ba3d3fSMatthias Ringwald } else {
27377ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = 0xff; // invalid
27477ba3d3fSMatthias Ringwald }
27577ba3d3fSMatthias Ringwald
27677ba3d3fSMatthias Ringwald // Ack Transaction
27777ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1;
27877ba3d3fSMatthias Ringwald pb_adv_run();
27977ba3d3fSMatthias Ringwald
28077ba3d3fSMatthias Ringwald // Forward to Provisioning
28177ba3d3fSMatthias Ringwald pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, pb_adv_msg_in_buffer, pb_adv_msg_in_len);
28277ba3d3fSMatthias Ringwald }
28377ba3d3fSMatthias Ringwald
pb_adv_handle_transaction_start(uint8_t transaction_nr,const uint8_t * pdu,uint16_t size)28477ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_start(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
28577ba3d3fSMatthias Ringwald
28677ba3d3fSMatthias Ringwald // resend ack if packet from previous transaction received
28777ba3d3fSMatthias Ringwald if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
28877ba3d3fSMatthias Ringwald printf("PB_ADV: %02x transaction complete, resending ack \n", transaction_nr);
28977ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1;
29077ba3d3fSMatthias Ringwald return;
29177ba3d3fSMatthias Ringwald }
29277ba3d3fSMatthias Ringwald
29377ba3d3fSMatthias Ringwald // new transaction?
29477ba3d3fSMatthias Ringwald if (transaction_nr != pb_adv_msg_in_transaction_nr){
29577ba3d3fSMatthias Ringwald
29677ba3d3fSMatthias Ringwald // check len
297205dc738SMatthias Ringwald if (size < 4) return;
298205dc738SMatthias Ringwald
299205dc738SMatthias Ringwald // check len
30077ba3d3fSMatthias Ringwald uint16_t msg_len = big_endian_read_16(pdu, 1);
30177ba3d3fSMatthias Ringwald if (msg_len > MESH_PB_ADV_MAX_PDU_SIZE){
30277ba3d3fSMatthias Ringwald // abort transaction
30377ba3d3fSMatthias Ringwald return;
30477ba3d3fSMatthias Ringwald }
30577ba3d3fSMatthias Ringwald
30677ba3d3fSMatthias Ringwald // check num segments
30777ba3d3fSMatthias Ringwald uint8_t last_segment = pdu[0] >> 2;
30877ba3d3fSMatthias Ringwald if (last_segment >= MESH_PB_ADV_MAX_SEGMENTS){
30977ba3d3fSMatthias Ringwald // abort transaction
31077ba3d3fSMatthias Ringwald return;
31177ba3d3fSMatthias Ringwald }
31277ba3d3fSMatthias Ringwald
31377ba3d3fSMatthias Ringwald printf("PB-ADV: %02x started\n", transaction_nr);
31477ba3d3fSMatthias Ringwald
31577ba3d3fSMatthias Ringwald pb_adv_msg_in_transaction_nr = transaction_nr;
31677ba3d3fSMatthias Ringwald pb_adv_msg_in_len = msg_len;
31777ba3d3fSMatthias Ringwald pb_adv_msg_in_fcs = pdu[3];
31877ba3d3fSMatthias Ringwald pb_adv_msg_in_last_segment = last_segment;
31977ba3d3fSMatthias Ringwald
32077ba3d3fSMatthias Ringwald // set bits for segments 1..n (segment 0 already received in this message)
32177ba3d3fSMatthias Ringwald pb_adv_msg_in_segments_missing = (1 << last_segment) - 1;
32277ba3d3fSMatthias Ringwald
32377ba3d3fSMatthias Ringwald // store payload
32477ba3d3fSMatthias Ringwald uint16_t payload_len = size - 4;
3256535961aSMatthias Ringwald (void)memcpy(pb_adv_msg_in_buffer, &pdu[4], payload_len);
32677ba3d3fSMatthias Ringwald
32777ba3d3fSMatthias Ringwald // complete?
32877ba3d3fSMatthias Ringwald if (pb_adv_msg_in_segments_missing == 0){
32977ba3d3fSMatthias Ringwald pb_adv_pdu_complete();
33077ba3d3fSMatthias Ringwald }
33177ba3d3fSMatthias Ringwald }
33277ba3d3fSMatthias Ringwald }
33377ba3d3fSMatthias Ringwald
pb_adv_handle_transaction_cont(uint8_t transaction_nr,const uint8_t * pdu,uint16_t size)33477ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_cont(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
33577ba3d3fSMatthias Ringwald
33677ba3d3fSMatthias Ringwald // check transaction nr
33777ba3d3fSMatthias Ringwald if (transaction_nr != 0xff && transaction_nr == pb_adv_msg_in_transaction_nr_prev){
33877ba3d3fSMatthias Ringwald printf("PB_ADV: %02x transaction complete, resending resending ack\n", transaction_nr);
33977ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 1;
34077ba3d3fSMatthias Ringwald return;
34177ba3d3fSMatthias Ringwald }
34277ba3d3fSMatthias Ringwald
34377ba3d3fSMatthias Ringwald if (transaction_nr != pb_adv_msg_in_transaction_nr){
34477ba3d3fSMatthias Ringwald printf("PB-ADV: %02x received msg for transaction nr %x\n", pb_adv_msg_in_transaction_nr, transaction_nr);
34577ba3d3fSMatthias Ringwald return;
34677ba3d3fSMatthias Ringwald }
34777ba3d3fSMatthias Ringwald
34877ba3d3fSMatthias Ringwald // validate seg nr
34977ba3d3fSMatthias Ringwald uint8_t seg = pdu[0] >> 2;
35077ba3d3fSMatthias Ringwald if (seg >= MESH_PB_ADV_MAX_SEGMENTS || seg == 0){
35177ba3d3fSMatthias Ringwald return;
35277ba3d3fSMatthias Ringwald }
35377ba3d3fSMatthias Ringwald
35477ba3d3fSMatthias Ringwald // check if segment already received
35577ba3d3fSMatthias Ringwald uint8_t seg_mask = 1 << (seg-1);
35677ba3d3fSMatthias Ringwald if ((pb_adv_msg_in_segments_missing & seg_mask) == 0){
35777ba3d3fSMatthias Ringwald printf("PB-ADV: %02x, segment %u already received\n", transaction_nr, seg);
35877ba3d3fSMatthias Ringwald return;
35977ba3d3fSMatthias Ringwald }
36077ba3d3fSMatthias Ringwald printf("PB-ADV: %02x, segment %u stored\n", transaction_nr, seg);
36177ba3d3fSMatthias Ringwald
36277ba3d3fSMatthias Ringwald // calculate offset and fragment size
36377ba3d3fSMatthias Ringwald uint16_t msg_pos = MESH_PB_ADV_START_PAYLOAD + (seg-1) * MESH_PB_ADV_CONT_PAYLOAD;
36477ba3d3fSMatthias Ringwald uint16_t fragment_size = size - 1;
36577ba3d3fSMatthias Ringwald
36677ba3d3fSMatthias Ringwald // check size if last segment
36777ba3d3fSMatthias Ringwald if (seg == pb_adv_msg_in_last_segment && (msg_pos + fragment_size) != pb_adv_msg_in_len){
36877ba3d3fSMatthias Ringwald // last segment has invalid size
36977ba3d3fSMatthias Ringwald return;
37077ba3d3fSMatthias Ringwald }
37177ba3d3fSMatthias Ringwald
37277ba3d3fSMatthias Ringwald // store segment and mark as received
3736535961aSMatthias Ringwald (void)memcpy(&pb_adv_msg_in_buffer[msg_pos], &pdu[1], fragment_size);
37477ba3d3fSMatthias Ringwald pb_adv_msg_in_segments_missing &= ~seg_mask;
37577ba3d3fSMatthias Ringwald
37677ba3d3fSMatthias Ringwald // last segment
37777ba3d3fSMatthias Ringwald if (pb_adv_msg_in_segments_missing == 0){
37877ba3d3fSMatthias Ringwald pb_adv_pdu_complete();
37977ba3d3fSMatthias Ringwald }
38077ba3d3fSMatthias Ringwald }
38177ba3d3fSMatthias Ringwald
pb_adv_outgoing_transaction_complete(uint8_t status)3824a72aacaSMatthias Ringwald static void pb_adv_outgoing_transaction_complete(uint8_t status){
38377ba3d3fSMatthias Ringwald // stop sending
38477ba3d3fSMatthias Ringwald pb_adv_msg_out_active = 0;
38577ba3d3fSMatthias Ringwald // emit done
38677ba3d3fSMatthias Ringwald pb_adv_emit_pdu_sent(status);
38777ba3d3fSMatthias Ringwald // keep track of ack'ed transactions
38877ba3d3fSMatthias Ringwald pb_adv_msg_out_completed_transaction_nr = pb_adv_msg_out_transaction_nr;
38977ba3d3fSMatthias Ringwald // increment outgoing transaction nr
39077ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr++;
39177ba3d3fSMatthias Ringwald if (pb_adv_msg_out_transaction_nr == 0x00){
39277ba3d3fSMatthias Ringwald // Device role
39377ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x80;
39477ba3d3fSMatthias Ringwald }
39577ba3d3fSMatthias Ringwald if (pb_adv_msg_out_transaction_nr == 0x80){
39677ba3d3fSMatthias Ringwald // Provisioner role
39777ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x00;
39877ba3d3fSMatthias Ringwald }
39977ba3d3fSMatthias Ringwald }
40077ba3d3fSMatthias Ringwald
pb_adv_handle_transaction_ack(uint8_t transaction_nr,const uint8_t * pdu,uint16_t size)40177ba3d3fSMatthias Ringwald static void pb_adv_handle_transaction_ack(uint8_t transaction_nr, const uint8_t * pdu, uint16_t size){
402f843ee5dSMatthias Ringwald UNUSED(pdu);
403f843ee5dSMatthias Ringwald UNUSED(size);
40477ba3d3fSMatthias Ringwald if (transaction_nr == pb_adv_msg_out_transaction_nr){
40577ba3d3fSMatthias Ringwald printf("PB-ADV: %02x ACK received\n", transaction_nr);
4064a72aacaSMatthias Ringwald pb_adv_outgoing_transaction_complete(ERROR_CODE_SUCCESS);
40777ba3d3fSMatthias Ringwald } else if (transaction_nr == pb_adv_msg_out_completed_transaction_nr){
40877ba3d3fSMatthias Ringwald // Transaction ack received again
40977ba3d3fSMatthias Ringwald } else {
41077ba3d3fSMatthias Ringwald printf("PB-ADV: %02x unexpected Transaction ACK %x recevied\n", pb_adv_msg_out_transaction_nr, transaction_nr);
41177ba3d3fSMatthias Ringwald }
41277ba3d3fSMatthias Ringwald }
41377ba3d3fSMatthias Ringwald
pb_adv_packet_to_send(void)41477ba3d3fSMatthias Ringwald static int pb_adv_packet_to_send(void){
41577ba3d3fSMatthias Ringwald return pb_adv_msg_in_send_ack || pb_adv_msg_out_active || (link_state == LINK_STATE_W4_ACK);
41677ba3d3fSMatthias Ringwald }
41777ba3d3fSMatthias Ringwald
pb_adv_timer_handler(btstack_timer_source_t * ts)41877ba3d3fSMatthias Ringwald static void pb_adv_timer_handler(btstack_timer_source_t * ts){
4192983fbcbSMatthias Ringwald UNUSED(ts);
42077ba3d3fSMatthias Ringwald pb_adv_random_delay_active = 0;
42177ba3d3fSMatthias Ringwald if (!pb_adv_packet_to_send()) return;
4224662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
42377ba3d3fSMatthias Ringwald }
42477ba3d3fSMatthias Ringwald
pb_adv_run(void)42577ba3d3fSMatthias Ringwald static void pb_adv_run(void){
42677ba3d3fSMatthias Ringwald if (!pb_adv_packet_to_send()) return;
42777ba3d3fSMatthias Ringwald if (pb_adv_random_delay_active) return;
42877ba3d3fSMatthias Ringwald
42977ba3d3fSMatthias Ringwald // spec recommends 20-50 ms, we use 20-51 ms
43077ba3d3fSMatthias Ringwald pb_adv_random_delay_active = 1;
43177ba3d3fSMatthias Ringwald uint16_t random_delay_ms = 20 + (pb_adv_random() & 0x1f);
43277ba3d3fSMatthias Ringwald log_info("random delay %u ms", random_delay_ms);
4331765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler);
4341765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, random_delay_ms);
4351765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer);
43677ba3d3fSMatthias Ringwald }
43777ba3d3fSMatthias Ringwald
pb_adv_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)43877ba3d3fSMatthias Ringwald static void pb_adv_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
4392983fbcbSMatthias Ringwald UNUSED(channel);
4402983fbcbSMatthias Ringwald
44177ba3d3fSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return;
442205dc738SMatthias Ringwald if (size < 3) return;
443205dc738SMatthias Ringwald
44477ba3d3fSMatthias Ringwald const uint8_t * data;
44577ba3d3fSMatthias Ringwald uint8_t length;
44677ba3d3fSMatthias Ringwald uint32_t link_id;
44777ba3d3fSMatthias Ringwald uint8_t transaction_nr;
44877ba3d3fSMatthias Ringwald uint8_t generic_provisioning_control;
44977ba3d3fSMatthias Ringwald switch(packet[0]){
45077ba3d3fSMatthias Ringwald case GAP_EVENT_ADVERTISING_REPORT:
451205dc738SMatthias Ringwald // check minimal size
452205dc738SMatthias Ringwald if (size < (12 + 8)) return;
453205dc738SMatthias Ringwald
454f843ee5dSMatthias Ringwald // data starts at offset 12
455f843ee5dSMatthias Ringwald data = &packet[12];
45677ba3d3fSMatthias Ringwald // PDB ADV PDU
45777ba3d3fSMatthias Ringwald length = data[0];
458f843ee5dSMatthias Ringwald
459f843ee5dSMatthias Ringwald // validate length field
460f843ee5dSMatthias Ringwald if ((12 + length) > size) return;
461f843ee5dSMatthias Ringwald
46277ba3d3fSMatthias Ringwald link_id = big_endian_read_32(data, 2);
46377ba3d3fSMatthias Ringwald transaction_nr = data[6];
46477ba3d3fSMatthias Ringwald // generic provision PDU
46577ba3d3fSMatthias Ringwald generic_provisioning_control = data[7];
46677ba3d3fSMatthias Ringwald mesh_gpcf_format_t generic_provisioning_control_format = (mesh_gpcf_format_t) generic_provisioning_control & 3;
46777ba3d3fSMatthias Ringwald
46877ba3d3fSMatthias Ringwald // unless, we're waiting for LINK_OPEN, check link_id
46977ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_OPEN){
47077ba3d3fSMatthias Ringwald if (link_id != pb_adv_link_id) break;
47177ba3d3fSMatthias Ringwald }
47277ba3d3fSMatthias Ringwald
47377ba3d3fSMatthias Ringwald if (generic_provisioning_control_format == MESH_GPCF_PROV_BEARER_CONTROL){
47477ba3d3fSMatthias Ringwald pb_adv_handle_bearer_control(link_id, transaction_nr, &data[7], length-6);
47577ba3d3fSMatthias Ringwald break;
47677ba3d3fSMatthias Ringwald }
47777ba3d3fSMatthias Ringwald
47877ba3d3fSMatthias Ringwald // verify link id and link state
47977ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_OPEN) break;
48077ba3d3fSMatthias Ringwald
4814a72aacaSMatthias Ringwald // stop link establishment timer
4821765fb5dSMatthias Ringwald if (pb_adv_link_establish_timer_active) {
4831765fb5dSMatthias Ringwald pb_adv_link_establish_timer_active = false;
4841765fb5dSMatthias Ringwald btstack_run_loop_remove_timer(&pb_adv_link_timer);
4851765fb5dSMatthias Ringwald }
4864a72aacaSMatthias Ringwald
48777ba3d3fSMatthias Ringwald switch (generic_provisioning_control_format){
48877ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_START:
48977ba3d3fSMatthias Ringwald pb_adv_handle_transaction_start(transaction_nr, &data[7], length-6);
49077ba3d3fSMatthias Ringwald break;
49177ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_CONT:
49277ba3d3fSMatthias Ringwald pb_adv_handle_transaction_cont(transaction_nr, &data[7], length-6);
49377ba3d3fSMatthias Ringwald break;
49477ba3d3fSMatthias Ringwald case MESH_GPCF_TRANSACTION_ACK:
49577ba3d3fSMatthias Ringwald pb_adv_handle_transaction_ack(transaction_nr, &data[7], length-6);
49677ba3d3fSMatthias Ringwald break;
49777ba3d3fSMatthias Ringwald default:
49877ba3d3fSMatthias Ringwald break;
49977ba3d3fSMatthias Ringwald }
50077ba3d3fSMatthias Ringwald pb_adv_run();
50177ba3d3fSMatthias Ringwald break;
50277ba3d3fSMatthias Ringwald case HCI_EVENT_MESH_META:
50377ba3d3fSMatthias Ringwald switch(packet[2]){
50477ba3d3fSMatthias Ringwald case MESH_SUBEVENT_CAN_SEND_NOW:
505480ff3cbSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
50677ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_W4_ACK){
507d16ad46bSMatthias Ringwald pb_adv_provisioner_open_countdown--;
508d16ad46bSMatthias Ringwald if (pb_adv_provisioner_open_countdown == 0){
509d16ad46bSMatthias Ringwald pb_adv_emit_link_open(ERROR_CODE_PAGE_TIMEOUT, pb_adv_cid);
510d16ad46bSMatthias Ringwald break;
511d16ad46bSMatthias Ringwald }
51277ba3d3fSMatthias Ringwald // build packet
51377ba3d3fSMatthias Ringwald uint8_t buffer[22];
51477ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id);
51577ba3d3fSMatthias Ringwald buffer[4] = 0; // Transaction ID = 0
51677ba3d3fSMatthias Ringwald buffer[5] = (0 << 2) | 3; // Link Open | Provisioning Bearer Control
5176535961aSMatthias Ringwald (void)memcpy(&buffer[6], pb_adv_peer_device_uuid, 16);
5184662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
519cb7b3e6fSMatthias Ringwald log_info("link open %08" PRIx32, pb_adv_link_id);
52077ba3d3fSMatthias Ringwald printf("PB-ADV: Sending Link Open for device uuid: ");
52177ba3d3fSMatthias Ringwald printf_hexdump(pb_adv_peer_device_uuid, 16);
5221765fb5dSMatthias Ringwald btstack_run_loop_set_timer_handler(&pb_adv_link_timer, &pb_adv_timer_handler);
5231765fb5dSMatthias Ringwald btstack_run_loop_set_timer(&pb_adv_link_timer, PB_ADV_LINK_OPEN_RETRANSMIT_MS);
5241765fb5dSMatthias Ringwald btstack_run_loop_add_timer(&pb_adv_link_timer);
52577ba3d3fSMatthias Ringwald break;
52677ba3d3fSMatthias Ringwald }
527480ff3cbSMatthias Ringwald #endif
52877ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_CLOSING){
529cb7b3e6fSMatthias Ringwald log_info("link close %08" PRIx32, pb_adv_link_id);
530cb7b3e6fSMatthias Ringwald printf("PB-ADV: Sending Link Close %08" PRIx32 "\n", pb_adv_link_id);
53177ba3d3fSMatthias Ringwald // build packet
53277ba3d3fSMatthias Ringwald uint8_t buffer[7];
53377ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id);
53477ba3d3fSMatthias Ringwald buffer[4] = 0; // Transaction ID = 0
53577ba3d3fSMatthias Ringwald buffer[5] = (2 << 2) | 3; // Link Close | Provisioning Bearer Control
53677ba3d3fSMatthias Ringwald buffer[6] = pb_adv_link_close_reason;
5374662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
53877ba3d3fSMatthias Ringwald pb_adv_link_close_countdown--;
53977ba3d3fSMatthias Ringwald if (pb_adv_link_close_countdown) {
5404662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
54177ba3d3fSMatthias Ringwald } else {
54277ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_OPEN;
54377ba3d3fSMatthias Ringwald }
54477ba3d3fSMatthias Ringwald break;
54577ba3d3fSMatthias Ringwald }
54677ba3d3fSMatthias Ringwald if (link_state == LINK_STATE_W2_SEND_ACK){
54777ba3d3fSMatthias Ringwald link_state = LINK_STATE_OPEN;
54877ba3d3fSMatthias Ringwald pb_adv_msg_out_transaction_nr = 0x80;
54977ba3d3fSMatthias Ringwald // build packet
55077ba3d3fSMatthias Ringwald uint8_t buffer[6];
55177ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id);
55277ba3d3fSMatthias Ringwald buffer[4] = 0;
55377ba3d3fSMatthias Ringwald buffer[5] = (1 << 2) | 3; // Link Ack | Provisioning Bearer Control
5544662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
555cb7b3e6fSMatthias Ringwald log_info("link ack %08" PRIx32, pb_adv_link_id);
556cb7b3e6fSMatthias Ringwald printf("PB-ADV: Sending Link Open Ack %08" PRIx32 "\n", pb_adv_link_id);
55777ba3d3fSMatthias Ringwald break;
55877ba3d3fSMatthias Ringwald }
55977ba3d3fSMatthias Ringwald if (pb_adv_msg_in_send_ack){
56077ba3d3fSMatthias Ringwald pb_adv_msg_in_send_ack = 0;
56177ba3d3fSMatthias Ringwald uint8_t buffer[6];
56277ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id);
56377ba3d3fSMatthias Ringwald buffer[4] = pb_adv_msg_in_transaction_nr_prev;
56477ba3d3fSMatthias Ringwald buffer[5] = MESH_GPCF_TRANSACTION_ACK;
5654662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, sizeof(buffer));
566cb7b3e6fSMatthias Ringwald log_info("transaction ack %08" PRIx32, pb_adv_link_id);
56777ba3d3fSMatthias Ringwald printf("PB-ADV: %02x sending ACK\n", pb_adv_msg_in_transaction_nr_prev);
56877ba3d3fSMatthias Ringwald pb_adv_run();
56977ba3d3fSMatthias Ringwald break;
57077ba3d3fSMatthias Ringwald }
57177ba3d3fSMatthias Ringwald if (pb_adv_msg_out_active){
57277ba3d3fSMatthias Ringwald
57377ba3d3fSMatthias Ringwald // check timeout for outgoing message
57477ba3d3fSMatthias Ringwald // since uint32_t is used and time now must be greater than pb_adv_msg_out_start,
57577ba3d3fSMatthias Ringwald // this claculation is correct even when the run loop time overruns
57677ba3d3fSMatthias Ringwald uint32_t transaction_time_ms = btstack_run_loop_get_time_ms() - pb_adv_msg_out_start;
57777ba3d3fSMatthias Ringwald if (transaction_time_ms >= MESH_GENERIC_PROVISIONING_TRANSACTION_TIMEOUT_MS){
5784a72aacaSMatthias Ringwald pb_adv_outgoing_transaction_complete(ERROR_CODE_CONNECTION_TIMEOUT);
57977ba3d3fSMatthias Ringwald return;
58077ba3d3fSMatthias Ringwald }
58177ba3d3fSMatthias Ringwald
58277ba3d3fSMatthias Ringwald uint8_t buffer[29]; // ADV MTU
58377ba3d3fSMatthias Ringwald big_endian_store_32(buffer, 0, pb_adv_link_id);
58477ba3d3fSMatthias Ringwald buffer[4] = pb_adv_msg_out_transaction_nr;
58577ba3d3fSMatthias Ringwald uint16_t bytes_left;
58677ba3d3fSMatthias Ringwald uint16_t pos;
58777ba3d3fSMatthias Ringwald if (pb_adv_msg_out_pos == 0){
58877ba3d3fSMatthias Ringwald // Transaction start
58977ba3d3fSMatthias Ringwald int seg_n = pb_adv_msg_out_len / 24;
59077ba3d3fSMatthias Ringwald pb_adv_msg_out_seg = 0;
59177ba3d3fSMatthias Ringwald buffer[5] = seg_n << 2 | MESH_GPCF_TRANSACTION_START;
59277ba3d3fSMatthias Ringwald big_endian_store_16(buffer, 6, pb_adv_msg_out_len);
59377ba3d3fSMatthias Ringwald buffer[8] = btstack_crc8_calc((uint8_t*)pb_adv_msg_out_buffer, pb_adv_msg_out_len);
59477ba3d3fSMatthias Ringwald pos = 9;
59577ba3d3fSMatthias Ringwald bytes_left = 24 - 4;
59677ba3d3fSMatthias Ringwald printf("PB-ADV: %02x Sending Start: ", pb_adv_msg_out_transaction_nr);
59777ba3d3fSMatthias Ringwald } else {
59877ba3d3fSMatthias Ringwald // Transaction continue
59977ba3d3fSMatthias Ringwald buffer[5] = pb_adv_msg_out_seg << 2 | MESH_GPCF_TRANSACTION_CONT;
60077ba3d3fSMatthias Ringwald pos = 6;
60177ba3d3fSMatthias Ringwald bytes_left = 24 - 1;
60277ba3d3fSMatthias Ringwald printf("PB-ADV: %02x Sending Cont: ", pb_adv_msg_out_transaction_nr);
60377ba3d3fSMatthias Ringwald }
60477ba3d3fSMatthias Ringwald pb_adv_msg_out_seg++;
60577ba3d3fSMatthias Ringwald uint16_t bytes_to_copy = btstack_min(bytes_left, pb_adv_msg_out_len - pb_adv_msg_out_pos);
6066535961aSMatthias Ringwald (void)memcpy(&buffer[pos],
6076535961aSMatthias Ringwald &pb_adv_msg_out_buffer[pb_adv_msg_out_pos],
6086535961aSMatthias Ringwald bytes_to_copy);
60977ba3d3fSMatthias Ringwald pos += bytes_to_copy;
61077ba3d3fSMatthias Ringwald printf("bytes %02u, pos %02u, len %02u: ", bytes_to_copy, pb_adv_msg_out_pos, pb_adv_msg_out_len);
61177ba3d3fSMatthias Ringwald printf_hexdump(buffer, pos);
61277ba3d3fSMatthias Ringwald pb_adv_msg_out_pos += bytes_to_copy;
61377ba3d3fSMatthias Ringwald
61477ba3d3fSMatthias Ringwald if (pb_adv_msg_out_pos == pb_adv_msg_out_len){
61577ba3d3fSMatthias Ringwald // done
61677ba3d3fSMatthias Ringwald pb_adv_msg_out_pos = 0;
61777ba3d3fSMatthias Ringwald }
6184662af4aSMatthias Ringwald adv_bearer_send_provisioning_pdu(buffer, pos);
61977ba3d3fSMatthias Ringwald pb_adv_run();
62077ba3d3fSMatthias Ringwald break;
62177ba3d3fSMatthias Ringwald }
62277ba3d3fSMatthias Ringwald break;
62377ba3d3fSMatthias Ringwald default:
62477ba3d3fSMatthias Ringwald break;
62577ba3d3fSMatthias Ringwald }
62677ba3d3fSMatthias Ringwald default:
62777ba3d3fSMatthias Ringwald break;
62877ba3d3fSMatthias Ringwald }
62977ba3d3fSMatthias Ringwald }
63077ba3d3fSMatthias Ringwald
pb_adv_init(void)6318936a143SMatthias Ringwald void pb_adv_init(void){
6324662af4aSMatthias Ringwald adv_bearer_register_for_provisioning_pdu(&pb_adv_handler);
63377ba3d3fSMatthias Ringwald pb_adv_lfsr = 0x12345678;
63477ba3d3fSMatthias Ringwald pb_adv_random();
63577ba3d3fSMatthias Ringwald }
63677ba3d3fSMatthias Ringwald
pb_adv_register_device_packet_handler(btstack_packet_handler_t packet_handler)63794d617e4SMatthias Ringwald void pb_adv_register_device_packet_handler(btstack_packet_handler_t packet_handler){
63894d617e4SMatthias Ringwald pb_adv_device_packet_handler = packet_handler;
63994d617e4SMatthias Ringwald }
64094d617e4SMatthias Ringwald
pb_adv_register_provisioner_packet_handler(btstack_packet_handler_t packet_handler)64194d617e4SMatthias Ringwald void pb_adv_register_provisioner_packet_handler(btstack_packet_handler_t packet_handler){
64294d617e4SMatthias Ringwald pb_adv_provisioner_packet_handler = packet_handler;
64377ba3d3fSMatthias Ringwald }
64477ba3d3fSMatthias Ringwald
pb_adv_send_pdu(uint16_t pb_transport_cid,const uint8_t * pdu,uint16_t size)645f8962c62SMatthias Ringwald void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
646f8962c62SMatthias Ringwald UNUSED(pb_transport_cid);
64777ba3d3fSMatthias Ringwald printf("PB-ADV: Send packet ");
64877ba3d3fSMatthias Ringwald printf_hexdump(pdu, size);
64977ba3d3fSMatthias Ringwald pb_adv_msg_out_buffer = pdu;
65077ba3d3fSMatthias Ringwald pb_adv_msg_out_len = size;
65177ba3d3fSMatthias Ringwald pb_adv_msg_out_pos = 0;
65277ba3d3fSMatthias Ringwald pb_adv_msg_out_start = btstack_run_loop_get_time_ms();
65377ba3d3fSMatthias Ringwald pb_adv_msg_out_active = 1;
65477ba3d3fSMatthias Ringwald pb_adv_run();
65577ba3d3fSMatthias Ringwald }
65677ba3d3fSMatthias Ringwald
65777ba3d3fSMatthias Ringwald /**
65877ba3d3fSMatthias Ringwald * Close Link
659f8962c62SMatthias Ringwald * @param pb_transport_cid
66077ba3d3fSMatthias Ringwald */
pb_adv_close_link(uint16_t pb_transport_cid,uint8_t reason)661f8962c62SMatthias Ringwald void pb_adv_close_link(uint16_t pb_transport_cid, uint8_t reason){
66277ba3d3fSMatthias Ringwald switch (link_state){
66377ba3d3fSMatthias Ringwald case LINK_STATE_W4_ACK:
66477ba3d3fSMatthias Ringwald case LINK_STATE_OPEN:
66577ba3d3fSMatthias Ringwald case LINK_STATE_W2_SEND_ACK:
666f8962c62SMatthias Ringwald pb_adv_emit_link_close(pb_transport_cid, 0);
66777ba3d3fSMatthias Ringwald link_state = LINK_STATE_CLOSING;
66877ba3d3fSMatthias Ringwald pb_adv_link_close_countdown = 3;
66977ba3d3fSMatthias Ringwald pb_adv_link_close_reason = reason;
6704662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
67177ba3d3fSMatthias Ringwald break;
67277ba3d3fSMatthias Ringwald case LINK_STATE_W4_OPEN:
67377ba3d3fSMatthias Ringwald case LINK_STATE_CLOSING:
67477ba3d3fSMatthias Ringwald // nothing to do
67577ba3d3fSMatthias Ringwald break;
6767bbeb3adSMilanka Ringwald default:
6777bbeb3adSMilanka Ringwald btstack_assert(false);
6787bbeb3adSMilanka Ringwald break;
67977ba3d3fSMatthias Ringwald }
68077ba3d3fSMatthias Ringwald }
68177ba3d3fSMatthias Ringwald
68277ba3d3fSMatthias Ringwald #ifdef ENABLE_MESH_PROVISIONER
pb_adv_create_link(const uint8_t * device_uuid)68377ba3d3fSMatthias Ringwald uint16_t pb_adv_create_link(const uint8_t * device_uuid){
68477ba3d3fSMatthias Ringwald if (link_state != LINK_STATE_W4_OPEN) return 0;
68577ba3d3fSMatthias Ringwald
68677ba3d3fSMatthias Ringwald pb_adv_peer_device_uuid = device_uuid;
68777ba3d3fSMatthias Ringwald pb_adv_provisioner_role = 1;
688d16ad46bSMatthias Ringwald pb_adv_provisioner_open_countdown = PB_ADV_LINK_OPEN_RETRIES;
68977ba3d3fSMatthias Ringwald
69077ba3d3fSMatthias Ringwald // create new 32-bit link id
69177ba3d3fSMatthias Ringwald pb_adv_link_id = pb_adv_random();
69277ba3d3fSMatthias Ringwald
69377ba3d3fSMatthias Ringwald // after sending OPEN, we wait for an ACK
69477ba3d3fSMatthias Ringwald link_state = LINK_STATE_W4_ACK;
69577ba3d3fSMatthias Ringwald
69677ba3d3fSMatthias Ringwald // request outgoing
6974662af4aSMatthias Ringwald adv_bearer_request_can_send_now_for_provisioning_pdu();
69877ba3d3fSMatthias Ringwald
69977ba3d3fSMatthias Ringwald // dummy pb_adv_cid
70077ba3d3fSMatthias Ringwald return pb_adv_cid;
70177ba3d3fSMatthias Ringwald }
70277ba3d3fSMatthias Ringwald #endif
70377ba3d3fSMatthias Ringwald
704