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 38*2d4000d1SMatthias 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" 46f4854a5eSMatthias Ringwald #include "ble/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 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 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 9177ba3d3fSMatthias Ringwald msg_sar_field = packet[pos] >> 6; 9277ba3d3fSMatthias Ringwald msg_type = 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)); 11377ba3d3fSMatthias Ringwald memcpy(sar_buffer.reassembly_buffer, packet+pos, pdu_segment_len); 11477ba3d3fSMatthias Ringwald reassembly_offset = pdu_segment_len; 11577ba3d3fSMatthias Ringwald return; 11677ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_CONTINUE: 11777ba3d3fSMatthias Ringwald memcpy(sar_buffer.reassembly_buffer + reassembly_offset, packet+pos, pdu_segment_len); 11877ba3d3fSMatthias Ringwald reassembly_offset += pdu_segment_len; 11977ba3d3fSMatthias Ringwald return; 12077ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_LAST_SEGMENT: 12177ba3d3fSMatthias Ringwald memcpy(sar_buffer.reassembly_buffer + reassembly_offset, packet+pos, pdu_segment_len); 12277ba3d3fSMatthias Ringwald reassembly_offset += pdu_segment_len; 12377ba3d3fSMatthias Ringwald // send to provisioning device 12477ba3d3fSMatthias Ringwald pb_gatt_packet_handler(PROVISIONING_DATA_PACKET, 0, sar_buffer.reassembly_buffer, reassembly_offset); 12577ba3d3fSMatthias Ringwald reassembly_offset = 0; 12677ba3d3fSMatthias Ringwald break; 12777ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_COMPLETE_MSG: 12877ba3d3fSMatthias Ringwald // send to provisioning device 12977ba3d3fSMatthias Ringwald pb_gatt_packet_handler(PROVISIONING_DATA_PACKET, 0, packet+pos, pdu_segment_len); 13077ba3d3fSMatthias Ringwald break; 13177ba3d3fSMatthias Ringwald } 13277ba3d3fSMatthias Ringwald break; 13377ba3d3fSMatthias Ringwald 13477ba3d3fSMatthias Ringwald case HCI_EVENT_PACKET: 13577ba3d3fSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 13677ba3d3fSMatthias Ringwald case HCI_EVENT_MESH_META: 13777ba3d3fSMatthias Ringwald switch (hci_event_mesh_meta_get_subevent_code(packet)){ 13877ba3d3fSMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN: 13977ba3d3fSMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED: 14077ba3d3fSMatthias Ringwald // Forward link open/close 14177ba3d3fSMatthias Ringwald pb_gatt_mtu = ATT_DEFAULT_MTU; 14277ba3d3fSMatthias Ringwald pb_gatt_packet_handler(HCI_EVENT_PACKET, 0, packet, size); 14377ba3d3fSMatthias Ringwald break; 14477ba3d3fSMatthias Ringwald case MESH_SUBEVENT_CAN_SEND_NOW: 14577ba3d3fSMatthias Ringwald con_handle = little_endian_read_16(packet, 3); 14677ba3d3fSMatthias Ringwald if (con_handle == HCI_CON_HANDLE_INVALID) return; 14777ba3d3fSMatthias Ringwald 14877ba3d3fSMatthias Ringwald sar_buffer.segmentation_buffer[0] = (segmentation_state << 6) | MESH_MSG_TYPE_PROVISIONING_PDU; 14977ba3d3fSMatthias Ringwald pdu_segment_len = btstack_min(proxy_pdu_size - segmentation_offset, pb_gatt_mtu - 1); 15077ba3d3fSMatthias Ringwald memcpy(&sar_buffer.segmentation_buffer[1], &proxy_pdu[segmentation_offset], pdu_segment_len); 15177ba3d3fSMatthias Ringwald segmentation_offset += pdu_segment_len; 15277ba3d3fSMatthias Ringwald 15377ba3d3fSMatthias Ringwald mesh_provisioning_service_server_send_proxy_pdu(con_handle, sar_buffer.segmentation_buffer, pdu_segment_len + 1); 15477ba3d3fSMatthias Ringwald 15577ba3d3fSMatthias Ringwald switch (segmentation_state){ 15677ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_COMPLETE_MSG: 15777ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_LAST_SEGMENT: 15877ba3d3fSMatthias Ringwald pb_gatt_emit_pdu_sent(0); 15977ba3d3fSMatthias Ringwald break; 16077ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_CONTINUE: 16177ba3d3fSMatthias Ringwald case MESH_MSG_SAR_FIELD_FIRST_SEGMENT: 16277ba3d3fSMatthias Ringwald if ((proxy_pdu_size - segmentation_offset) > (pb_gatt_mtu - 1)){ 16377ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_CONTINUE; 16477ba3d3fSMatthias Ringwald } else { 16577ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_LAST_SEGMENT; 16677ba3d3fSMatthias Ringwald } 16777ba3d3fSMatthias Ringwald mesh_provisioning_service_server_request_can_send_now(con_handle); 16877ba3d3fSMatthias Ringwald break; 16977ba3d3fSMatthias Ringwald } 17077ba3d3fSMatthias Ringwald break; 17177ba3d3fSMatthias Ringwald default: 17277ba3d3fSMatthias Ringwald break; 17377ba3d3fSMatthias Ringwald } 17477ba3d3fSMatthias Ringwald } 17577ba3d3fSMatthias Ringwald break; 17677ba3d3fSMatthias Ringwald default: 17777ba3d3fSMatthias Ringwald break; 17877ba3d3fSMatthias Ringwald } 17977ba3d3fSMatthias Ringwald } 18077ba3d3fSMatthias Ringwald 18177ba3d3fSMatthias Ringwald /** 18277ba3d3fSMatthias Ringwald * Setup mesh provisioning service 18377ba3d3fSMatthias Ringwald * @param device_uuid 18477ba3d3fSMatthias Ringwald */ 18554274a76SMatthias Ringwald void pb_gatt_init(void){ 18677ba3d3fSMatthias Ringwald // setup mesh provisioning service 18777ba3d3fSMatthias Ringwald mesh_provisioning_service_server_init(); 18877ba3d3fSMatthias Ringwald mesh_provisioning_service_server_register_packet_handler(packet_handler); 18977ba3d3fSMatthias Ringwald } 19077ba3d3fSMatthias Ringwald 19177ba3d3fSMatthias Ringwald /** 19277ba3d3fSMatthias Ringwald * Register listener for Provisioning PDUs 19377ba3d3fSMatthias Ringwald */ 19477ba3d3fSMatthias Ringwald void pb_gatt_register_packet_handler(btstack_packet_handler_t _packet_handler){ 19577ba3d3fSMatthias Ringwald pb_gatt_packet_handler = _packet_handler; 19677ba3d3fSMatthias Ringwald } 19777ba3d3fSMatthias Ringwald 19877ba3d3fSMatthias Ringwald /** 19977ba3d3fSMatthias Ringwald * Send pdu 20077ba3d3fSMatthias Ringwald * @param con_handle 20177ba3d3fSMatthias Ringwald * @param pdu 20277ba3d3fSMatthias Ringwald * @param pdu_size 20377ba3d3fSMatthias Ringwald */ 20477ba3d3fSMatthias Ringwald void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t size){ 20577ba3d3fSMatthias Ringwald if (!pdu || size <= 0) return; 20677ba3d3fSMatthias Ringwald if (con_handle == HCI_CON_HANDLE_INVALID) return; 20777ba3d3fSMatthias Ringwald // store pdu, request to send 20877ba3d3fSMatthias Ringwald proxy_pdu = pdu; 20977ba3d3fSMatthias Ringwald proxy_pdu_size = size; 21077ba3d3fSMatthias Ringwald segmentation_offset = 0; 21177ba3d3fSMatthias Ringwald 21277ba3d3fSMatthias Ringwald // check if segmentation is necessary 21377ba3d3fSMatthias Ringwald if (proxy_pdu_size > (pb_gatt_mtu - 1)){ 21477ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_FIRST_SEGMENT; 21577ba3d3fSMatthias Ringwald } else { 21677ba3d3fSMatthias Ringwald segmentation_state = MESH_MSG_SAR_FIELD_COMPLETE_MSG; 21777ba3d3fSMatthias Ringwald } 21877ba3d3fSMatthias Ringwald mesh_provisioning_service_server_request_can_send_now(con_handle); 21977ba3d3fSMatthias Ringwald } 22077ba3d3fSMatthias Ringwald /** 22177ba3d3fSMatthias Ringwald * Close Link 22277ba3d3fSMatthias Ringwald * @param con_handle 22377ba3d3fSMatthias Ringwald * @param reason 0 = success, 1 = timeout, 2 = fail 22477ba3d3fSMatthias Ringwald */ 22577ba3d3fSMatthias Ringwald void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 2262983fbcbSMatthias Ringwald UNUSED(con_handle); 2272983fbcbSMatthias Ringwald UNUSED(reason); 22877ba3d3fSMatthias Ringwald } 22977ba3d3fSMatthias Ringwald 23077ba3d3fSMatthias Ringwald /** 23177ba3d3fSMatthias Ringwald * Setup Link with unprovisioned device 23277ba3d3fSMatthias Ringwald * @param device_uuid 23377ba3d3fSMatthias Ringwald * @returns con_handle or HCI_CON_HANDLE_INVALID 23477ba3d3fSMatthias Ringwald */ 23577ba3d3fSMatthias Ringwald uint16_t pb_gatt_create_link(const uint8_t * device_uuid){ 2362983fbcbSMatthias Ringwald UNUSED(device_uuid); 23777ba3d3fSMatthias Ringwald return HCI_CON_HANDLE_INVALID; 23877ba3d3fSMatthias Ringwald } 239