xref: /btstack/src/mesh/pb_gatt.c (revision 2d4000d1850724e5e3baecd65f36d42e5d35f76f)
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