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_gatt.c"
3977ba3d3fSMatthias Ringwald
40f4854a5eSMatthias Ringwald #include "mesh/pb_gatt.h"
41f4854a5eSMatthias Ringwald
4277ba3d3fSMatthias Ringwald #include <stdlib.h>
4377ba3d3fSMatthias Ringwald #include <string.h>
44f4854a5eSMatthias Ringwald
45f4854a5eSMatthias Ringwald #include "ble/att_server.h"
46*d567aeb3SMatthias Ringwald #include "mesh/gatt-service/mesh_provisioning_service_server.h"
47f4854a5eSMatthias Ringwald
4877ba3d3fSMatthias Ringwald #include "btstack_debug.h"
4977ba3d3fSMatthias Ringwald #include "btstack_event.h"
50f4854a5eSMatthias Ringwald #include "btstack_util.h"
51f4854a5eSMatthias Ringwald
52f4854a5eSMatthias Ringwald #include "mesh/provisioning.h"
5377ba3d3fSMatthias Ringwald
5477ba3d3fSMatthias Ringwald /************** PB GATT Mesh Provisioning ********************/
5577ba3d3fSMatthias Ringwald
5677ba3d3fSMatthias Ringwald // share buffer for reassembly and segmentation - protocol is half-duplex
5777ba3d3fSMatthias Ringwald static union {
5877ba3d3fSMatthias Ringwald uint8_t reassembly_buffer[MESH_PROV_MAX_PROXY_PDU];
5977ba3d3fSMatthias Ringwald uint8_t segmentation_buffer[MESH_PROV_MAX_PROXY_PDU];
6077ba3d3fSMatthias Ringwald } sar_buffer;
6177ba3d3fSMatthias Ringwald
6277ba3d3fSMatthias Ringwald static const uint8_t * proxy_pdu;
6377ba3d3fSMatthias Ringwald static uint16_t proxy_pdu_size;
6477ba3d3fSMatthias Ringwald
6577ba3d3fSMatthias Ringwald static uint16_t reassembly_offset;
6677ba3d3fSMatthias Ringwald static uint16_t segmentation_offset;
6777ba3d3fSMatthias Ringwald static mesh_msg_sar_field_t segmentation_state;
6877ba3d3fSMatthias Ringwald static uint16_t pb_gatt_mtu;
6977ba3d3fSMatthias Ringwald
7077ba3d3fSMatthias Ringwald static btstack_packet_handler_t pb_gatt_packet_handler;
7177ba3d3fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
7277ba3d3fSMatthias Ringwald
pb_gatt_emit_pdu_sent(uint8_t status)7377ba3d3fSMatthias Ringwald static void pb_gatt_emit_pdu_sent(uint8_t status){
7477ba3d3fSMatthias Ringwald uint8_t event[] = {HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
7577ba3d3fSMatthias Ringwald pb_gatt_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
7677ba3d3fSMatthias Ringwald }
7777ba3d3fSMatthias Ringwald
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)7877ba3d3fSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
7977ba3d3fSMatthias Ringwald UNUSED(channel);
8077ba3d3fSMatthias Ringwald UNUSED(size);
8177ba3d3fSMatthias Ringwald mesh_msg_sar_field_t msg_sar_field;
8277ba3d3fSMatthias Ringwald mesh_msg_type_t msg_type;
832983fbcbSMatthias Ringwald uint16_t pdu_segment_len;
842983fbcbSMatthias Ringwald uint16_t pos;
8577ba3d3fSMatthias Ringwald hci_con_handle_t con_handle;
8677ba3d3fSMatthias Ringwald
8777ba3d3fSMatthias Ringwald switch (packet_type) {
8877ba3d3fSMatthias Ringwald case PROVISIONING_DATA_PACKET:
8977ba3d3fSMatthias Ringwald pos = 0;
9077ba3d3fSMatthias Ringwald // on provisioning PDU call packet handler with PROVISIONG_DATA type
917bbeb3adSMilanka Ringwald msg_sar_field = (mesh_msg_sar_field_t) (packet[pos] >> 6);
927bbeb3adSMilanka Ringwald msg_type = (mesh_msg_type_t) (packet[pos] & 0x3F);
9377ba3d3fSMatthias Ringwald pos++;
9477ba3d3fSMatthias Ringwald if (msg_type != MESH_MSG_TYPE_PROVISIONING_PDU) return;
9577ba3d3fSMatthias Ringwald if (!pb_gatt_packet_handler) return;
9677ba3d3fSMatthias Ringwald
9777ba3d3fSMatthias Ringwald pdu_segment_len = size - pos;
9877ba3d3fSMatthias Ringwald
9977ba3d3fSMatthias Ringwald if (sizeof(sar_buffer.reassembly_buffer) - reassembly_offset < pdu_segment_len) {
10077ba3d3fSMatthias Ringwald log_error("sar buffer too small left %d, new to store %d", MESH_PROV_MAX_PROXY_PDU - reassembly_offset, pdu_segment_len);
10177ba3d3fSMatthias Ringwald break;
10277ba3d3fSMatthias Ringwald }
10377ba3d3fSMatthias Ringwald
10477ba3d3fSMatthias Ringwald // update mtu if incoming packet is larger than default
10577ba3d3fSMatthias Ringwald if (size > (ATT_DEFAULT_MTU - 1)){
10677ba3d3fSMatthias Ringwald log_info("Remote uses larger MTU, enable long PDUs");
10777ba3d3fSMatthias Ringwald pb_gatt_mtu = att_server_get_mtu(channel);
10877ba3d3fSMatthias Ringwald }
10977ba3d3fSMatthias Ringwald
11077ba3d3fSMatthias Ringwald switch (msg_sar_field){
11177ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_FIRST_SEGMENT:
11277ba3d3fSMatthias Ringwald memset(sar_buffer.reassembly_buffer, 0, sizeof(sar_buffer.reassembly_buffer));
1136535961aSMatthias Ringwald (void)memcpy(sar_buffer.reassembly_buffer, packet + pos,
1146535961aSMatthias Ringwald pdu_segment_len);
11577ba3d3fSMatthias Ringwald reassembly_offset = pdu_segment_len;
11677ba3d3fSMatthias Ringwald return;
11777ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_CONTINUE:
1186535961aSMatthias Ringwald (void)memcpy(sar_buffer.reassembly_buffer + reassembly_offset,
1196535961aSMatthias Ringwald packet + pos, pdu_segment_len);
12077ba3d3fSMatthias Ringwald reassembly_offset += pdu_segment_len;
12177ba3d3fSMatthias Ringwald return;
12277ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_LAST_SEGMENT:
1236535961aSMatthias Ringwald (void)memcpy(sar_buffer.reassembly_buffer + reassembly_offset,
1246535961aSMatthias Ringwald packet + pos, pdu_segment_len);
12577ba3d3fSMatthias Ringwald reassembly_offset += pdu_segment_len;
12677ba3d3fSMatthias Ringwald // send to provisioning device
12777ba3d3fSMatthias Ringwald pb_gatt_packet_handler(PROVISIONING_DATA_PACKET, 0, sar_buffer.reassembly_buffer, reassembly_offset);
12877ba3d3fSMatthias Ringwald reassembly_offset = 0;
12977ba3d3fSMatthias Ringwald break;
13077ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_COMPLETE_MSG:
13177ba3d3fSMatthias Ringwald // send to provisioning device
13277ba3d3fSMatthias Ringwald pb_gatt_packet_handler(PROVISIONING_DATA_PACKET, 0, packet+pos, pdu_segment_len);
13377ba3d3fSMatthias Ringwald break;
1347bbeb3adSMilanka Ringwald default:
1357bbeb3adSMilanka Ringwald btstack_assert(false);
1367bbeb3adSMilanka Ringwald break;
13777ba3d3fSMatthias Ringwald }
13877ba3d3fSMatthias Ringwald break;
13977ba3d3fSMatthias Ringwald
14077ba3d3fSMatthias Ringwald case HCI_EVENT_PACKET:
1417bbeb3adSMilanka Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_MESH_META) break;
1427bbeb3adSMilanka Ringwald
14377ba3d3fSMatthias Ringwald switch (hci_event_mesh_meta_get_subevent_code(packet)){
14477ba3d3fSMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN:
14577ba3d3fSMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED:
14677ba3d3fSMatthias Ringwald // Forward link open/close
14777ba3d3fSMatthias Ringwald pb_gatt_mtu = ATT_DEFAULT_MTU;
14877ba3d3fSMatthias Ringwald pb_gatt_packet_handler(HCI_EVENT_PACKET, 0, packet, size);
14977ba3d3fSMatthias Ringwald break;
15077ba3d3fSMatthias Ringwald case MESH_SUBEVENT_CAN_SEND_NOW:
15177ba3d3fSMatthias Ringwald con_handle = little_endian_read_16(packet, 3);
15277ba3d3fSMatthias Ringwald if (con_handle == HCI_CON_HANDLE_INVALID) return;
15377ba3d3fSMatthias Ringwald
15477ba3d3fSMatthias Ringwald sar_buffer.segmentation_buffer[0] = (segmentation_state << 6) | MESH_MSG_TYPE_PROVISIONING_PDU;
15577ba3d3fSMatthias Ringwald pdu_segment_len = btstack_min(proxy_pdu_size - segmentation_offset, pb_gatt_mtu - 1);
1566535961aSMatthias Ringwald (void)memcpy(&sar_buffer.segmentation_buffer[1],
1576535961aSMatthias Ringwald &proxy_pdu[segmentation_offset],
1586535961aSMatthias Ringwald pdu_segment_len);
15977ba3d3fSMatthias Ringwald segmentation_offset += pdu_segment_len;
16077ba3d3fSMatthias Ringwald
16177ba3d3fSMatthias Ringwald mesh_provisioning_service_server_send_proxy_pdu(con_handle, sar_buffer.segmentation_buffer, pdu_segment_len + 1);
16277ba3d3fSMatthias Ringwald
16377ba3d3fSMatthias Ringwald switch (segmentation_state){
16477ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_COMPLETE_MSG:
16577ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_LAST_SEGMENT:
16677ba3d3fSMatthias Ringwald pb_gatt_emit_pdu_sent(0);
16777ba3d3fSMatthias Ringwald break;
16877ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_CONTINUE:
16977ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_FIRST_SEGMENT:
17077ba3d3fSMatthias Ringwald if ((proxy_pdu_size - segmentation_offset) > (pb_gatt_mtu - 1)){
17177ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_CONTINUE;
17277ba3d3fSMatthias Ringwald } else {
17377ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_LAST_SEGMENT;
17477ba3d3fSMatthias Ringwald }
17577ba3d3fSMatthias Ringwald mesh_provisioning_service_server_request_can_send_now(con_handle);
17677ba3d3fSMatthias Ringwald break;
1777bbeb3adSMilanka Ringwald default:
1787bbeb3adSMilanka Ringwald btstack_assert(false);
1797bbeb3adSMilanka Ringwald break;
18077ba3d3fSMatthias Ringwald }
18177ba3d3fSMatthias Ringwald break;
18277ba3d3fSMatthias Ringwald default:
18377ba3d3fSMatthias Ringwald break;
18477ba3d3fSMatthias Ringwald }
18577ba3d3fSMatthias Ringwald break;
1867bbeb3adSMilanka Ringwald
18777ba3d3fSMatthias Ringwald default:
18877ba3d3fSMatthias Ringwald break;
18977ba3d3fSMatthias Ringwald }
19077ba3d3fSMatthias Ringwald }
19177ba3d3fSMatthias Ringwald
19277ba3d3fSMatthias Ringwald /**
19377ba3d3fSMatthias Ringwald * Setup mesh provisioning service
19477ba3d3fSMatthias Ringwald * @param device_uuid
19577ba3d3fSMatthias Ringwald */
pb_gatt_init(void)19654274a76SMatthias Ringwald void pb_gatt_init(void){
19777ba3d3fSMatthias Ringwald // setup mesh provisioning service
19877ba3d3fSMatthias Ringwald mesh_provisioning_service_server_init();
19977ba3d3fSMatthias Ringwald mesh_provisioning_service_server_register_packet_handler(packet_handler);
20077ba3d3fSMatthias Ringwald }
20177ba3d3fSMatthias Ringwald
20277ba3d3fSMatthias Ringwald /**
20377ba3d3fSMatthias Ringwald * Register listener for Provisioning PDUs
20477ba3d3fSMatthias Ringwald */
pb_gatt_register_packet_handler(btstack_packet_handler_t _packet_handler)20577ba3d3fSMatthias Ringwald void pb_gatt_register_packet_handler(btstack_packet_handler_t _packet_handler){
20677ba3d3fSMatthias Ringwald pb_gatt_packet_handler = _packet_handler;
20777ba3d3fSMatthias Ringwald }
20877ba3d3fSMatthias Ringwald
20977ba3d3fSMatthias Ringwald /**
21077ba3d3fSMatthias Ringwald * Send pdu
21177ba3d3fSMatthias Ringwald * @param con_handle
21277ba3d3fSMatthias Ringwald * @param pdu
21377ba3d3fSMatthias Ringwald * @param pdu_size
21477ba3d3fSMatthias Ringwald */
pb_gatt_send_pdu(uint16_t con_handle,const uint8_t * pdu,uint16_t size)21577ba3d3fSMatthias Ringwald void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t size){
21677ba3d3fSMatthias Ringwald if (!pdu || size <= 0) return;
21777ba3d3fSMatthias Ringwald if (con_handle == HCI_CON_HANDLE_INVALID) return;
21877ba3d3fSMatthias Ringwald // store pdu, request to send
21977ba3d3fSMatthias Ringwald proxy_pdu = pdu;
22077ba3d3fSMatthias Ringwald proxy_pdu_size = size;
22177ba3d3fSMatthias Ringwald segmentation_offset = 0;
22277ba3d3fSMatthias Ringwald
22377ba3d3fSMatthias Ringwald // check if segmentation is necessary
22477ba3d3fSMatthias Ringwald if (proxy_pdu_size > (pb_gatt_mtu - 1)){
22577ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_FIRST_SEGMENT;
22677ba3d3fSMatthias Ringwald } else {
22777ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_COMPLETE_MSG;
22877ba3d3fSMatthias Ringwald }
22977ba3d3fSMatthias Ringwald mesh_provisioning_service_server_request_can_send_now(con_handle);
23077ba3d3fSMatthias Ringwald }
23177ba3d3fSMatthias Ringwald /**
23277ba3d3fSMatthias Ringwald * Close Link
23377ba3d3fSMatthias Ringwald * @param con_handle
23477ba3d3fSMatthias Ringwald * @param reason 0 = success, 1 = timeout, 2 = fail
23577ba3d3fSMatthias Ringwald */
pb_gatt_close_link(hci_con_handle_t con_handle,uint8_t reason)23677ba3d3fSMatthias Ringwald void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
2372983fbcbSMatthias Ringwald UNUSED(con_handle);
2382983fbcbSMatthias Ringwald UNUSED(reason);
23977ba3d3fSMatthias Ringwald }
24077ba3d3fSMatthias Ringwald
24177ba3d3fSMatthias Ringwald /**
24277ba3d3fSMatthias Ringwald * Setup Link with unprovisioned device
24377ba3d3fSMatthias Ringwald * @param device_uuid
2446b65794dSMilanka Ringwald * @return con_handle or HCI_CON_HANDLE_INVALID
24577ba3d3fSMatthias Ringwald */
pb_gatt_create_link(const uint8_t * device_uuid)24677ba3d3fSMatthias Ringwald uint16_t pb_gatt_create_link(const uint8_t * device_uuid){
2472983fbcbSMatthias Ringwald UNUSED(device_uuid);
24877ba3d3fSMatthias Ringwald return HCI_CON_HANDLE_INVALID;
24977ba3d3fSMatthias Ringwald }
250