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