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 893a22aa81SMatthias Ringwald static goep_server_service_t * goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm){ 903a22aa81SMatthias Ringwald btstack_linked_item_t *it; 913a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){ 923a22aa81SMatthias Ringwald goep_server_service_t * service = ((goep_server_service_t *) it); 933a22aa81SMatthias Ringwald if (service->l2cap_psm == l2cap_psm){ 943a22aa81SMatthias Ringwald return service; 953a22aa81SMatthias Ringwald }; 963a22aa81SMatthias Ringwald } 973a22aa81SMatthias Ringwald return NULL; 983a22aa81SMatthias Ringwald } 993a22aa81SMatthias Ringwald 1003a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid){ 1013a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1023a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1033a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1043a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_RFCOMM) continue; 1053a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1063a22aa81SMatthias Ringwald return connection; 1073a22aa81SMatthias Ringwald }; 1083a22aa81SMatthias Ringwald } 1093a22aa81SMatthias Ringwald return NULL; 1103a22aa81SMatthias Ringwald } 1113a22aa81SMatthias Ringwald 1123a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid){ 1133a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1143a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1153a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1163a22aa81SMatthias Ringwald if (connection->type != GOEP_CONNECTION_L2CAP) continue; 1173a22aa81SMatthias Ringwald if (connection->bearer_cid == bearer_cid){ 1183a22aa81SMatthias Ringwald return connection; 1193a22aa81SMatthias Ringwald }; 1203a22aa81SMatthias Ringwald } 1213a22aa81SMatthias Ringwald return NULL; 1223a22aa81SMatthias Ringwald } 1233a22aa81SMatthias Ringwald 1243a22aa81SMatthias Ringwald static goep_server_connection_t * goep_server_get_connection_for_goep_cid(uint16_t goep_cid){ 1253a22aa81SMatthias Ringwald btstack_linked_item_t *it; 1263a22aa81SMatthias Ringwald for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){ 1273a22aa81SMatthias Ringwald goep_server_connection_t * connection = ((goep_server_connection_t *) it); 1283a22aa81SMatthias Ringwald if (connection->goep_cid == goep_cid){ 1293a22aa81SMatthias Ringwald return connection; 1303a22aa81SMatthias Ringwald }; 1313a22aa81SMatthias Ringwald } 1323a22aa81SMatthias Ringwald return NULL; 1333a22aa81SMatthias Ringwald } 1343a22aa81SMatthias Ringwald 1353a22aa81SMatthias Ringwald static uint16_t goep_server_get_next_goep_cid(void){ 1363a22aa81SMatthias Ringwald goep_server_cid_counter++; 1373a22aa81SMatthias Ringwald if (goep_server_cid_counter == 0){ 1383a22aa81SMatthias Ringwald goep_server_cid_counter = 1; 1393a22aa81SMatthias Ringwald } 1403a22aa81SMatthias Ringwald return goep_server_cid_counter; 1413a22aa81SMatthias Ringwald } 1423a22aa81SMatthias Ringwald 143*96cdeffcSMatthias 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){ 144*96cdeffcSMatthias Ringwald uint8_t event[13]; 145*96cdeffcSMatthias Ringwald uint16_t pos = 0; 146*96cdeffcSMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 147*96cdeffcSMatthias Ringwald event[pos++] = 15 - 2; 148*96cdeffcSMatthias Ringwald event[pos++] = GOEP_SUBEVENT_INCOMING_CONNECTION; 149*96cdeffcSMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 150*96cdeffcSMatthias Ringwald pos+=2; 151*96cdeffcSMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 152*96cdeffcSMatthias Ringwald pos += 6; 153*96cdeffcSMatthias Ringwald little_endian_store_16(event, pos, con_handle); 154*96cdeffcSMatthias Ringwald pos += 2; 155*96cdeffcSMatthias Ringwald btstack_assert(pos == sizeof(event)); 156*96cdeffcSMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 157*96cdeffcSMatthias Ringwald } 158*96cdeffcSMatthias Ringwald 1593a22aa81SMatthias 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){ 1603a22aa81SMatthias Ringwald uint8_t event[15]; 1613a22aa81SMatthias Ringwald uint16_t pos = 0; 1623a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1633a22aa81SMatthias Ringwald event[pos++] = 15 - 2; 1643a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED; 1653a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1663a22aa81SMatthias Ringwald pos+=2; 1673a22aa81SMatthias Ringwald event[pos++] = status; 1683a22aa81SMatthias Ringwald memcpy(&event[pos], bd_addr, 6); 1693a22aa81SMatthias Ringwald pos += 6; 1703a22aa81SMatthias Ringwald little_endian_store_16(event, pos, con_handle); 1713a22aa81SMatthias Ringwald pos += 2; 1723a22aa81SMatthias Ringwald event[pos++] = 1; 1733a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1743a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1753a22aa81SMatthias Ringwald } 1763a22aa81SMatthias Ringwald 1773a22aa81SMatthias Ringwald static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){ 1783a22aa81SMatthias Ringwald uint8_t event[5]; 1793a22aa81SMatthias Ringwald uint16_t pos = 0; 1803a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1813a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1823a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED; 1833a22aa81SMatthias Ringwald little_endian_store_16(event, pos, goep_cid); 1843a22aa81SMatthias Ringwald pos += 2; 1853a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1863a22aa81SMatthias Ringwald callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos); 1873a22aa81SMatthias Ringwald } 1883a22aa81SMatthias Ringwald 1893a22aa81SMatthias Ringwald static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){ 1903a22aa81SMatthias Ringwald uint8_t event[5]; 1913a22aa81SMatthias Ringwald uint16_t pos = 0; 1923a22aa81SMatthias Ringwald event[pos++] = HCI_EVENT_GOEP_META; 1933a22aa81SMatthias Ringwald event[pos++] = 5 - 3; 1943a22aa81SMatthias Ringwald event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW; 1953a22aa81SMatthias Ringwald little_endian_store_16(event,pos,connection->goep_cid); 1963a22aa81SMatthias Ringwald pos += 2; 1973a22aa81SMatthias Ringwald btstack_assert(pos == sizeof(event)); 1983a22aa81SMatthias Ringwald connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos); 1993a22aa81SMatthias Ringwald } 2003a22aa81SMatthias Ringwald 2013a22aa81SMatthias 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){ 2023a22aa81SMatthias Ringwald 2033a22aa81SMatthias Ringwald uint16_t goep_cid = context->goep_cid; 2043a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = context->callback; 2053a22aa81SMatthias Ringwald 2063a22aa81SMatthias Ringwald if (status) { 2073a22aa81SMatthias Ringwald log_info("goep_client: open failed, status %u", status); 2083a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context); 2093a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(context); 2103a22aa81SMatthias Ringwald } else { 2113a22aa81SMatthias Ringwald // context->bearer_mtu = mtu; 2123a22aa81SMatthias Ringwald context->state = GOEP_SERVER_CONNECTED; 2133a22aa81SMatthias Ringwald context->bearer_cid = bearer_cid; 2143a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2153a22aa81SMatthias Ringwald if (context->type == GOEP_CONNECTION_L2CAP){ 2163a22aa81SMatthias Ringwald bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer)); 2173a22aa81SMatthias Ringwald } 2183a22aa81SMatthias Ringwald #endif 2193a22aa81SMatthias Ringwald context->bearer_mtu = bearer_mtu; 2203a22aa81SMatthias Ringwald log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu); 2213a22aa81SMatthias Ringwald } 2223a22aa81SMatthias Ringwald 2233a22aa81SMatthias Ringwald goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status); 2243a22aa81SMatthias Ringwald } 2253a22aa81SMatthias Ringwald 2263a22aa81SMatthias Ringwald static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){ 2273a22aa81SMatthias Ringwald uint16_t goep_cid = goep_connection->goep_cid; 2283a22aa81SMatthias Ringwald btstack_packet_handler_t packet_handler = goep_connection->callback; 2293a22aa81SMatthias Ringwald 2303a22aa81SMatthias Ringwald btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 2313a22aa81SMatthias Ringwald btstack_memory_goep_server_connection_free(goep_connection); 2323a22aa81SMatthias Ringwald 2333a22aa81SMatthias Ringwald goep_server_emit_connection_closed(packet_handler, goep_cid); 2343a22aa81SMatthias Ringwald } 2353a22aa81SMatthias Ringwald 2363a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 2373a22aa81SMatthias Ringwald static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2383a22aa81SMatthias Ringwald UNUSED(channel); 2393a22aa81SMatthias Ringwald UNUSED(size); 2403a22aa81SMatthias Ringwald 2413a22aa81SMatthias Ringwald bd_addr_t event_addr; 2423a22aa81SMatthias Ringwald uint16_t l2cap_psm; 2433a22aa81SMatthias Ringwald uint16_t l2cap_cid; 2443a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 2453a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 2463a22aa81SMatthias Ringwald 2473a22aa81SMatthias Ringwald switch (packet_type){ 2483a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 2493a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 2503a22aa81SMatthias Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 2513a22aa81SMatthias Ringwald l2cap_psm = l2cap_event_incoming_connection_get_psm(packet); 2523a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_incoming_connection_get_local_cid(packet); 2533a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 2543a22aa81SMatthias Ringwald if (!goep_service){ 2553a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2563a22aa81SMatthias Ringwald break; 2573a22aa81SMatthias Ringwald } 2583a22aa81SMatthias Ringwald 2593a22aa81SMatthias Ringwald // alloc structure 2603a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 2613a22aa81SMatthias Ringwald if (!goep_connection){ 2623a22aa81SMatthias Ringwald l2cap_decline_connection(l2cap_cid); 2633a22aa81SMatthias Ringwald break; 2643a22aa81SMatthias Ringwald } 2653a22aa81SMatthias Ringwald 2663a22aa81SMatthias Ringwald // setup connection 2673a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 2683a22aa81SMatthias Ringwald goep_connection->bearer_cid = l2cap_cid; 2693a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 2703a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_L2CAP; 271*96cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 2723a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 273*96cdeffcSMatthias Ringwald 274*96cdeffcSMatthias Ringwald // notify user 275*96cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 276*96cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 277*96cdeffcSMatthias Ringwald l2cap_event_incoming_connection_get_handle(packet)); 2783a22aa81SMatthias Ringwald break; 2793a22aa81SMatthias Ringwald 2803a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 2813a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet); 2823a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 2833a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 2843a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 2853a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 2863a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 2873a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_handle(packet), 2883a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_status(packet), 2893a22aa81SMatthias Ringwald l2cap_cid, 2903a22aa81SMatthias Ringwald l2cap_event_channel_opened_get_remote_mtu(packet) ); 2913a22aa81SMatthias Ringwald return; 2923a22aa81SMatthias Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 2933a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet); 2943a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 2953a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 2963a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 2973a22aa81SMatthias Ringwald break; 2983a22aa81SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 2993a22aa81SMatthias Ringwald l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet); 3003a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid); 3013a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3023a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3033a22aa81SMatthias Ringwald break; 3043a22aa81SMatthias Ringwald default: 3053a22aa81SMatthias Ringwald break; 3063a22aa81SMatthias Ringwald } 3073a22aa81SMatthias Ringwald break; 3083a22aa81SMatthias Ringwald case L2CAP_DATA_PACKET: 3093a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_l2cap_cid(channel); 3103a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3113a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 3123a22aa81SMatthias Ringwald break; 3133a22aa81SMatthias Ringwald default: 3143a22aa81SMatthias Ringwald break; 3153a22aa81SMatthias Ringwald } 3163a22aa81SMatthias Ringwald } 3173a22aa81SMatthias Ringwald #endif 3183a22aa81SMatthias Ringwald 3193a22aa81SMatthias Ringwald static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 3203a22aa81SMatthias Ringwald UNUSED(channel); 3213a22aa81SMatthias Ringwald UNUSED(size); 3223a22aa81SMatthias Ringwald 3233a22aa81SMatthias Ringwald bd_addr_t event_addr; 3243a22aa81SMatthias Ringwald uint8_t rfcomm_channel; 3253a22aa81SMatthias Ringwald uint16_t rfcomm_cid; 3263a22aa81SMatthias Ringwald goep_server_service_t * goep_service; 3273a22aa81SMatthias Ringwald goep_server_connection_t * goep_connection; 3283a22aa81SMatthias Ringwald 3293a22aa81SMatthias Ringwald switch (packet_type){ 3303a22aa81SMatthias Ringwald case HCI_EVENT_PACKET: 3313a22aa81SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 3323a22aa81SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION: 3333a22aa81SMatthias Ringwald rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet); 3343a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); 3353a22aa81SMatthias Ringwald 3363a22aa81SMatthias Ringwald goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 3373a22aa81SMatthias Ringwald if (!goep_service){ 3383a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3393a22aa81SMatthias Ringwald break; 3403a22aa81SMatthias Ringwald } 3413a22aa81SMatthias Ringwald 3423a22aa81SMatthias Ringwald // alloc structure 3433a22aa81SMatthias Ringwald goep_connection = btstack_memory_goep_server_connection_get(); 3443a22aa81SMatthias Ringwald if (!goep_connection){ 3453a22aa81SMatthias Ringwald rfcomm_decline_connection(rfcomm_cid); 3463a22aa81SMatthias Ringwald break; 3473a22aa81SMatthias Ringwald } 3483a22aa81SMatthias Ringwald 3493a22aa81SMatthias Ringwald // setup connection 3503a22aa81SMatthias Ringwald goep_connection->goep_cid = goep_server_get_next_goep_cid(); 3513a22aa81SMatthias Ringwald goep_connection->bearer_cid = rfcomm_cid; 3523a22aa81SMatthias Ringwald goep_connection->callback = goep_service->callback; 3533a22aa81SMatthias Ringwald goep_connection->type = GOEP_CONNECTION_RFCOMM; 354*96cdeffcSMatthias Ringwald goep_connection->state = GOEP_SERVER_W4_ACCEPT_REJECT; 3553a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection); 356*96cdeffcSMatthias Ringwald 357*96cdeffcSMatthias Ringwald // notify user 358*96cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); 359*96cdeffcSMatthias Ringwald goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr, 360*96cdeffcSMatthias Ringwald rfcomm_event_incoming_connection_get_con_handle(packet)); 3613a22aa81SMatthias Ringwald break; 3623a22aa81SMatthias Ringwald 3633a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED: 3643a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet); 3653a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3663a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3673a22aa81SMatthias Ringwald btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED); 3683a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_bd_addr(packet, event_addr); 3693a22aa81SMatthias Ringwald goep_server_handle_connection_opened(goep_connection, event_addr, 3703a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_con_handle(packet), 3713a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_status(packet), 3723a22aa81SMatthias Ringwald rfcomm_cid, 3733a22aa81SMatthias Ringwald rfcomm_event_channel_opened_get_max_frame_size(packet) ); 3743a22aa81SMatthias Ringwald break; 3753a22aa81SMatthias Ringwald 3763a22aa81SMatthias Ringwald case RFCOMM_EVENT_CAN_SEND_NOW: 3773a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet); 3783a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3793a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3803a22aa81SMatthias Ringwald goep_server_emit_can_send_now_event(goep_connection); 3813a22aa81SMatthias Ringwald break; 3823a22aa81SMatthias Ringwald 3833a22aa81SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED: 3843a22aa81SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet); 3853a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid); 3863a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3873a22aa81SMatthias Ringwald goep_server_handle_connection_closed(goep_connection); 3883a22aa81SMatthias Ringwald break; 3893a22aa81SMatthias Ringwald 3903a22aa81SMatthias Ringwald default: 3913a22aa81SMatthias Ringwald break; 3923a22aa81SMatthias Ringwald } 3933a22aa81SMatthias Ringwald break; 3943a22aa81SMatthias Ringwald 3953a22aa81SMatthias Ringwald case RFCOMM_DATA_PACKET: 3963a22aa81SMatthias Ringwald goep_connection = goep_server_get_connection_for_rfcomm_cid(channel); 3973a22aa81SMatthias Ringwald btstack_assert(goep_connection != NULL); 3983a22aa81SMatthias Ringwald goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size); 3993a22aa81SMatthias Ringwald break; 4003a22aa81SMatthias Ringwald 4013a22aa81SMatthias Ringwald default: 4023a22aa81SMatthias Ringwald break; 4033a22aa81SMatthias Ringwald } 4043a22aa81SMatthias Ringwald } 4053a22aa81SMatthias Ringwald 4063a22aa81SMatthias Ringwald void goep_server_init(void){ 4073a22aa81SMatthias Ringwald } 4083a22aa81SMatthias Ringwald 4093a22aa81SMatthias Ringwald uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size, 4103a22aa81SMatthias Ringwald uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){ 4113a22aa81SMatthias Ringwald 4123a22aa81SMatthias Ringwald log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u", 4133a22aa81SMatthias Ringwald rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu); 4143a22aa81SMatthias Ringwald 4153a22aa81SMatthias Ringwald // check if service is already registered 4163a22aa81SMatthias Ringwald goep_server_service_t * service; 4173a22aa81SMatthias Ringwald service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel); 4183a22aa81SMatthias Ringwald if (service != NULL) { 4193a22aa81SMatthias Ringwald return RFCOMM_CHANNEL_ALREADY_REGISTERED; 4203a22aa81SMatthias Ringwald } 4213a22aa81SMatthias Ringwald 4223a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4233a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4243a22aa81SMatthias Ringwald service = goep_server_get_service_for_l2cap_psm(l2cap_psm); 4253a22aa81SMatthias Ringwald if (service != NULL) { 4263a22aa81SMatthias Ringwald return L2CAP_SERVICE_ALREADY_REGISTERED; 4273a22aa81SMatthias Ringwald } 4283a22aa81SMatthias Ringwald } 4293a22aa81SMatthias Ringwald #endif 4303a22aa81SMatthias Ringwald 4313a22aa81SMatthias Ringwald // alloc structure 4323a22aa81SMatthias Ringwald service = btstack_memory_goep_server_service_get(); 4333a22aa81SMatthias Ringwald if (service == NULL) { 4343a22aa81SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 4353a22aa81SMatthias Ringwald } 4363a22aa81SMatthias Ringwald 4373a22aa81SMatthias Ringwald // fill in 4383a22aa81SMatthias Ringwald service->callback = callback; 4393a22aa81SMatthias Ringwald service->rfcomm_channel = rfcomm_channel; 4403a22aa81SMatthias Ringwald service->l2cap_psm = l2cap_psm; 4413a22aa81SMatthias Ringwald 4423a22aa81SMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 4433a22aa81SMatthias Ringwald bool rfcomm_registered = false; 4443a22aa81SMatthias Ringwald 4453a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4463a22aa81SMatthias Ringwald bool l2cap_registered = false; 4473a22aa81SMatthias Ringwald // register with L2CAP 4483a22aa81SMatthias Ringwald if (l2cap_psm != 0){ 4493a22aa81SMatthias Ringwald status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level); 4503a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4513a22aa81SMatthias Ringwald l2cap_registered = true; 4523a22aa81SMatthias Ringwald } 4533a22aa81SMatthias Ringwald } 4543a22aa81SMatthias Ringwald #endif 4553a22aa81SMatthias Ringwald 4563a22aa81SMatthias Ringwald // register with RFCOMM 4573a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4583a22aa81SMatthias Ringwald status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size); 4593a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4603a22aa81SMatthias Ringwald rfcomm_registered = true; 4613a22aa81SMatthias Ringwald } 4623a22aa81SMatthias Ringwald } 4633a22aa81SMatthias Ringwald 4643a22aa81SMatthias Ringwald // add service on success 4653a22aa81SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 4663a22aa81SMatthias Ringwald btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service); 4673a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 4683a22aa81SMatthias Ringwald } 4693a22aa81SMatthias Ringwald 4703a22aa81SMatthias Ringwald // unrestore otherwise 4713a22aa81SMatthias Ringwald btstack_memory_goep_server_service_free(service); 4723a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 4733a22aa81SMatthias Ringwald if (l2cap_registered){ 4743a22aa81SMatthias Ringwald l2cap_unregister_service(l2cap_psm); 4753a22aa81SMatthias Ringwald } 4763a22aa81SMatthias Ringwald #endif 4773a22aa81SMatthias Ringwald if (rfcomm_registered){ 4783a22aa81SMatthias Ringwald rfcomm_unregister_service(rfcomm_channel); 4793a22aa81SMatthias Ringwald } 4803a22aa81SMatthias Ringwald return status; 4813a22aa81SMatthias Ringwald } 4823a22aa81SMatthias Ringwald 483*96cdeffcSMatthias Ringwald uint8_t goep_server_accept_connection(uint16_t goep_cid){ 484*96cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 485*96cdeffcSMatthias Ringwald if (connection == NULL){ 486*96cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 487*96cdeffcSMatthias Ringwald } 488*96cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 489*96cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 490*96cdeffcSMatthias Ringwald } 491*96cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 492*96cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 493*96cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 494*96cdeffcSMatthias Ringwald return l2cap_ertm_accept_connection(connection->bearer_cid, &ertm_config, connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER); 495*96cdeffcSMatthias Ringwald } 496*96cdeffcSMatthias Ringwald #endif 497*96cdeffcSMatthias Ringwald return rfcomm_accept_connection(connection->bearer_cid); 498*96cdeffcSMatthias Ringwald } 499*96cdeffcSMatthias Ringwald 500*96cdeffcSMatthias Ringwald uint8_t goep_server_decline_connection(uint16_t goep_cid){ 501*96cdeffcSMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 502*96cdeffcSMatthias Ringwald if (connection == NULL){ 503*96cdeffcSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 504*96cdeffcSMatthias Ringwald } 505*96cdeffcSMatthias Ringwald connection->state = GOEP_SERVER_W4_CONNECTED; 506*96cdeffcSMatthias Ringwald if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){ 507*96cdeffcSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 508*96cdeffcSMatthias Ringwald } 509*96cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 510*96cdeffcSMatthias Ringwald if (connection->type == GOEP_CONNECTION_L2CAP){ 511*96cdeffcSMatthias Ringwald l2cap_decline_connection(connection->bearer_cid); 512*96cdeffcSMatthias Ringwald return ERROR_CODE_SUCCESS; 513*96cdeffcSMatthias Ringwald } 514*96cdeffcSMatthias Ringwald #endif 515*96cdeffcSMatthias Ringwald return rfcomm_decline_connection(connection->bearer_cid); 516*96cdeffcSMatthias Ringwald } 517*96cdeffcSMatthias Ringwald 5183a22aa81SMatthias Ringwald uint8_t goep_server_request_can_send_now(uint16_t goep_cid){ 5193a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5203a22aa81SMatthias Ringwald if (connection == NULL){ 5213a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5223a22aa81SMatthias Ringwald } 5233a22aa81SMatthias Ringwald 5243a22aa81SMatthias Ringwald switch (connection->type){ 5253a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5263a22aa81SMatthias Ringwald rfcomm_request_can_send_now_event(connection->bearer_cid); 5273a22aa81SMatthias Ringwald break; 5283a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5293a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5303a22aa81SMatthias Ringwald l2cap_request_can_send_now_event(connection->bearer_cid); 5313a22aa81SMatthias Ringwald break; 5323a22aa81SMatthias Ringwald #endif 5333a22aa81SMatthias Ringwald default: 5343a22aa81SMatthias Ringwald btstack_unreachable(); 5353a22aa81SMatthias Ringwald break; 5363a22aa81SMatthias Ringwald } 5373a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 5383a22aa81SMatthias Ringwald } 5393a22aa81SMatthias Ringwald 5403a22aa81SMatthias Ringwald static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){ 5413a22aa81SMatthias Ringwald switch (connection->type){ 5423a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5433a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5443a22aa81SMatthias Ringwald return goep_server_l2cap_packet_buffer; 5453a22aa81SMatthias Ringwald #endif 5463a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5473a22aa81SMatthias Ringwald return rfcomm_get_outgoing_buffer(); 5483a22aa81SMatthias Ringwald default: 5493a22aa81SMatthias Ringwald btstack_unreachable(); 5503a22aa81SMatthias Ringwald return NULL; 5513a22aa81SMatthias Ringwald } 5523a22aa81SMatthias Ringwald } 5533a22aa81SMatthias Ringwald 5543a22aa81SMatthias Ringwald static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){ 5553a22aa81SMatthias Ringwald return connection->bearer_mtu; 5563a22aa81SMatthias Ringwald } 5573a22aa81SMatthias Ringwald 5583a22aa81SMatthias Ringwald static void goep_server_packet_init(goep_server_connection_t * connection){ 5593a22aa81SMatthias Ringwald switch (connection->type){ 5603a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 5613a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 5623a22aa81SMatthias Ringwald break; 5633a22aa81SMatthias Ringwald #endif 5643a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 5653a22aa81SMatthias Ringwald rfcomm_reserve_packet_buffer(); 5663a22aa81SMatthias Ringwald break; 5673a22aa81SMatthias Ringwald default: 5683a22aa81SMatthias Ringwald btstack_unreachable(); 5693a22aa81SMatthias Ringwald break; 5703a22aa81SMatthias Ringwald } 5713a22aa81SMatthias Ringwald } 5723a22aa81SMatthias Ringwald 5733a22aa81SMatthias Ringwald uint8_t goep_server_set_connection_id(uint16_t goep_cid, uint32_t connection_id){ 5743a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 5753a22aa81SMatthias Ringwald if (connection == NULL) { 5763a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 5773a22aa81SMatthias Ringwald } 5783a22aa81SMatthias Ringwald connection->obex_connection_id = connection_id; 5793a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 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); 5953a22aa81SMatthias Ringwald return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, connection->obex_connection_id); 5963a22aa81SMatthias Ringwald } 5973a22aa81SMatthias Ringwald 5983a22aa81SMatthias Ringwald uint8_t goep_server_response_create_general(uint16_t goep_cid, uint8_t opcode){ 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); 6063a22aa81SMatthias Ringwald return obex_message_builder_response_create_general(buffer, buffer_len, opcode); 6073a22aa81SMatthias Ringwald } 6083a22aa81SMatthias Ringwald 6093a22aa81SMatthias Ringwald uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){ 6103a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6113a22aa81SMatthias Ringwald if (connection == NULL) { 6123a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6133a22aa81SMatthias Ringwald } 6143a22aa81SMatthias Ringwald 6153a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6163a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6173a22aa81SMatthias Ringwald return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length); 6183a22aa81SMatthias Ringwald } 6193a22aa81SMatthias Ringwald 6203a22aa81SMatthias Ringwald uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){ 6213a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6223a22aa81SMatthias Ringwald if (connection == NULL) { 6233a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6243a22aa81SMatthias Ringwald } 6253a22aa81SMatthias Ringwald 6263a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6273a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6283a22aa81SMatthias Ringwald return obex_message_builder_header_add_who(buffer, buffer_len, target); 6293a22aa81SMatthias Ringwald } 6303a22aa81SMatthias Ringwald 6313a22aa81SMatthias Ringwald uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){ 6323a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6333a22aa81SMatthias Ringwald if (connection == NULL) { 6343a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6353a22aa81SMatthias Ringwald } 6363a22aa81SMatthias Ringwald 6373a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6383a22aa81SMatthias Ringwald uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection); 6393a22aa81SMatthias Ringwald return obex_message_builder_header_add_srm_enable(buffer, buffer_len); 6403a22aa81SMatthias Ringwald } 6413a22aa81SMatthias Ringwald 6423a22aa81SMatthias Ringwald uint8_t goep_server_execute(uint16_t goep_cid){ 6433a22aa81SMatthias Ringwald goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid); 6443a22aa81SMatthias Ringwald if (connection == NULL) { 6453a22aa81SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 6463a22aa81SMatthias Ringwald } 6473a22aa81SMatthias Ringwald 6483a22aa81SMatthias Ringwald uint8_t * buffer = goep_server_get_outgoing_buffer(connection); 6493a22aa81SMatthias Ringwald uint16_t pos = big_endian_read_16(buffer, 1); 6503a22aa81SMatthias Ringwald switch (connection->type) { 6513a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP 6523a22aa81SMatthias Ringwald case GOEP_CONNECTION_L2CAP: 6533a22aa81SMatthias Ringwald return l2cap_send(connection->bearer_cid, buffer, pos); 6543a22aa81SMatthias Ringwald break; 6553a22aa81SMatthias Ringwald #endif 6563a22aa81SMatthias Ringwald case GOEP_CONNECTION_RFCOMM: 6573a22aa81SMatthias Ringwald return rfcomm_send_prepared(connection->bearer_cid, pos); 6583a22aa81SMatthias Ringwald break; 6593a22aa81SMatthias Ringwald default: 6603a22aa81SMatthias Ringwald btstack_unreachable(); 6613a22aa81SMatthias Ringwald return ERROR_CODE_SUCCESS; 6623a22aa81SMatthias Ringwald } 6633a22aa81SMatthias Ringwald } 6643a22aa81SMatthias Ringwald 6653a22aa81SMatthias Ringwald void goep_server_deinit(void){ 6663a22aa81SMatthias Ringwald goep_server_cid_counter = 0; 6673a22aa81SMatthias Ringwald goep_server_services = NULL; 6683a22aa81SMatthias Ringwald } 669