xref: /btstack/src/mesh/pb_gatt.c (revision 6535961a1f105e850ecdf294c128b9fc982ee05a)
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_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));
113*6535961aSMatthias Ringwald                     (void)memcpy(sar_buffer.reassembly_buffer, packet + pos,
114*6535961aSMatthias Ringwald                                  pdu_segment_len);
11577ba3d3fSMatthias Ringwald                     reassembly_offset = pdu_segment_len;
11677ba3d3fSMatthias Ringwald                     return;
11777ba3d3fSMatthias Ringwald                 case MESH_MSG_SAR_FIELD_CONTINUE:
118*6535961aSMatthias Ringwald                     (void)memcpy(sar_buffer.reassembly_buffer + reassembly_offset,
119*6535961aSMatthias 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:
123*6535961aSMatthias Ringwald                     (void)memcpy(sar_buffer.reassembly_buffer + reassembly_offset,
124*6535961aSMatthias 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;
13477ba3d3fSMatthias Ringwald             }
13577ba3d3fSMatthias Ringwald             break;
13677ba3d3fSMatthias Ringwald 
13777ba3d3fSMatthias Ringwald         case HCI_EVENT_PACKET:
13877ba3d3fSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
13977ba3d3fSMatthias Ringwald                 case HCI_EVENT_MESH_META:
14077ba3d3fSMatthias Ringwald                     switch (hci_event_mesh_meta_get_subevent_code(packet)){
14177ba3d3fSMatthias Ringwald                         case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN:
14277ba3d3fSMatthias Ringwald                         case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED:
14377ba3d3fSMatthias Ringwald                             // Forward link open/close
14477ba3d3fSMatthias Ringwald                             pb_gatt_mtu = ATT_DEFAULT_MTU;
14577ba3d3fSMatthias Ringwald                             pb_gatt_packet_handler(HCI_EVENT_PACKET, 0, packet, size);
14677ba3d3fSMatthias Ringwald                             break;
14777ba3d3fSMatthias Ringwald                         case MESH_SUBEVENT_CAN_SEND_NOW:
14877ba3d3fSMatthias Ringwald                             con_handle = little_endian_read_16(packet, 3);
14977ba3d3fSMatthias Ringwald                             if (con_handle == HCI_CON_HANDLE_INVALID) return;
15077ba3d3fSMatthias Ringwald 
15177ba3d3fSMatthias Ringwald                             sar_buffer.segmentation_buffer[0] = (segmentation_state << 6) | MESH_MSG_TYPE_PROVISIONING_PDU;
15277ba3d3fSMatthias Ringwald                             pdu_segment_len = btstack_min(proxy_pdu_size - segmentation_offset, pb_gatt_mtu - 1);
153*6535961aSMatthias Ringwald                             (void)memcpy(&sar_buffer.segmentation_buffer[1],
154*6535961aSMatthias Ringwald                                          &proxy_pdu[segmentation_offset],
155*6535961aSMatthias Ringwald                                          pdu_segment_len);
15677ba3d3fSMatthias Ringwald                             segmentation_offset += pdu_segment_len;
15777ba3d3fSMatthias Ringwald 
15877ba3d3fSMatthias Ringwald                             mesh_provisioning_service_server_send_proxy_pdu(con_handle, sar_buffer.segmentation_buffer, pdu_segment_len + 1);
15977ba3d3fSMatthias Ringwald 
16077ba3d3fSMatthias Ringwald                             switch (segmentation_state){
16177ba3d3fSMatthias Ringwald                                 case MESH_MSG_SAR_FIELD_COMPLETE_MSG:
16277ba3d3fSMatthias Ringwald                                 case MESH_MSG_SAR_FIELD_LAST_SEGMENT:
16377ba3d3fSMatthias Ringwald                                     pb_gatt_emit_pdu_sent(0);
16477ba3d3fSMatthias Ringwald                                     break;
16577ba3d3fSMatthias Ringwald                                 case MESH_MSG_SAR_FIELD_CONTINUE:
16677ba3d3fSMatthias Ringwald                                 case MESH_MSG_SAR_FIELD_FIRST_SEGMENT:
16777ba3d3fSMatthias Ringwald                                     if ((proxy_pdu_size - segmentation_offset) > (pb_gatt_mtu - 1)){
16877ba3d3fSMatthias Ringwald                                         segmentation_state = MESH_MSG_SAR_FIELD_CONTINUE;
16977ba3d3fSMatthias Ringwald                                     } else {
17077ba3d3fSMatthias Ringwald                                         segmentation_state = MESH_MSG_SAR_FIELD_LAST_SEGMENT;
17177ba3d3fSMatthias Ringwald                                     }
17277ba3d3fSMatthias Ringwald                                     mesh_provisioning_service_server_request_can_send_now(con_handle);
17377ba3d3fSMatthias Ringwald                                     break;
17477ba3d3fSMatthias Ringwald                             }
17577ba3d3fSMatthias Ringwald                             break;
17677ba3d3fSMatthias Ringwald                         default:
17777ba3d3fSMatthias Ringwald                             break;
17877ba3d3fSMatthias Ringwald                     }
17977ba3d3fSMatthias Ringwald             }
18077ba3d3fSMatthias Ringwald             break;
18177ba3d3fSMatthias Ringwald         default:
18277ba3d3fSMatthias Ringwald             break;
18377ba3d3fSMatthias Ringwald     }
18477ba3d3fSMatthias Ringwald }
18577ba3d3fSMatthias Ringwald 
18677ba3d3fSMatthias Ringwald /**
18777ba3d3fSMatthias Ringwald  * Setup mesh provisioning service
18877ba3d3fSMatthias Ringwald  * @param device_uuid
18977ba3d3fSMatthias Ringwald  */
19054274a76SMatthias Ringwald void pb_gatt_init(void){
19177ba3d3fSMatthias Ringwald     // setup mesh provisioning service
19277ba3d3fSMatthias Ringwald     mesh_provisioning_service_server_init();
19377ba3d3fSMatthias Ringwald     mesh_provisioning_service_server_register_packet_handler(packet_handler);
19477ba3d3fSMatthias Ringwald }
19577ba3d3fSMatthias Ringwald 
19677ba3d3fSMatthias Ringwald /**
19777ba3d3fSMatthias Ringwald  * Register listener for Provisioning PDUs
19877ba3d3fSMatthias Ringwald  */
19977ba3d3fSMatthias Ringwald void pb_gatt_register_packet_handler(btstack_packet_handler_t _packet_handler){
20077ba3d3fSMatthias Ringwald     pb_gatt_packet_handler = _packet_handler;
20177ba3d3fSMatthias Ringwald }
20277ba3d3fSMatthias Ringwald 
20377ba3d3fSMatthias Ringwald /**
20477ba3d3fSMatthias Ringwald  * Send pdu
20577ba3d3fSMatthias Ringwald  * @param con_handle
20677ba3d3fSMatthias Ringwald  * @param pdu
20777ba3d3fSMatthias Ringwald  * @param pdu_size
20877ba3d3fSMatthias Ringwald  */
20977ba3d3fSMatthias Ringwald void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t size){
21077ba3d3fSMatthias Ringwald     if (!pdu || size <= 0) return;
21177ba3d3fSMatthias Ringwald     if (con_handle == HCI_CON_HANDLE_INVALID) return;
21277ba3d3fSMatthias Ringwald     // store pdu, request to send
21377ba3d3fSMatthias Ringwald     proxy_pdu = pdu;
21477ba3d3fSMatthias Ringwald     proxy_pdu_size = size;
21577ba3d3fSMatthias Ringwald     segmentation_offset = 0;
21677ba3d3fSMatthias Ringwald 
21777ba3d3fSMatthias Ringwald     // check if segmentation is necessary
21877ba3d3fSMatthias Ringwald     if (proxy_pdu_size > (pb_gatt_mtu - 1)){
21977ba3d3fSMatthias Ringwald         segmentation_state = MESH_MSG_SAR_FIELD_FIRST_SEGMENT;
22077ba3d3fSMatthias Ringwald     } else {
22177ba3d3fSMatthias Ringwald         segmentation_state = MESH_MSG_SAR_FIELD_COMPLETE_MSG;
22277ba3d3fSMatthias Ringwald     }
22377ba3d3fSMatthias Ringwald     mesh_provisioning_service_server_request_can_send_now(con_handle);
22477ba3d3fSMatthias Ringwald }
22577ba3d3fSMatthias Ringwald /**
22677ba3d3fSMatthias Ringwald  * Close Link
22777ba3d3fSMatthias Ringwald  * @param con_handle
22877ba3d3fSMatthias Ringwald  * @param reason 0 = success, 1 = timeout, 2 = fail
22977ba3d3fSMatthias Ringwald  */
23077ba3d3fSMatthias Ringwald void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
2312983fbcbSMatthias Ringwald     UNUSED(con_handle);
2322983fbcbSMatthias Ringwald     UNUSED(reason);
23377ba3d3fSMatthias Ringwald }
23477ba3d3fSMatthias Ringwald 
23577ba3d3fSMatthias Ringwald /**
23677ba3d3fSMatthias Ringwald  * Setup Link with unprovisioned device
23777ba3d3fSMatthias Ringwald  * @param device_uuid
23877ba3d3fSMatthias Ringwald  * @returns con_handle or HCI_CON_HANDLE_INVALID
23977ba3d3fSMatthias Ringwald  */
24077ba3d3fSMatthias Ringwald uint16_t pb_gatt_create_link(const uint8_t * device_uuid){
2412983fbcbSMatthias Ringwald     UNUSED(device_uuid);
24277ba3d3fSMatthias Ringwald     return HCI_CON_HANDLE_INVALID;
24377ba3d3fSMatthias Ringwald }
244