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" 545248bd90SMatthias Ringwald #include "classic/obex_message_builder.h" 553a22aa81SMatthias Ringwald 563a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 573a22aa81SMatthias Ringwald #include "l2cap.h" 583a22aa81SMatthias Ringwald 593a22aa81SMatthias Ringwald static l2cap_ertm_config_t ertm_config = { 603a22aa81SMatthias Ringwald 1, // ertm mandatory 613a22aa81SMatthias Ringwald 2, // max transmit, some tests require > 1 623a22aa81SMatthias Ringwald 2000, 633a22aa81SMatthias Ringwald 12000, 643a22aa81SMatthias Ringwald (GOEP_SERVER_ERTM_BUFFER / 2), // l2cap ertm mtu 653a22aa81SMatthias Ringwald 2, 663a22aa81SMatthias Ringwald 2, 673a22aa81SMatthias Ringwald 1, // 16-bit FCS 683a22aa81SMatthias Ringwald }; 693a22aa81SMatthias Ringwald 703a22aa81SMatthias Ringwald static uint8_t goep_server_l2cap_packet_buffer[1000]; 713a22aa81SMatthias Ringwald 723a22aa81SMatthias Ringwald #endif 733a22aa81SMatthias Ringwald 743a22aa81SMatthias Ringwald static btstack_linked_list_t goep_server_connections = NULL; 753a22aa81SMatthias Ringwald static btstack_linked_list_t goep_server_services = NULL; 763a22aa81SMatthias Ringwald static uint16_t goep_server_cid_counter = 0; 773a22aa81SMatthias Ringwald 783a22aa81SMatthias Ringwald static goep_server_service_t * goep_server_get_service_for_rfcomm_channel(uint8_t rfcomm_channel){ 793a22aa81SMatthias Ringwald btstack_linked_item_t *it; 803a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){ 813a22aa81SMatthias Ringwald goep_server_service_t * service = ((goep_server_service_t *) it); 823a22aa81SMatthias Ringwald if (service->rfcomm_channel == rfcomm_channel){ 833a22aa81SMatthias Ringwald return service; 843a22aa81SMatthias Ringwald }; 853a22aa81SMatthias Ringwald } 863a22aa81SMatthias Ringwald return NULL; 873a22aa81SMatthias Ringwald } 883a22aa81SMatthias Ringwald 89*63cff0c9SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 903a22aa81SMatthias Ringwald static goep_server_service_t * goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm){ 913a22aa81SMatthias Ringwald btstack_linked_item_t *it; 923a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){ 933a22aa81SMatthias Ringwald goep_server_service_t * service = ((goep_server_service_t *) it); 943a22aa81SMatthias Ringwald if (service->l2cap_psm == l2cap_psm){ 953a22aa81SMatthias Ringwald return service; 963a22aa81SMatthias Ringwald }; 973a22aa81SMatthias Ringwald } 983a22aa81SMatthias Ringwald return NULL; 993a22aa81SMatthias Ringwald } 100*63cff0c9SMatthias Ringwald #endif 1013a22aa81SMatthias Ringwald 1023a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid){ 1033a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1043a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1053a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1063a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_RFCOMM) continue; 1073a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1083a22aa81SMatthias Ringwald return connection; 1093a22aa81SMatthias Ringwald }; 1103a22aa81SMatthias Ringwald } 1113a22aa81SMatthias Ringwald return NULL; 1123a22aa81SMatthias Ringwald } 1133a22aa81SMatthias Ringwald 114*63cff0c9SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 1153a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid){ 1163a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1173a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1183a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1193a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_L2CAP) continue; 1203a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1213a22aa81SMatthias Ringwald return connection; 1223a22aa81SMatthias Ringwald }; 1233a22aa81SMatthias Ringwald } 1243a22aa81SMatthias Ringwald return NULL; 1253a22aa81SMatthias Ringwald } 126*63cff0c9SMatthias Ringwald #endif 1273a22aa81SMatthias Ringwald 1283a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_goep_cid(uint16_t goep_cid){ 1293a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1303a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1313a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1323a22aa81SMatthias Ringwald if (connection->goep_cid == goep_cid){ 1333a22aa81SMatthias Ringwald return connection; 1343a22aa81SMatthias Ringwald }; 1353a22aa81SMatthias Ringwald } 1363a22aa81SMatthias Ringwald return NULL; 1373a22aa81SMatthias Ringwald } 1383a22aa81SMatthias Ringwald 1393a22aa81SMatthias Ringwald static uint16_t goep_server_get_next_goep_cid(void){ 1403a22aa81SMatthias Ringwald goep_server_cid_counter++; 1413a22aa81SMatthias Ringwald if (goep_server_cid_counter == 0){ 1423a22aa81SMatthias Ringwald goep_server_cid_counter = 1; 1433a22aa81SMatthias Ringwald } 1443a22aa81SMatthias Ringwald return goep_server_cid_counter; 1453a22aa81SMatthias Ringwald } 1463a22aa81SMatthias Ringwald 14796cdeffcSMatthias 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){ 14896cdeffcSMatthias Ringwald uint8_t event[13]; 14996cdeffcSMatthias Ringwald uint16_t pos = 0; 15096cdeffcSMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 15196cdeffcSMatthias Ringwald event[pos++] = 15 - 2; 15296cdeffcSMatthias Ringwald event[pos++] = GOEP_SUBEVENT_INCOMING_CONNECTION; 15396cdeffcSMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 15496cdeffcSMatthias Ringwald pos+=2; 15596cdeffcSMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 15696cdeffcSMatthias Ringwald pos += 6; 15796cdeffcSMatthias Ringwald little_endian_store_16(event, pos, con_handle); 15896cdeffcSMatthias Ringwald pos += 2; 15996cdeffcSMatthias Ringwald btstack_assert(pos == sizeof(event)); 16096cdeffcSMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 16196cdeffcSMatthias Ringwald } 16296cdeffcSMatthias Ringwald 1633a22aa81SMatthias 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){ 1643a22aa81SMatthias Ringwald uint8_t event[15]; 1653a22aa81SMatthias Ringwald uint16_t pos = 0; 1663a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1673a22aa81SMatthias Ringwald event[pos++] = 15 - 2; 1683a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED; 1693a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1703a22aa81SMatthias Ringwald pos+=2; 1713a22aa81SMatthias Ringwald event[pos++] = status; 1723a22aa81SMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 1733a22aa81SMatthias Ringwald pos += 6; 1743a22aa81SMatthias Ringwald little_endian_store_16(event, pos, con_handle); 1753a22aa81SMatthias Ringwald pos += 2; 1763a22aa81SMatthias Ringwald event[pos++] = 1; 1773a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1783a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1793a22aa81SMatthias Ringwald } 1803a22aa81SMatthias Ringwald 1813a22aa81SMatthias Ringwald static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){ 1823a22aa81SMatthias Ringwald uint8_t event[5]; 1833a22aa81SMatthias Ringwald uint16_t pos = 0; 1843a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1853a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1863a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED; 1873a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1883a22aa81SMatthias Ringwald pos += 2; 1893a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1903a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1913a22aa81SMatthias Ringwald } 1923a22aa81SMatthias Ringwald 1933a22aa81SMatthias Ringwald static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){ 1943a22aa81SMatthias Ringwald uint8_t event[5]; 1953a22aa81SMatthias Ringwald uint16_t pos = 0; 1963a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1973a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1983a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW; 1993a22aa81SMatthias Ringwald little_endian_store_16(event,pos,connection->goep_cid); 2003a22aa81SMatthias Ringwald pos += 2; 2013a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 2023a22aa81SMatthias Ringwald connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos); 2033a22aa81SMatthias Ringwald } 2043a22aa81SMatthias Ringwald 2053a22aa81SMatthias 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){ 2063a22aa81SMatthias Ringwald 2073a22aa81SMatthias Ringwald uint16_t goep_cid = context->goep_cid; 2083a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = context->callback; 2093a22aa81SMatthias Ringwald 2103a22aa81SMatthias Ringwald if (status) { 2113a22aa81SMatthias Ringwald log_info("goep_client: open failed, status %u", status); 2123a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context); 2133a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(context); 2143a22aa81SMatthias Ringwald } else { 2153a22aa81SMatthias Ringwald // context->bearer_mtu = mtu; 2163a22aa81SMatthias Ringwald context->state = GOEP_SERVER_CONNECTED; 2173a22aa81SMatthias Ringwald context->bearer_cid = bearer_cid; 2183a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2193a22aa81SMatthias Ringwald if (context->type == GOEP_CONNECTION_L2CAP){ 2203a22aa81SMatthias Ringwald bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer)); 2213a22aa81SMatthias Ringwald } 2223a22aa81SMatthias Ringwald #endif 2233a22aa81SMatthias Ringwald context->bearer_mtu = bearer_mtu; 2243a22aa81SMatthias Ringwald log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu); 2253a22aa81SMatthias Ringwald } 2263a22aa81SMatthias Ringwald 2273a22aa81SMatthias Ringwald goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status); 2283a22aa81SMatthias Ringwald } 2293a22aa81SMatthias Ringwald 2303a22aa81SMatthias Ringwald static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){ 2313a22aa81SMatthias Ringwald uint16_t goep_cid = goep_connection->goep_cid; 2323a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = goep_connection->callback; 2333a22aa81SMatthias Ringwald 2343a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 2353a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(goep_connection); 2363a22aa81SMatthias Ringwald 2373a22aa81SMatthias Ringwald goep_server_emit_connection_closed(packet_handler, goep_cid); 2383a22aa81SMatthias Ringwald } 2393a22aa81SMatthias Ringwald 2403a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2413a22aa81SMatthias Ringwald static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2423a22aa81SMatthias Ringwald UNUSED(channel); 2433a22aa81SMatthias Ringwald UNUSED(size); 2443a22aa81SMatthias Ringwald 2453a22aa81SMatthias Ringwald bd_addr_t event_addr; 2463a22aa81SMatthias Ringwald uint16_t l2cap_psm; 2473a22aa81SMatthias Ringwald uint16_t l2cap_cid; 2483a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 2493a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 2503a22aa81SMatthias Ringwald 2513a22aa81SMatthias Ringwald switch (packet_type){ 2523a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 2533a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 2543a22aa81SMatthias Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 2553a22aa81SMatthias Ringwald l2cap_psm = l2cap_event_incoming_connection_get_psm(packet); 2563a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_incoming_connection_get_local_cid(packet); 2573a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 2583a22aa81SMatthias Ringwald if (!goep_service){ 2593a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2603a22aa81SMatthias Ringwald break; 2613a22aa81SMatthias Ringwald } 2623a22aa81SMatthias Ringwald 2633a22aa81SMatthias Ringwald // alloc structure 2643a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 2653a22aa81SMatthias Ringwald if (!goep_connection){ 2663a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2673a22aa81SMatthias Ringwald break; 2683a22aa81SMatthias Ringwald } 2693a22aa81SMatthias Ringwald 2703a22aa81SMatthias Ringwald // setup connection 2713a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 2723a22aa81SMatthias Ringwald goep_connection->bearer_cid = l2cap_cid; 2733a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 2743a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_L2CAP; 27596cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 2763a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 27796cdeffcSMatthias Ringwald 27896cdeffcSMatthias Ringwald // notify user 27996cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 28096cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 28196cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_handle(packet)); 2823a22aa81SMatthias Ringwald break; 2833a22aa81SMatthias Ringwald 2843a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 2853a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet); 2863a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 2873a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 2883a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 2893a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 2903a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 2913a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_handle(packet), 2923a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_status(packet), 2933a22aa81SMatthias Ringwald l2cap_cid, 2943a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_remote_mtu(packet) ); 2953a22aa81SMatthias Ringwald return; 2963a22aa81SMatthias Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 2973a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet); 2983a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 2993a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3003a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 3013a22aa81SMatthias Ringwald break; 3023a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 3033a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet); 3043a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 3053a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3063a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3073a22aa81SMatthias Ringwald break; 3083a22aa81SMatthias Ringwald default: 3093a22aa81SMatthias Ringwald break; 3103a22aa81SMatthias Ringwald } 3113a22aa81SMatthias Ringwald break; 3123a22aa81SMatthias Ringwald case L2CAP_DATA_PACKET: 3133a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(channel); 3143a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3153a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 3163a22aa81SMatthias Ringwald break; 3173a22aa81SMatthias Ringwald default: 3183a22aa81SMatthias Ringwald break; 3193a22aa81SMatthias Ringwald } 3203a22aa81SMatthias Ringwald } 3213a22aa81SMatthias Ringwald #endif 3223a22aa81SMatthias Ringwald 3233a22aa81SMatthias Ringwald static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 3243a22aa81SMatthias Ringwald UNUSED(channel); 3253a22aa81SMatthias Ringwald UNUSED(size); 3263a22aa81SMatthias Ringwald 3273a22aa81SMatthias Ringwald bd_addr_t event_addr; 3283a22aa81SMatthias Ringwald uint8_t rfcomm_channel; 3293a22aa81SMatthias Ringwald uint16_t rfcomm_cid; 3303a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 3313a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 3323a22aa81SMatthias Ringwald 3333a22aa81SMatthias Ringwald switch (packet_type){ 3343a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 3353a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 3363a22aa81SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION: 3373a22aa81SMatthias Ringwald rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet); 3383a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); 3393a22aa81SMatthias Ringwald 3403a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 3413a22aa81SMatthias Ringwald if (!goep_service){ 3423a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3433a22aa81SMatthias Ringwald break; 3443a22aa81SMatthias Ringwald } 3453a22aa81SMatthias Ringwald 3463a22aa81SMatthias Ringwald // alloc structure 3473a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 3483a22aa81SMatthias Ringwald if (!goep_connection){ 3493a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3503a22aa81SMatthias Ringwald break; 3513a22aa81SMatthias Ringwald } 3523a22aa81SMatthias Ringwald 3533a22aa81SMatthias Ringwald // setup connection 3543a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 3553a22aa81SMatthias Ringwald goep_connection->bearer_cid = rfcomm_cid; 3563a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 3573a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_RFCOMM; 35896cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 3593a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 36096cdeffcSMatthias Ringwald 36196cdeffcSMatthias Ringwald // notify user 36296cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); 36396cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 36496cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_con_handle(packet)); 3653a22aa81SMatthias Ringwald break; 3663a22aa81SMatthias Ringwald 3673a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED: 3683a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet); 3693a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3703a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3713a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 3723a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_bd_addr(packet, event_addr); 3733a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 3743a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_con_handle(packet), 3753a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_status(packet), 3763a22aa81SMatthias Ringwald rfcomm_cid, 3773a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_max_frame_size(packet) ); 3783a22aa81SMatthias Ringwald break; 3793a22aa81SMatthias Ringwald 3803a22aa81SMatthias Ringwald case RFCOMM_EVENT_CAN_SEND_NOW: 3813a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet); 3823a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3833a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3843a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 3853a22aa81SMatthias Ringwald break; 3863a22aa81SMatthias Ringwald 3873a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED: 3883a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet); 3893a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3903a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3913a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3923a22aa81SMatthias Ringwald break; 3933a22aa81SMatthias Ringwald 3943a22aa81SMatthias Ringwald default: 3953a22aa81SMatthias Ringwald break; 3963a22aa81SMatthias Ringwald } 3973a22aa81SMatthias Ringwald break; 3983a22aa81SMatthias Ringwald 3993a22aa81SMatthias Ringwald case RFCOMM_DATA_PACKET: 4003a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(channel); 4013a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 4023a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 4033a22aa81SMatthias Ringwald break; 4043a22aa81SMatthias Ringwald 4053a22aa81SMatthias Ringwald default: 4063a22aa81SMatthias Ringwald break; 4073a22aa81SMatthias Ringwald } 4083a22aa81SMatthias Ringwald } 4093a22aa81SMatthias Ringwald 4103a22aa81SMatthias Ringwald void goep_server_init(void){ 4113a22aa81SMatthias Ringwald } 4123a22aa81SMatthias Ringwald 4133a22aa81SMatthias Ringwald uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size, 4143a22aa81SMatthias Ringwald uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){ 4153a22aa81SMatthias Ringwald 4163a22aa81SMatthias Ringwald log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u", 4173a22aa81SMatthias Ringwald rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu); 4183a22aa81SMatthias Ringwald 4193a22aa81SMatthias Ringwald // check if service is already registered 4203a22aa81SMatthias Ringwald goep_server_service_t * service; 4213a22aa81SMatthias Ringwald service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 4223a22aa81SMatthias Ringwald if (service != NULL) { 4233a22aa81SMatthias Ringwald return RFCOMM_CHANNEL_ALREADY_REGISTERED; 4243a22aa81SMatthias Ringwald } 4253a22aa81SMatthias Ringwald 4263a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4273a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4283a22aa81SMatthias Ringwald service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 4293a22aa81SMatthias Ringwald if (service != NULL) { 4303a22aa81SMatthias Ringwald return L2CAP_SERVICE_ALREADY_REGISTERED; 4313a22aa81SMatthias Ringwald } 4323a22aa81SMatthias Ringwald } 4333a22aa81SMatthias Ringwald #endif 4343a22aa81SMatthias Ringwald 4353a22aa81SMatthias Ringwald // alloc structure 4363a22aa81SMatthias Ringwald service = btstack_memory_goep_server_service_get(); 4373a22aa81SMatthias Ringwald if (service == NULL) { 4383a22aa81SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 4393a22aa81SMatthias Ringwald } 4403a22aa81SMatthias Ringwald 4413a22aa81SMatthias Ringwald // fill in 4423a22aa81SMatthias Ringwald service->callback = callback; 4433a22aa81SMatthias Ringwald service->rfcomm_channel = rfcomm_channel; 4443a22aa81SMatthias Ringwald service->l2cap_psm = l2cap_psm; 4453a22aa81SMatthias Ringwald 4463a22aa81SMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 4473a22aa81SMatthias Ringwald bool rfcomm_registered = false; 4483a22aa81SMatthias Ringwald 4493a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4503a22aa81SMatthias Ringwald bool l2cap_registered = false; 4513a22aa81SMatthias Ringwald // register with L2CAP 4523a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4533a22aa81SMatthias Ringwald status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level); 4543a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4553a22aa81SMatthias Ringwald l2cap_registered = true; 4563a22aa81SMatthias Ringwald } 4573a22aa81SMatthias Ringwald } 4583a22aa81SMatthias Ringwald #endif 4593a22aa81SMatthias Ringwald 4603a22aa81SMatthias Ringwald // register with RFCOMM 4613a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4623a22aa81SMatthias Ringwald status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size); 4633a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4643a22aa81SMatthias Ringwald rfcomm_registered = true; 4653a22aa81SMatthias Ringwald } 4663a22aa81SMatthias Ringwald } 4673a22aa81SMatthias Ringwald 4683a22aa81SMatthias Ringwald // add service on success 4693a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4703a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service); 4713a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 4723a22aa81SMatthias Ringwald } 4733a22aa81SMatthias Ringwald 4743a22aa81SMatthias Ringwald // unrestore otherwise 4753a22aa81SMatthias Ringwald btstack_memory_goep_server_service_free(service); 4763a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4773a22aa81SMatthias Ringwald if (l2cap_registered){ 4783a22aa81SMatthias Ringwald l2cap_unregister_service(l2cap_psm); 4793a22aa81SMatthias Ringwald } 4803a22aa81SMatthias Ringwald #endif 4813a22aa81SMatthias Ringwald if (rfcomm_registered){ 4823a22aa81SMatthias Ringwald rfcomm_unregister_service(rfcomm_channel); 4833a22aa81SMatthias Ringwald } 4843a22aa81SMatthias Ringwald return status; 4853a22aa81SMatthias Ringwald } 4863a22aa81SMatthias Ringwald 48796cdeffcSMatthias Ringwald uint8_t goep_server_accept_connection(uint16_t goep_cid){ 48896cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 48996cdeffcSMatthias Ringwald if (connection == NULL){ 49096cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 49196cdeffcSMatthias Ringwald } 49296cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 49396cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 49496cdeffcSMatthias Ringwald } 49596cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 49696cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 49796cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 49896cdeffcSMatthias Ringwald return l2cap_ertm_accept_connection(connection->bearer_cid, &ertm_config, connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER); 49996cdeffcSMatthias Ringwald } 50096cdeffcSMatthias Ringwald #endif 50196cdeffcSMatthias Ringwald return rfcomm_accept_connection(connection->bearer_cid); 50296cdeffcSMatthias Ringwald } 50396cdeffcSMatthias Ringwald 50496cdeffcSMatthias Ringwald uint8_t goep_server_decline_connection(uint16_t goep_cid){ 50596cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 50696cdeffcSMatthias Ringwald if (connection == NULL){ 50796cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 50896cdeffcSMatthias Ringwald } 50996cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 51096cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 51196cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 51296cdeffcSMatthias Ringwald } 51396cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 51496cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 51596cdeffcSMatthias Ringwald l2cap_decline_connection(connection->bearer_cid); 51696cdeffcSMatthias Ringwald return ERROR_CODE_SUCCESS; 51796cdeffcSMatthias Ringwald } 51896cdeffcSMatthias Ringwald #endif 51996cdeffcSMatthias Ringwald return rfcomm_decline_connection(connection->bearer_cid); 52096cdeffcSMatthias Ringwald } 52196cdeffcSMatthias Ringwald 5223a22aa81SMatthias Ringwald uint8_t goep_server_request_can_send_now(uint16_t goep_cid){ 5233a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5243a22aa81SMatthias Ringwald if (connection == NULL){ 5253a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5263a22aa81SMatthias Ringwald } 5273a22aa81SMatthias Ringwald 5283a22aa81SMatthias Ringwald switch (connection->type){ 5293a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5303a22aa81SMatthias Ringwald rfcomm_request_can_send_now_event(connection->bearer_cid); 5313a22aa81SMatthias Ringwald break; 5323a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5333a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5343a22aa81SMatthias Ringwald l2cap_request_can_send_now_event(connection->bearer_cid); 5353a22aa81SMatthias Ringwald break; 5363a22aa81SMatthias Ringwald #endif 5373a22aa81SMatthias Ringwald default: 5383a22aa81SMatthias Ringwald btstack_unreachable(); 5393a22aa81SMatthias Ringwald break; 5403a22aa81SMatthias Ringwald } 5413a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 5423a22aa81SMatthias Ringwald } 5433a22aa81SMatthias Ringwald 5443a22aa81SMatthias Ringwald static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){ 5453a22aa81SMatthias Ringwald switch (connection->type){ 5463a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5473a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5483a22aa81SMatthias Ringwald return goep_server_l2cap_packet_buffer; 5493a22aa81SMatthias Ringwald #endif 5503a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5513a22aa81SMatthias Ringwald return rfcomm_get_outgoing_buffer(); 5523a22aa81SMatthias Ringwald default: 5533a22aa81SMatthias Ringwald btstack_unreachable(); 5543a22aa81SMatthias Ringwald return NULL; 5553a22aa81SMatthias Ringwald } 5563a22aa81SMatthias Ringwald } 5573a22aa81SMatthias Ringwald 5583a22aa81SMatthias Ringwald static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){ 5593a22aa81SMatthias Ringwald return connection->bearer_mtu; 5603a22aa81SMatthias Ringwald } 5613a22aa81SMatthias Ringwald 5623a22aa81SMatthias Ringwald static void goep_server_packet_init(goep_server_connection_t * connection){ 5633a22aa81SMatthias Ringwald switch (connection->type){ 5643a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5653a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5663a22aa81SMatthias Ringwald break; 5673a22aa81SMatthias Ringwald #endif 5683a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5693a22aa81SMatthias Ringwald rfcomm_reserve_packet_buffer(); 5703a22aa81SMatthias Ringwald break; 5713a22aa81SMatthias Ringwald default: 5723a22aa81SMatthias Ringwald btstack_unreachable(); 5733a22aa81SMatthias Ringwald break; 5743a22aa81SMatthias Ringwald } 5753a22aa81SMatthias Ringwald } 5763a22aa81SMatthias Ringwald 5773a22aa81SMatthias 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){ 5783a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5793a22aa81SMatthias Ringwald if (connection == NULL) { 5803a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5813a22aa81SMatthias Ringwald } 5823a22aa81SMatthias Ringwald 5833a22aa81SMatthias Ringwald goep_server_packet_init(connection); 5843a22aa81SMatthias Ringwald 5853a22aa81SMatthias Ringwald // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU 5863a22aa81SMatthias Ringwald maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu); 5873a22aa81SMatthias Ringwald 5883a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 5893a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 5900f4783aaSMatthias Ringwald return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, (uint32_t) goep_cid); 5913a22aa81SMatthias Ringwald } 5923a22aa81SMatthias Ringwald 5933a22aa81SMatthias Ringwald uint8_t goep_server_response_create_general(uint16_t goep_cid, uint8_t opcode){ 5943a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5953a22aa81SMatthias Ringwald if (connection == NULL) { 5963a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5973a22aa81SMatthias Ringwald } 5983a22aa81SMatthias Ringwald goep_server_packet_init(connection); 5993a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6003a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6013a22aa81SMatthias Ringwald return obex_message_builder_response_create_general(buffer, buffer_len, opcode); 6023a22aa81SMatthias Ringwald } 6033a22aa81SMatthias Ringwald 6043a22aa81SMatthias Ringwald uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){ 6053a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6063a22aa81SMatthias Ringwald if (connection == NULL) { 6073a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6083a22aa81SMatthias Ringwald } 6093a22aa81SMatthias Ringwald 6103a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6113a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6123a22aa81SMatthias Ringwald return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length); 6133a22aa81SMatthias Ringwald } 6143a22aa81SMatthias Ringwald 6153a22aa81SMatthias Ringwald uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){ 6163a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6173a22aa81SMatthias Ringwald if (connection == NULL) { 6183a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6193a22aa81SMatthias Ringwald } 6203a22aa81SMatthias Ringwald 6213a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6223a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6233a22aa81SMatthias Ringwald return obex_message_builder_header_add_who(buffer, buffer_len, target); 6243a22aa81SMatthias Ringwald } 6253a22aa81SMatthias Ringwald 6263a22aa81SMatthias Ringwald uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){ 6273a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6283a22aa81SMatthias Ringwald if (connection == NULL) { 6293a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6303a22aa81SMatthias Ringwald } 6313a22aa81SMatthias Ringwald 6323a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6333a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6343a22aa81SMatthias Ringwald return obex_message_builder_header_add_srm_enable(buffer, buffer_len); 6353a22aa81SMatthias Ringwald } 6363a22aa81SMatthias Ringwald 6373a22aa81SMatthias Ringwald uint8_t goep_server_execute(uint16_t goep_cid){ 6383a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6393a22aa81SMatthias Ringwald if (connection == NULL) { 6403a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6413a22aa81SMatthias Ringwald } 6423a22aa81SMatthias Ringwald 6433a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6443a22aa81SMatthias Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 6453a22aa81SMatthias Ringwald switch (connection->type) { 6463a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 6473a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 6483a22aa81SMatthias Ringwald return l2cap_send(connection->bearer_cid, buffer, pos); 6493a22aa81SMatthias Ringwald break; 6503a22aa81SMatthias Ringwald #endif 6513a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 6523a22aa81SMatthias Ringwald return rfcomm_send_prepared(connection->bearer_cid, pos); 6533a22aa81SMatthias Ringwald break; 6543a22aa81SMatthias Ringwald default: 6553a22aa81SMatthias Ringwald btstack_unreachable(); 6563a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 6573a22aa81SMatthias Ringwald } 6583a22aa81SMatthias Ringwald } 6593a22aa81SMatthias Ringwald 6603a22aa81SMatthias Ringwald void goep_server_deinit(void){ 6613a22aa81SMatthias Ringwald goep_server_cid_counter = 0; 6623a22aa81SMatthias Ringwald goep_server_services = NULL; 6633a22aa81SMatthias Ringwald } 664