xref: /btstack/src/classic/goep_server.c (revision 63cff0c949f85dfa8a313daa4ff5ffc65a497067)
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