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