13a22aa81SMatthias Ringwald /* 23a22aa81SMatthias Ringwald * Copyright (C) 2019 BlueKitchen GmbH 33a22aa81SMatthias Ringwald * 43a22aa81SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53a22aa81SMatthias Ringwald * modification, are permitted provided that the following conditions 63a22aa81SMatthias Ringwald * are met: 73a22aa81SMatthias Ringwald * 83a22aa81SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93a22aa81SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103a22aa81SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113a22aa81SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123a22aa81SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133a22aa81SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143a22aa81SMatthias Ringwald * contributors may be used to endorse or promote products derived 153a22aa81SMatthias Ringwald * from this software without specific prior written permission. 163a22aa81SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173a22aa81SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183a22aa81SMatthias Ringwald * monetary gain. 193a22aa81SMatthias Ringwald * 203a22aa81SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213a22aa81SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223a22aa81SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233a22aa81SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243a22aa81SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253a22aa81SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263a22aa81SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273a22aa81SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283a22aa81SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293a22aa81SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303a22aa81SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313a22aa81SMatthias Ringwald * SUCH DAMAGE. 323a22aa81SMatthias Ringwald * 333a22aa81SMatthias Ringwald * Please inquire about commercial licensing options at 343a22aa81SMatthias Ringwald * [email protected] 353a22aa81SMatthias Ringwald * 363a22aa81SMatthias Ringwald */ 373a22aa81SMatthias Ringwald 383a22aa81SMatthias Ringwald #define BTSTACK_FILE__ "goep_server.c" 393a22aa81SMatthias Ringwald 403a22aa81SMatthias Ringwald #include "btstack_config.h" 413a22aa81SMatthias Ringwald 423a22aa81SMatthias Ringwald #include <stdint.h> 433a22aa81SMatthias Ringwald #include <string.h> 443a22aa81SMatthias Ringwald 453a22aa81SMatthias Ringwald #include "hci_cmd.h" 463a22aa81SMatthias Ringwald #include "btstack_debug.h" 473a22aa81SMatthias Ringwald #include "btstack_defines.h" 483a22aa81SMatthias Ringwald #include "hci.h" 493a22aa81SMatthias Ringwald #include "btstack_memory.h" 503a22aa81SMatthias Ringwald #include "hci_dump.h" 513a22aa81SMatthias Ringwald #include "btstack_event.h" 523a22aa81SMatthias Ringwald 533a22aa81SMatthias Ringwald #include "classic/goep_server.h" 54c8e39cadSMatthias Ringwald #include "classic/obex.h" 555248bd90SMatthias Ringwald #include "classic/obex_message_builder.h" 563a22aa81SMatthias Ringwald 573a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 583a22aa81SMatthias Ringwald #include "l2cap.h" 593a22aa81SMatthias Ringwald 603a22aa81SMatthias Ringwald static l2cap_ertm_config_t ertm_config = { 613a22aa81SMatthias Ringwald 1, // ertm mandatory 623a22aa81SMatthias Ringwald 2, // max transmit, some tests require > 1 633a22aa81SMatthias Ringwald 2000, 643a22aa81SMatthias Ringwald 12000, 653a22aa81SMatthias Ringwald (GOEP_SERVER_ERTM_BUFFER / 2), // l2cap ertm mtu 663a22aa81SMatthias Ringwald 2, 673a22aa81SMatthias Ringwald 2, 683a22aa81SMatthias Ringwald 1, // 16-bit FCS 693a22aa81SMatthias Ringwald }; 703a22aa81SMatthias Ringwald 713a22aa81SMatthias Ringwald static uint8_t goep_server_l2cap_packet_buffer[1000]; 723a22aa81SMatthias Ringwald 733a22aa81SMatthias Ringwald #endif 743a22aa81SMatthias Ringwald 753a22aa81SMatthias Ringwald static btstack_linked_list_t goep_server_connections = NULL; 763a22aa81SMatthias Ringwald static btstack_linked_list_t goep_server_services = NULL; 773a22aa81SMatthias Ringwald static uint16_t goep_server_cid_counter = 0; 783a22aa81SMatthias Ringwald 793a22aa81SMatthias Ringwald static goep_server_service_t * goep_server_get_service_for_rfcomm_channel(uint8_t rfcomm_channel){ 803a22aa81SMatthias Ringwald btstack_linked_item_t *it; 813a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){ 823a22aa81SMatthias Ringwald goep_server_service_t * service = ((goep_server_service_t *) it); 833a22aa81SMatthias Ringwald if (service->rfcomm_channel == rfcomm_channel){ 843a22aa81SMatthias Ringwald return service; 853a22aa81SMatthias Ringwald }; 863a22aa81SMatthias Ringwald } 873a22aa81SMatthias Ringwald return NULL; 883a22aa81SMatthias Ringwald } 893a22aa81SMatthias Ringwald 9063cff0c9SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 913a22aa81SMatthias Ringwald static goep_server_service_t * goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm){ 923a22aa81SMatthias Ringwald btstack_linked_item_t *it; 933a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){ 943a22aa81SMatthias Ringwald goep_server_service_t * service = ((goep_server_service_t *) it); 953a22aa81SMatthias Ringwald if (service->l2cap_psm == l2cap_psm){ 963a22aa81SMatthias Ringwald return service; 973a22aa81SMatthias Ringwald }; 983a22aa81SMatthias Ringwald } 993a22aa81SMatthias Ringwald return NULL; 1003a22aa81SMatthias Ringwald } 10163cff0c9SMatthias Ringwald #endif 1023a22aa81SMatthias Ringwald 1033a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid){ 1043a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1053a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1063a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1073a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_RFCOMM) continue; 1083a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1093a22aa81SMatthias Ringwald return connection; 1103a22aa81SMatthias Ringwald }; 1113a22aa81SMatthias Ringwald } 1123a22aa81SMatthias Ringwald return NULL; 1133a22aa81SMatthias Ringwald } 1143a22aa81SMatthias Ringwald 11563cff0c9SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 1163a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid){ 1173a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1183a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1193a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1203a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_L2CAP) continue; 1213a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1223a22aa81SMatthias Ringwald return connection; 1233a22aa81SMatthias Ringwald }; 1243a22aa81SMatthias Ringwald } 1253a22aa81SMatthias Ringwald return NULL; 1263a22aa81SMatthias Ringwald } 12763cff0c9SMatthias Ringwald #endif 1283a22aa81SMatthias Ringwald 1293a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_goep_cid(uint16_t goep_cid){ 1303a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1313a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1323a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1333a22aa81SMatthias Ringwald if (connection->goep_cid == goep_cid){ 1343a22aa81SMatthias Ringwald return connection; 1353a22aa81SMatthias Ringwald }; 1363a22aa81SMatthias Ringwald } 1373a22aa81SMatthias Ringwald return NULL; 1383a22aa81SMatthias Ringwald } 1393a22aa81SMatthias Ringwald 1403a22aa81SMatthias Ringwald static uint16_t goep_server_get_next_goep_cid(void){ 1413a22aa81SMatthias Ringwald goep_server_cid_counter++; 1423a22aa81SMatthias Ringwald if (goep_server_cid_counter == 0){ 1433a22aa81SMatthias Ringwald goep_server_cid_counter = 1; 1443a22aa81SMatthias Ringwald } 1453a22aa81SMatthias Ringwald return goep_server_cid_counter; 1463a22aa81SMatthias Ringwald } 1473a22aa81SMatthias Ringwald 14896cdeffcSMatthias Ringwald static inline void goep_server_emit_incoming_connection(btstack_packet_handler_t callback, uint16_t goep_cid, bd_addr_t bd_addr, hci_con_handle_t con_handle){ 14996cdeffcSMatthias Ringwald uint8_t event[13]; 15096cdeffcSMatthias Ringwald uint16_t pos = 0; 15196cdeffcSMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 15296cdeffcSMatthias Ringwald event[pos++] = 15 - 2; 15396cdeffcSMatthias Ringwald event[pos++] = GOEP_SUBEVENT_INCOMING_CONNECTION; 15496cdeffcSMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 15596cdeffcSMatthias Ringwald pos+=2; 15696cdeffcSMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 15796cdeffcSMatthias Ringwald pos += 6; 15896cdeffcSMatthias Ringwald little_endian_store_16(event, pos, con_handle); 15996cdeffcSMatthias Ringwald pos += 2; 16096cdeffcSMatthias Ringwald btstack_assert(pos == sizeof(event)); 16196cdeffcSMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 16296cdeffcSMatthias Ringwald } 16396cdeffcSMatthias Ringwald 1643a22aa81SMatthias Ringwald static inline void goep_server_emit_connection_opened(btstack_packet_handler_t callback, uint16_t goep_cid, bd_addr_t bd_addr, hci_con_handle_t con_handle, uint8_t status){ 1653a22aa81SMatthias Ringwald uint8_t event[15]; 1663a22aa81SMatthias Ringwald uint16_t pos = 0; 1673a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1683a22aa81SMatthias Ringwald event[pos++] = 15 - 2; 1693a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED; 1703a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1713a22aa81SMatthias Ringwald pos+=2; 1723a22aa81SMatthias Ringwald event[pos++] = status; 1733a22aa81SMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 1743a22aa81SMatthias Ringwald pos += 6; 1753a22aa81SMatthias Ringwald little_endian_store_16(event, pos, con_handle); 1763a22aa81SMatthias Ringwald pos += 2; 1773a22aa81SMatthias Ringwald event[pos++] = 1; 1783a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1793a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1803a22aa81SMatthias Ringwald } 1813a22aa81SMatthias Ringwald 1823a22aa81SMatthias Ringwald static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){ 1833a22aa81SMatthias Ringwald uint8_t event[5]; 1843a22aa81SMatthias Ringwald uint16_t pos = 0; 1853a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1863a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1873a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED; 1883a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1893a22aa81SMatthias Ringwald pos += 2; 1903a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1913a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1923a22aa81SMatthias Ringwald } 1933a22aa81SMatthias Ringwald 1943a22aa81SMatthias Ringwald static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){ 1953a22aa81SMatthias Ringwald uint8_t event[5]; 1963a22aa81SMatthias Ringwald uint16_t pos = 0; 1973a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1983a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1993a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW; 2003a22aa81SMatthias Ringwald little_endian_store_16(event,pos,connection->goep_cid); 2013a22aa81SMatthias Ringwald pos += 2; 2023a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 2033a22aa81SMatthias Ringwald connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos); 2043a22aa81SMatthias Ringwald } 2053a22aa81SMatthias Ringwald 2063a22aa81SMatthias Ringwald static void goep_server_handle_connection_opened(goep_server_connection_t * context, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status, uint16_t bearer_cid, uint16_t bearer_mtu){ 2073a22aa81SMatthias Ringwald 2083a22aa81SMatthias Ringwald uint16_t goep_cid = context->goep_cid; 2093a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = context->callback; 2103a22aa81SMatthias Ringwald 2113a22aa81SMatthias Ringwald if (status) { 2123a22aa81SMatthias Ringwald log_info("goep_client: open failed, status %u", status); 2133a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context); 2143a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(context); 2153a22aa81SMatthias Ringwald } else { 2163a22aa81SMatthias Ringwald // context->bearer_mtu = mtu; 2173a22aa81SMatthias Ringwald context->state = GOEP_SERVER_CONNECTED; 2183a22aa81SMatthias Ringwald context->bearer_cid = bearer_cid; 2193a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2203a22aa81SMatthias Ringwald if (context->type == GOEP_CONNECTION_L2CAP){ 2213a22aa81SMatthias Ringwald bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer)); 2223a22aa81SMatthias Ringwald } 2233a22aa81SMatthias Ringwald #endif 2243a22aa81SMatthias Ringwald context->bearer_mtu = bearer_mtu; 2253a22aa81SMatthias Ringwald log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu); 2263a22aa81SMatthias Ringwald } 2273a22aa81SMatthias Ringwald 2283a22aa81SMatthias Ringwald goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status); 2293a22aa81SMatthias Ringwald } 2303a22aa81SMatthias Ringwald 2313a22aa81SMatthias Ringwald static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){ 2323a22aa81SMatthias Ringwald uint16_t goep_cid = goep_connection->goep_cid; 2333a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = goep_connection->callback; 2343a22aa81SMatthias Ringwald 2353a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 2363a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(goep_connection); 2373a22aa81SMatthias Ringwald 2383a22aa81SMatthias Ringwald goep_server_emit_connection_closed(packet_handler, goep_cid); 2393a22aa81SMatthias Ringwald } 2403a22aa81SMatthias Ringwald 2413a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2423a22aa81SMatthias Ringwald static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2433a22aa81SMatthias Ringwald UNUSED(channel); 2443a22aa81SMatthias Ringwald UNUSED(size); 2453a22aa81SMatthias Ringwald 2463a22aa81SMatthias Ringwald bd_addr_t event_addr; 2473a22aa81SMatthias Ringwald uint16_t l2cap_psm; 2483a22aa81SMatthias Ringwald uint16_t l2cap_cid; 2493a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 2503a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 2513a22aa81SMatthias Ringwald 2523a22aa81SMatthias Ringwald switch (packet_type){ 2533a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 2543a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 2553a22aa81SMatthias Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 2563a22aa81SMatthias Ringwald l2cap_psm = l2cap_event_incoming_connection_get_psm(packet); 2573a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_incoming_connection_get_local_cid(packet); 2583a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 2593a22aa81SMatthias Ringwald if (!goep_service){ 2603a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2613a22aa81SMatthias Ringwald break; 2623a22aa81SMatthias Ringwald } 2633a22aa81SMatthias Ringwald 2643a22aa81SMatthias Ringwald // alloc structure 2653a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 2663a22aa81SMatthias Ringwald if (!goep_connection){ 2673a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2683a22aa81SMatthias Ringwald break; 2693a22aa81SMatthias Ringwald } 2703a22aa81SMatthias Ringwald 2713a22aa81SMatthias Ringwald // setup connection 2723a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 2733a22aa81SMatthias Ringwald goep_connection->bearer_cid = l2cap_cid; 2743a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 2753a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_L2CAP; 27696cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 2773a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 27896cdeffcSMatthias Ringwald 27996cdeffcSMatthias Ringwald // notify user 28096cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 28196cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 28296cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_handle(packet)); 2833a22aa81SMatthias Ringwald break; 2843a22aa81SMatthias Ringwald 2853a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 2863a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet); 2873a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 2883a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 2893a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 2903a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 2913a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 2923a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_handle(packet), 2933a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_status(packet), 2943a22aa81SMatthias Ringwald l2cap_cid, 2953a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_remote_mtu(packet) ); 2963a22aa81SMatthias Ringwald return; 2973a22aa81SMatthias Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 2983a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet); 2993a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 3003a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3013a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 3023a22aa81SMatthias Ringwald break; 3033a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 3043a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet); 3053a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 3063a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3073a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3083a22aa81SMatthias Ringwald break; 3093a22aa81SMatthias Ringwald default: 3103a22aa81SMatthias Ringwald break; 3113a22aa81SMatthias Ringwald } 3123a22aa81SMatthias Ringwald break; 3133a22aa81SMatthias Ringwald case L2CAP_DATA_PACKET: 3143a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(channel); 3153a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3163a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 3173a22aa81SMatthias Ringwald break; 3183a22aa81SMatthias Ringwald default: 3193a22aa81SMatthias Ringwald break; 3203a22aa81SMatthias Ringwald } 3213a22aa81SMatthias Ringwald } 3223a22aa81SMatthias Ringwald #endif 3233a22aa81SMatthias Ringwald 3243a22aa81SMatthias Ringwald static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 3253a22aa81SMatthias Ringwald UNUSED(channel); 3263a22aa81SMatthias Ringwald UNUSED(size); 3273a22aa81SMatthias Ringwald 3283a22aa81SMatthias Ringwald bd_addr_t event_addr; 3293a22aa81SMatthias Ringwald uint8_t rfcomm_channel; 3303a22aa81SMatthias Ringwald uint16_t rfcomm_cid; 3313a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 3323a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 3333a22aa81SMatthias Ringwald 3343a22aa81SMatthias Ringwald switch (packet_type){ 3353a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 3363a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 3373a22aa81SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION: 3383a22aa81SMatthias Ringwald rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet); 3393a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); 3403a22aa81SMatthias Ringwald 3413a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 3423a22aa81SMatthias Ringwald if (!goep_service){ 3433a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3443a22aa81SMatthias Ringwald break; 3453a22aa81SMatthias Ringwald } 3463a22aa81SMatthias Ringwald 3473a22aa81SMatthias Ringwald // alloc structure 3483a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 3493a22aa81SMatthias Ringwald if (!goep_connection){ 3503a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3513a22aa81SMatthias Ringwald break; 3523a22aa81SMatthias Ringwald } 3533a22aa81SMatthias Ringwald 3543a22aa81SMatthias Ringwald // setup connection 3553a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 3563a22aa81SMatthias Ringwald goep_connection->bearer_cid = rfcomm_cid; 3573a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 3583a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_RFCOMM; 35996cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 3603a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 36196cdeffcSMatthias Ringwald 36296cdeffcSMatthias Ringwald // notify user 36396cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); 36496cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 36596cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_con_handle(packet)); 3663a22aa81SMatthias Ringwald break; 3673a22aa81SMatthias Ringwald 3683a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED: 3693a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet); 3703a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3713a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3723a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 3733a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_bd_addr(packet, event_addr); 3743a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 3753a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_con_handle(packet), 3763a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_status(packet), 3773a22aa81SMatthias Ringwald rfcomm_cid, 3783a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_max_frame_size(packet) ); 3793a22aa81SMatthias Ringwald break; 3803a22aa81SMatthias Ringwald 3813a22aa81SMatthias Ringwald case RFCOMM_EVENT_CAN_SEND_NOW: 3823a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet); 3833a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3843a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3853a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 3863a22aa81SMatthias Ringwald break; 3873a22aa81SMatthias Ringwald 3883a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED: 3893a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet); 3903a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3913a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3923a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3933a22aa81SMatthias Ringwald break; 3943a22aa81SMatthias Ringwald 3953a22aa81SMatthias Ringwald default: 3963a22aa81SMatthias Ringwald break; 3973a22aa81SMatthias Ringwald } 3983a22aa81SMatthias Ringwald break; 3993a22aa81SMatthias Ringwald 4003a22aa81SMatthias Ringwald case RFCOMM_DATA_PACKET: 4013a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(channel); 4023a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 4033a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 4043a22aa81SMatthias Ringwald break; 4053a22aa81SMatthias Ringwald 4063a22aa81SMatthias Ringwald default: 4073a22aa81SMatthias Ringwald break; 4083a22aa81SMatthias Ringwald } 4093a22aa81SMatthias Ringwald } 4103a22aa81SMatthias Ringwald 4113a22aa81SMatthias Ringwald void goep_server_init(void){ 4123a22aa81SMatthias Ringwald } 4133a22aa81SMatthias Ringwald 4143a22aa81SMatthias Ringwald uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size, 4153a22aa81SMatthias Ringwald uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){ 4163a22aa81SMatthias Ringwald 4173a22aa81SMatthias Ringwald log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u", 4183a22aa81SMatthias Ringwald rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu); 4193a22aa81SMatthias Ringwald 4203a22aa81SMatthias Ringwald // check if service is already registered 4213a22aa81SMatthias Ringwald goep_server_service_t * service; 4223a22aa81SMatthias Ringwald service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 4233a22aa81SMatthias Ringwald if (service != NULL) { 4243a22aa81SMatthias Ringwald return RFCOMM_CHANNEL_ALREADY_REGISTERED; 4253a22aa81SMatthias Ringwald } 4263a22aa81SMatthias Ringwald 4273a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4283a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4293a22aa81SMatthias Ringwald service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 4303a22aa81SMatthias Ringwald if (service != NULL) { 4313a22aa81SMatthias Ringwald return L2CAP_SERVICE_ALREADY_REGISTERED; 4323a22aa81SMatthias Ringwald } 4333a22aa81SMatthias Ringwald } 4343a22aa81SMatthias Ringwald #endif 4353a22aa81SMatthias Ringwald 4363a22aa81SMatthias Ringwald // alloc structure 4373a22aa81SMatthias Ringwald service = btstack_memory_goep_server_service_get(); 4383a22aa81SMatthias Ringwald if (service == NULL) { 4393a22aa81SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 4403a22aa81SMatthias Ringwald } 4413a22aa81SMatthias Ringwald 4423a22aa81SMatthias Ringwald // fill in 4433a22aa81SMatthias Ringwald service->callback = callback; 4443a22aa81SMatthias Ringwald service->rfcomm_channel = rfcomm_channel; 4453a22aa81SMatthias Ringwald service->l2cap_psm = l2cap_psm; 4463a22aa81SMatthias Ringwald 4473a22aa81SMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 4483a22aa81SMatthias Ringwald bool rfcomm_registered = false; 4493a22aa81SMatthias Ringwald 4503a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4513a22aa81SMatthias Ringwald bool l2cap_registered = false; 4523a22aa81SMatthias Ringwald // register with L2CAP 4533a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4543a22aa81SMatthias Ringwald status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level); 4553a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4563a22aa81SMatthias Ringwald l2cap_registered = true; 4573a22aa81SMatthias Ringwald } 4583a22aa81SMatthias Ringwald } 4593a22aa81SMatthias Ringwald #endif 4603a22aa81SMatthias Ringwald 4613a22aa81SMatthias Ringwald // register with RFCOMM 4623a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4633a22aa81SMatthias Ringwald status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size); 4643a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4653a22aa81SMatthias Ringwald rfcomm_registered = true; 4663a22aa81SMatthias Ringwald } 4673a22aa81SMatthias Ringwald } 4683a22aa81SMatthias Ringwald 4693a22aa81SMatthias Ringwald // add service on success 4703a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4713a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service); 4723a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 4733a22aa81SMatthias Ringwald } 4743a22aa81SMatthias Ringwald 4753a22aa81SMatthias Ringwald // unrestore otherwise 4763a22aa81SMatthias Ringwald btstack_memory_goep_server_service_free(service); 4773a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4783a22aa81SMatthias Ringwald if (l2cap_registered){ 4793a22aa81SMatthias Ringwald l2cap_unregister_service(l2cap_psm); 4803a22aa81SMatthias Ringwald } 4813a22aa81SMatthias Ringwald #endif 4823a22aa81SMatthias Ringwald if (rfcomm_registered){ 4833a22aa81SMatthias Ringwald rfcomm_unregister_service(rfcomm_channel); 4843a22aa81SMatthias Ringwald } 4853a22aa81SMatthias Ringwald return status; 4863a22aa81SMatthias Ringwald } 4873a22aa81SMatthias Ringwald 48896cdeffcSMatthias Ringwald uint8_t goep_server_accept_connection(uint16_t goep_cid){ 48996cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 49096cdeffcSMatthias Ringwald if (connection == NULL){ 49196cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 49296cdeffcSMatthias Ringwald } 49396cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 49496cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 49596cdeffcSMatthias Ringwald } 49696cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 49796cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 49896cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 49996cdeffcSMatthias Ringwald return l2cap_ertm_accept_connection(connection->bearer_cid, &ertm_config, connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER); 50096cdeffcSMatthias Ringwald } 50196cdeffcSMatthias Ringwald #endif 50296cdeffcSMatthias Ringwald return rfcomm_accept_connection(connection->bearer_cid); 50396cdeffcSMatthias Ringwald } 50496cdeffcSMatthias Ringwald 50596cdeffcSMatthias Ringwald uint8_t goep_server_decline_connection(uint16_t goep_cid){ 50696cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 50796cdeffcSMatthias Ringwald if (connection == NULL){ 50896cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 50996cdeffcSMatthias Ringwald } 51096cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 51196cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 51296cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 51396cdeffcSMatthias Ringwald } 51496cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 51596cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 51696cdeffcSMatthias Ringwald l2cap_decline_connection(connection->bearer_cid); 51796cdeffcSMatthias Ringwald return ERROR_CODE_SUCCESS; 51896cdeffcSMatthias Ringwald } 51996cdeffcSMatthias Ringwald #endif 52096cdeffcSMatthias Ringwald return rfcomm_decline_connection(connection->bearer_cid); 52196cdeffcSMatthias Ringwald } 52296cdeffcSMatthias Ringwald 5233a22aa81SMatthias Ringwald uint8_t goep_server_request_can_send_now(uint16_t goep_cid){ 5243a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5253a22aa81SMatthias Ringwald if (connection == NULL){ 5263a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5273a22aa81SMatthias Ringwald } 5283a22aa81SMatthias Ringwald 5290bbed0feSMatthias Ringwald btstack_assert(connection->state == GOEP_SERVER_CONNECTED); 5300bbed0feSMatthias Ringwald 5313a22aa81SMatthias Ringwald switch (connection->type){ 5323a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5333a22aa81SMatthias Ringwald rfcomm_request_can_send_now_event(connection->bearer_cid); 5343a22aa81SMatthias Ringwald break; 5353a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5363a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5373a22aa81SMatthias Ringwald l2cap_request_can_send_now_event(connection->bearer_cid); 5383a22aa81SMatthias Ringwald break; 5393a22aa81SMatthias Ringwald #endif 5403a22aa81SMatthias Ringwald default: 5413a22aa81SMatthias Ringwald btstack_unreachable(); 5423a22aa81SMatthias Ringwald break; 5433a22aa81SMatthias Ringwald } 5443a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 5453a22aa81SMatthias Ringwald } 5463a22aa81SMatthias Ringwald 5473a22aa81SMatthias Ringwald static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){ 5483a22aa81SMatthias Ringwald switch (connection->type){ 5493a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5503a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5513a22aa81SMatthias Ringwald return goep_server_l2cap_packet_buffer; 5523a22aa81SMatthias Ringwald #endif 5533a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5543a22aa81SMatthias Ringwald return rfcomm_get_outgoing_buffer(); 5553a22aa81SMatthias Ringwald default: 5563a22aa81SMatthias Ringwald btstack_unreachable(); 5573a22aa81SMatthias Ringwald return NULL; 5583a22aa81SMatthias Ringwald } 5593a22aa81SMatthias Ringwald } 5603a22aa81SMatthias Ringwald 5613a22aa81SMatthias Ringwald static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){ 5623a22aa81SMatthias Ringwald return connection->bearer_mtu; 5633a22aa81SMatthias Ringwald } 5643a22aa81SMatthias Ringwald 5653a22aa81SMatthias Ringwald static void goep_server_packet_init(goep_server_connection_t * connection){ 5660bbed0feSMatthias Ringwald btstack_assert(connection->state == GOEP_SERVER_CONNECTED); 5673a22aa81SMatthias Ringwald switch (connection->type){ 5683a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5693a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5703a22aa81SMatthias Ringwald break; 5713a22aa81SMatthias Ringwald #endif 5723a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5733a22aa81SMatthias Ringwald rfcomm_reserve_packet_buffer(); 5743a22aa81SMatthias Ringwald break; 5753a22aa81SMatthias Ringwald default: 5763a22aa81SMatthias Ringwald btstack_unreachable(); 5773a22aa81SMatthias Ringwald break; 5783a22aa81SMatthias Ringwald } 5790bbed0feSMatthias Ringwald connection->state = GOEP_SERVER_OUTGOING_BUFFER_RESERVED; 5803a22aa81SMatthias Ringwald } 5813a22aa81SMatthias Ringwald 5823a22aa81SMatthias Ringwald uint8_t goep_server_response_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){ 5833a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5843a22aa81SMatthias Ringwald if (connection == NULL) { 5853a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5863a22aa81SMatthias Ringwald } 5873a22aa81SMatthias Ringwald 5883a22aa81SMatthias Ringwald goep_server_packet_init(connection); 5893a22aa81SMatthias Ringwald 5903a22aa81SMatthias Ringwald // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU 5913a22aa81SMatthias Ringwald maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu); 5923a22aa81SMatthias Ringwald 5933a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 5943a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 5950f4783aaSMatthias Ringwald return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, (uint32_t) goep_cid); 5963a22aa81SMatthias Ringwald } 5973a22aa81SMatthias Ringwald 598c8e39cadSMatthias Ringwald uint8_t goep_server_response_create_general(uint16_t goep_cid){ 5993a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6003a22aa81SMatthias Ringwald if (connection == NULL) { 6013a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6023a22aa81SMatthias Ringwald } 6033a22aa81SMatthias Ringwald goep_server_packet_init(connection); 6043a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6053a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 606c8e39cadSMatthias Ringwald return obex_message_builder_response_create_general(buffer, buffer_len, OBEX_RESP_SUCCESS); 6073a22aa81SMatthias Ringwald } 6083a22aa81SMatthias Ringwald 609*223b1d64SMatthias Ringwald uint16_t goep_server_response_get_max_message_size(uint16_t goep_cid){ 610*223b1d64SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 611*223b1d64SMatthias Ringwald if (connection == NULL) { 612*223b1d64SMatthias Ringwald return 0; 613*223b1d64SMatthias Ringwald } 614*223b1d64SMatthias Ringwald return goep_server_get_outgoing_buffer_len(connection); 615*223b1d64SMatthias Ringwald } 616*223b1d64SMatthias Ringwald 6171a9eef62SMatthias Ringwald uint16_t goep_server_response_get_max_body_size(uint16_t goep_cid){ 6181a9eef62SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6191a9eef62SMatthias Ringwald if (connection == NULL) { 6201a9eef62SMatthias Ringwald return 0; 6211a9eef62SMatthias Ringwald } 6221a9eef62SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6231a9eef62SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6241a9eef62SMatthias Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 6251a9eef62SMatthias Ringwald return buffer_len - pos; 6261a9eef62SMatthias Ringwald } 6271a9eef62SMatthias Ringwald 6283a22aa81SMatthias Ringwald uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){ 6293a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6303a22aa81SMatthias Ringwald if (connection == NULL) { 6313a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6323a22aa81SMatthias Ringwald } 6333a22aa81SMatthias Ringwald 6343a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6353a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6363a22aa81SMatthias Ringwald return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length); 6373a22aa81SMatthias Ringwald } 6383a22aa81SMatthias Ringwald 6393a22aa81SMatthias Ringwald uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){ 6403a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6413a22aa81SMatthias Ringwald if (connection == NULL) { 6423a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6433a22aa81SMatthias Ringwald } 6443a22aa81SMatthias Ringwald 6453a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6463a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6473a22aa81SMatthias Ringwald return obex_message_builder_header_add_who(buffer, buffer_len, target); 6483a22aa81SMatthias Ringwald } 6493a22aa81SMatthias Ringwald 6503a22aa81SMatthias Ringwald uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){ 6513a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6523a22aa81SMatthias Ringwald if (connection == NULL) { 6533a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6543a22aa81SMatthias Ringwald } 6553a22aa81SMatthias Ringwald 6563a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6573a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6583a22aa81SMatthias Ringwald return obex_message_builder_header_add_srm_enable(buffer, buffer_len); 6593a22aa81SMatthias Ringwald } 6603a22aa81SMatthias Ringwald 6612a4ebdf6SMatthias Ringwald uint8_t goep_server_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){ 6622a4ebdf6SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6632a4ebdf6SMatthias Ringwald if (connection == NULL) { 6642a4ebdf6SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6652a4ebdf6SMatthias Ringwald } 6662a4ebdf6SMatthias Ringwald 6672a4ebdf6SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6682a4ebdf6SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6692a4ebdf6SMatthias Ringwald return obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length); 6702a4ebdf6SMatthias Ringwald } 6712a4ebdf6SMatthias Ringwald 672c8e39cadSMatthias Ringwald uint8_t goep_server_execute(uint16_t goep_cid, uint8_t response_code){ 6733a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6743a22aa81SMatthias Ringwald if (connection == NULL) { 6753a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6763a22aa81SMatthias Ringwald } 6773a22aa81SMatthias Ringwald 6780bbed0feSMatthias Ringwald connection->state = GOEP_SERVER_CONNECTED; 6790bbed0feSMatthias Ringwald 6803a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6810bbed0feSMatthias Ringwald // set response code 682c8e39cadSMatthias Ringwald buffer[0] = response_code; 6833a22aa81SMatthias Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 6843a22aa81SMatthias Ringwald switch (connection->type) { 6853a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 6863a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 6873a22aa81SMatthias Ringwald return l2cap_send(connection->bearer_cid, buffer, pos); 6883a22aa81SMatthias Ringwald break; 6893a22aa81SMatthias Ringwald #endif 6903a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 6913a22aa81SMatthias Ringwald return rfcomm_send_prepared(connection->bearer_cid, pos); 6923a22aa81SMatthias Ringwald break; 6933a22aa81SMatthias Ringwald default: 6943a22aa81SMatthias Ringwald btstack_unreachable(); 6953a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 6963a22aa81SMatthias Ringwald } 6973a22aa81SMatthias Ringwald } 6983a22aa81SMatthias Ringwald 6993a22aa81SMatthias Ringwald void goep_server_deinit(void){ 7003a22aa81SMatthias Ringwald goep_server_cid_counter = 0; 7013a22aa81SMatthias Ringwald goep_server_services = NULL; 7023a22aa81SMatthias Ringwald } 703