xref: /btstack/src/classic/goep_server.c (revision 335549393173250c8cced9c08514d60b1955350b)
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
6603ebb521SMatthias Ringwald     4,
6703ebb521SMatthias Ringwald     4,
683a22aa81SMatthias Ringwald     1,      // 16-bit FCS
693a22aa81SMatthias Ringwald };
703a22aa81SMatthias Ringwald 
7103ebb521SMatthias Ringwald static uint8_t goep_server_l2cap_packet_buffer[GOEP_SERVER_ERTM_BUFFER];
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 
goep_server_get_service_for_rfcomm_channel(uint8_t rfcomm_channel)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
goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm)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 
goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid)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
goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid)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 
goep_server_get_connection_for_goep_cid(uint16_t goep_cid)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 
goep_server_get_next_goep_cid(void)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 
goep_server_emit_incoming_connection(btstack_packet_handler_t callback,uint16_t goep_cid,bd_addr_t bd_addr,hci_con_handle_t con_handle)14896cdeffcSMatthias Ringwald 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;
156ba8264daSMatthias Ringwald     reverse_bd_addr(bd_addr, &event[pos]);
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 
goep_server_emit_connection_opened(btstack_packet_handler_t callback,uint16_t goep_cid,bd_addr_t bd_addr,hci_con_handle_t con_handle,uint8_t status)1643a22aa81SMatthias Ringwald 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;
173ba8264daSMatthias Ringwald     reverse_bd_addr(bd_addr, &event[pos]);
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 
goep_server_emit_connection_closed(btstack_packet_handler_t callback,uint16_t goep_cid)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 
goep_server_emit_can_send_now_event(goep_server_connection_t * connection)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 
goep_server_handle_connection_opened(goep_server_connection_t * context,bd_addr_t addr,hci_con_handle_t con_handle,uint8_t status,uint16_t bearer_cid,uint16_t bearer_mtu)2063a22aa81SMatthias Ringwald 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 
goep_server_handle_connection_closed(goep_server_connection_t * goep_connection)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
goep_server_packet_handler_l2cap(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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 
goep_server_packet_handler_rfcomm(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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 
goep_server_init(void)4113a22aa81SMatthias Ringwald void goep_server_init(void){
4123a22aa81SMatthias Ringwald }
4133a22aa81SMatthias Ringwald 
goep_server_register_service(btstack_packet_handler_t callback,uint8_t rfcomm_channel,uint16_t rfcomm_max_frame_size,uint16_t l2cap_psm,uint16_t l2cap_mtu,gap_security_level_t security_level)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     }
43403ebb521SMatthias Ringwald #else
43503ebb521SMatthias Ringwald     UNUSED(l2cap_mtu);
43603ebb521SMatthias Ringwald     UNUSED(l2cap_psm);
43703ebb521SMatthias Ringwald     UNUSED(security_level);
4383a22aa81SMatthias Ringwald #endif
4393a22aa81SMatthias Ringwald 
4403a22aa81SMatthias Ringwald     // alloc structure
4413a22aa81SMatthias Ringwald     service = btstack_memory_goep_server_service_get();
4423a22aa81SMatthias Ringwald     if (service == NULL) {
4433a22aa81SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
4443a22aa81SMatthias Ringwald     }
4453a22aa81SMatthias Ringwald 
4463a22aa81SMatthias Ringwald     // fill in
4473a22aa81SMatthias Ringwald     service->callback = callback;
4483a22aa81SMatthias Ringwald     service->rfcomm_channel = rfcomm_channel;
4493a22aa81SMatthias Ringwald     service->l2cap_psm = l2cap_psm;
4503a22aa81SMatthias Ringwald 
4513a22aa81SMatthias Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
4523a22aa81SMatthias Ringwald     bool rfcomm_registered = false;
4533a22aa81SMatthias Ringwald 
4543a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
4553a22aa81SMatthias Ringwald     bool l2cap_registered = false;
4563a22aa81SMatthias Ringwald     // register with L2CAP
4573a22aa81SMatthias Ringwald     if (l2cap_psm != 0){
4583a22aa81SMatthias Ringwald         status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level);
4593a22aa81SMatthias Ringwald         if (status == ERROR_CODE_SUCCESS){
4603a22aa81SMatthias Ringwald             l2cap_registered = true;
4613a22aa81SMatthias Ringwald         }
4623a22aa81SMatthias Ringwald     }
4633a22aa81SMatthias Ringwald #endif
4643a22aa81SMatthias Ringwald 
4653a22aa81SMatthias Ringwald     // register with RFCOMM
4663a22aa81SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
4673a22aa81SMatthias Ringwald         status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size);
4683a22aa81SMatthias Ringwald         if (status == ERROR_CODE_SUCCESS){
4693a22aa81SMatthias Ringwald             rfcomm_registered = true;
4703a22aa81SMatthias Ringwald         }
4713a22aa81SMatthias Ringwald     }
4723a22aa81SMatthias Ringwald 
4733a22aa81SMatthias Ringwald     // add service on success
4743a22aa81SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
4753a22aa81SMatthias Ringwald         btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service);
4763a22aa81SMatthias Ringwald         return ERROR_CODE_SUCCESS;
4773a22aa81SMatthias Ringwald     }
4783a22aa81SMatthias Ringwald 
4793a22aa81SMatthias Ringwald     // unrestore otherwise
4803a22aa81SMatthias Ringwald     btstack_memory_goep_server_service_free(service);
4813a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
4823a22aa81SMatthias Ringwald     if (l2cap_registered){
4833a22aa81SMatthias Ringwald         l2cap_unregister_service(l2cap_psm);
4843a22aa81SMatthias Ringwald     }
4853a22aa81SMatthias Ringwald #endif
4863a22aa81SMatthias Ringwald     if (rfcomm_registered){
4873a22aa81SMatthias Ringwald         rfcomm_unregister_service(rfcomm_channel);
4883a22aa81SMatthias Ringwald     }
4893a22aa81SMatthias Ringwald     return status;
4903a22aa81SMatthias Ringwald }
4913a22aa81SMatthias Ringwald 
goep_server_accept_connection(uint16_t goep_cid)49296cdeffcSMatthias Ringwald uint8_t goep_server_accept_connection(uint16_t goep_cid){
49396cdeffcSMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
49496cdeffcSMatthias Ringwald     if (connection == NULL){
49596cdeffcSMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
49696cdeffcSMatthias Ringwald     }
49796cdeffcSMatthias Ringwald     if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){
49896cdeffcSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
49996cdeffcSMatthias Ringwald     }
50096cdeffcSMatthias Ringwald     connection->state = GOEP_SERVER_W4_CONNECTED;
50196cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
50296cdeffcSMatthias Ringwald     if (connection->type == GOEP_CONNECTION_L2CAP){
50396cdeffcSMatthias Ringwald         return l2cap_ertm_accept_connection(connection->bearer_cid, &ertm_config, connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER);
50496cdeffcSMatthias Ringwald     }
50596cdeffcSMatthias Ringwald #endif
50696cdeffcSMatthias Ringwald     return rfcomm_accept_connection(connection->bearer_cid);
50796cdeffcSMatthias Ringwald }
50896cdeffcSMatthias Ringwald 
goep_server_decline_connection(uint16_t goep_cid)50996cdeffcSMatthias Ringwald uint8_t goep_server_decline_connection(uint16_t goep_cid){
51096cdeffcSMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
51196cdeffcSMatthias Ringwald     if (connection == NULL){
51296cdeffcSMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
51396cdeffcSMatthias Ringwald     }
51496cdeffcSMatthias Ringwald     connection->state = GOEP_SERVER_W4_CONNECTED;
51596cdeffcSMatthias Ringwald     if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){
51696cdeffcSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
51796cdeffcSMatthias Ringwald     }
51896cdeffcSMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
51996cdeffcSMatthias Ringwald     if (connection->type == GOEP_CONNECTION_L2CAP){
52096cdeffcSMatthias Ringwald         l2cap_decline_connection(connection->bearer_cid);
52196cdeffcSMatthias Ringwald         return ERROR_CODE_SUCCESS;
52296cdeffcSMatthias Ringwald     }
52396cdeffcSMatthias Ringwald #endif
52496cdeffcSMatthias Ringwald     return rfcomm_decline_connection(connection->bearer_cid);
52596cdeffcSMatthias Ringwald }
52696cdeffcSMatthias Ringwald 
goep_server_request_can_send_now(uint16_t goep_cid)5273a22aa81SMatthias Ringwald uint8_t goep_server_request_can_send_now(uint16_t goep_cid){
5283a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
5293a22aa81SMatthias Ringwald     if (connection == NULL){
5303a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
5313a22aa81SMatthias Ringwald     }
5323a22aa81SMatthias Ringwald 
5330bbed0feSMatthias Ringwald     btstack_assert(connection->state == GOEP_SERVER_CONNECTED);
5340bbed0feSMatthias Ringwald 
5353a22aa81SMatthias Ringwald     switch (connection->type){
5363a22aa81SMatthias Ringwald         case GOEP_CONNECTION_RFCOMM:
5373a22aa81SMatthias Ringwald             rfcomm_request_can_send_now_event(connection->bearer_cid);
5383a22aa81SMatthias Ringwald             break;
5393a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
5403a22aa81SMatthias Ringwald         case GOEP_CONNECTION_L2CAP:
5413a22aa81SMatthias Ringwald             l2cap_request_can_send_now_event(connection->bearer_cid);
5423a22aa81SMatthias Ringwald             break;
5433a22aa81SMatthias Ringwald #endif
5443a22aa81SMatthias Ringwald         default:
5453a22aa81SMatthias Ringwald             btstack_unreachable();
5463a22aa81SMatthias Ringwald             break;
5473a22aa81SMatthias Ringwald     }
5483a22aa81SMatthias Ringwald     return ERROR_CODE_SUCCESS;
5493a22aa81SMatthias Ringwald }
5503a22aa81SMatthias Ringwald 
goep_server_get_outgoing_buffer(goep_server_connection_t * connection)5513a22aa81SMatthias Ringwald static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){
5523a22aa81SMatthias Ringwald     switch (connection->type){
5533a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
5543a22aa81SMatthias Ringwald         case GOEP_CONNECTION_L2CAP:
5553a22aa81SMatthias Ringwald             return goep_server_l2cap_packet_buffer;
5563a22aa81SMatthias Ringwald #endif
5573a22aa81SMatthias Ringwald         case GOEP_CONNECTION_RFCOMM:
5583a22aa81SMatthias Ringwald             return rfcomm_get_outgoing_buffer();
5593a22aa81SMatthias Ringwald         default:
5603a22aa81SMatthias Ringwald             btstack_unreachable();
5613a22aa81SMatthias Ringwald             return NULL;
5623a22aa81SMatthias Ringwald     }
5633a22aa81SMatthias Ringwald }
5643a22aa81SMatthias Ringwald 
goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection)5653a22aa81SMatthias Ringwald static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){
5663a22aa81SMatthias Ringwald     return connection->bearer_mtu;
5673a22aa81SMatthias Ringwald }
5683a22aa81SMatthias Ringwald 
goep_server_packet_init(goep_server_connection_t * connection)5693a22aa81SMatthias Ringwald static void goep_server_packet_init(goep_server_connection_t * connection){
5700bbed0feSMatthias Ringwald     btstack_assert(connection->state == GOEP_SERVER_CONNECTED);
5713a22aa81SMatthias Ringwald     switch (connection->type){
5723a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
5733a22aa81SMatthias Ringwald         case GOEP_CONNECTION_L2CAP:
5743a22aa81SMatthias Ringwald             break;
5753a22aa81SMatthias Ringwald #endif
5763a22aa81SMatthias Ringwald         case GOEP_CONNECTION_RFCOMM:
5773a22aa81SMatthias Ringwald             rfcomm_reserve_packet_buffer();
5783a22aa81SMatthias Ringwald             break;
5793a22aa81SMatthias Ringwald         default:
5803a22aa81SMatthias Ringwald             btstack_unreachable();
5813a22aa81SMatthias Ringwald             break;
5823a22aa81SMatthias Ringwald     }
5830bbed0feSMatthias Ringwald     connection->state = GOEP_SERVER_OUTGOING_BUFFER_RESERVED;
5843a22aa81SMatthias Ringwald }
5853a22aa81SMatthias Ringwald 
goep_server_response_create_connect(uint16_t goep_cid,uint8_t obex_version_number,uint8_t flags,uint16_t maximum_obex_packet_length)5863a22aa81SMatthias 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){
5873a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
5883a22aa81SMatthias Ringwald     if (connection == NULL) {
5893a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
5903a22aa81SMatthias Ringwald     }
5913a22aa81SMatthias Ringwald 
5923a22aa81SMatthias Ringwald     goep_server_packet_init(connection);
5933a22aa81SMatthias Ringwald 
5943a22aa81SMatthias Ringwald     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU
5953a22aa81SMatthias Ringwald     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu);
5963a22aa81SMatthias Ringwald 
5973a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
5983a22aa81SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
5990f4783aaSMatthias Ringwald     return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, (uint32_t) goep_cid);
6003a22aa81SMatthias Ringwald }
6013a22aa81SMatthias Ringwald 
goep_server_response_create_general(uint16_t goep_cid)602c8e39cadSMatthias Ringwald uint8_t goep_server_response_create_general(uint16_t goep_cid){
6033a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
6043a22aa81SMatthias Ringwald     if (connection == NULL) {
6053a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
6063a22aa81SMatthias Ringwald     }
6073a22aa81SMatthias Ringwald     goep_server_packet_init(connection);
6083a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
6093a22aa81SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
610c8e39cadSMatthias Ringwald     return obex_message_builder_response_create_general(buffer, buffer_len, OBEX_RESP_SUCCESS);
6113a22aa81SMatthias Ringwald }
6123a22aa81SMatthias Ringwald 
goep_server_response_get_max_message_size(uint16_t goep_cid)613223b1d64SMatthias Ringwald uint16_t goep_server_response_get_max_message_size(uint16_t goep_cid){
614223b1d64SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
615223b1d64SMatthias Ringwald     if (connection == NULL) {
616223b1d64SMatthias Ringwald         return 0;
617223b1d64SMatthias Ringwald     }
618223b1d64SMatthias Ringwald     return goep_server_get_outgoing_buffer_len(connection);
619223b1d64SMatthias Ringwald }
620223b1d64SMatthias Ringwald 
goep_server_header_add_end_of_body(uint16_t goep_cid,const uint8_t * end_of_body,uint16_t length)6213a22aa81SMatthias Ringwald uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){
6223a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
6233a22aa81SMatthias Ringwald     if (connection == NULL) {
6243a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
6253a22aa81SMatthias Ringwald     }
6263a22aa81SMatthias Ringwald 
6273a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
6283a22aa81SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
6293a22aa81SMatthias Ringwald     return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length);
6303a22aa81SMatthias Ringwald }
6313a22aa81SMatthias Ringwald 
goep_server_header_add_who(uint16_t goep_cid,const uint8_t * target)6323a22aa81SMatthias Ringwald uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){
6333a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
6343a22aa81SMatthias Ringwald     if (connection == NULL) {
6353a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
6363a22aa81SMatthias Ringwald     }
6373a22aa81SMatthias Ringwald 
6383a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
6393a22aa81SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
6403a22aa81SMatthias Ringwald     return obex_message_builder_header_add_who(buffer, buffer_len, target);
6413a22aa81SMatthias Ringwald }
6423a22aa81SMatthias Ringwald 
goep_server_header_add_srm_enable(uint16_t goep_cid)6433a22aa81SMatthias Ringwald uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){
6443a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
6453a22aa81SMatthias Ringwald     if (connection == NULL) {
6463a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
6473a22aa81SMatthias Ringwald     }
6483a22aa81SMatthias Ringwald 
6493a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
6503a22aa81SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
6513a22aa81SMatthias Ringwald     return obex_message_builder_header_add_srm_enable(buffer, buffer_len);
6523a22aa81SMatthias Ringwald }
6533a22aa81SMatthias Ringwald 
goep_server_header_add_srm_enable_wait(uint16_t goep_cid)654*33554939SMatthias Ringwald uint8_t goep_server_header_add_srm_enable_wait(uint16_t goep_cid) {
655*33554939SMatthias Ringwald     goep_server_connection_t* connection = goep_server_get_connection_for_goep_cid(goep_cid);
656*33554939SMatthias Ringwald     if (connection == NULL) {
657*33554939SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
658*33554939SMatthias Ringwald     }
659*33554939SMatthias Ringwald 
660*33554939SMatthias Ringwald     uint8_t* buffer = goep_server_get_outgoing_buffer(connection);
661*33554939SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
662*33554939SMatthias Ringwald     return obex_message_builder_header_add_srm_enable(buffer, buffer_len)
663*33554939SMatthias Ringwald         || obex_message_builder_header_add_srmp_wait(buffer, buffer_len);
664*33554939SMatthias Ringwald }
665*33554939SMatthias Ringwald 
goep_server_header_add_name(uint16_t goep_cid,const char * name)666*33554939SMatthias Ringwald uint8_t goep_server_header_add_name(uint16_t goep_cid, const char* name) {
667*33554939SMatthias Ringwald 
668*33554939SMatthias Ringwald     if (name == NULL) {
669*33554939SMatthias Ringwald         return OBEX_UNKNOWN_ERROR;
670*33554939SMatthias Ringwald     }
671*33554939SMatthias Ringwald 
672*33554939SMatthias Ringwald     goep_server_connection_t* connection = goep_server_get_connection_for_goep_cid(goep_cid);
673*33554939SMatthias Ringwald     if (connection == NULL) {
674*33554939SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
675*33554939SMatthias Ringwald     }
676*33554939SMatthias Ringwald 
677*33554939SMatthias Ringwald     uint8_t* buffer = goep_server_get_outgoing_buffer(connection);
678*33554939SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
679*33554939SMatthias Ringwald     return obex_message_builder_header_add_name(buffer, buffer_len, name);
680*33554939SMatthias Ringwald }
681*33554939SMatthias Ringwald 
goep_server_header_add_type(uint16_t goep_cid,const char * type)682*33554939SMatthias Ringwald uint8_t goep_server_header_add_type(uint16_t goep_cid, const char* type) {
683*33554939SMatthias Ringwald 
684*33554939SMatthias Ringwald     if (type == NULL) {
685*33554939SMatthias Ringwald         return OBEX_UNKNOWN_ERROR;
686*33554939SMatthias Ringwald     }
687*33554939SMatthias Ringwald 
688*33554939SMatthias Ringwald     goep_server_connection_t* connection = goep_server_get_connection_for_goep_cid(goep_cid);
689*33554939SMatthias Ringwald     if (connection == NULL) {
690*33554939SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
691*33554939SMatthias Ringwald     }
692*33554939SMatthias Ringwald 
693*33554939SMatthias Ringwald     uint8_t* buffer = goep_server_get_outgoing_buffer(connection);
694*33554939SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
695*33554939SMatthias Ringwald     return obex_message_builder_header_add_type(buffer, buffer_len, type);
696*33554939SMatthias Ringwald }
697*33554939SMatthias Ringwald 
goep_server_header_add_application_parameters(uint16_t goep_cid,const uint8_t * data,uint16_t length)6982a4ebdf6SMatthias Ringwald uint8_t goep_server_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){
6992a4ebdf6SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
7002a4ebdf6SMatthias Ringwald     if (connection == NULL) {
7012a4ebdf6SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
7022a4ebdf6SMatthias Ringwald     }
7032a4ebdf6SMatthias Ringwald 
7042a4ebdf6SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
7052a4ebdf6SMatthias Ringwald     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
7062a4ebdf6SMatthias Ringwald     return obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length);
7072a4ebdf6SMatthias Ringwald }
7082a4ebdf6SMatthias Ringwald 
goep_server_execute(uint16_t goep_cid,uint8_t response_code)709c8e39cadSMatthias Ringwald uint8_t goep_server_execute(uint16_t goep_cid, uint8_t response_code){
7103a22aa81SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
7113a22aa81SMatthias Ringwald     if (connection == NULL) {
7123a22aa81SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
7133a22aa81SMatthias Ringwald     }
7143a22aa81SMatthias Ringwald 
715b2eb4c1eSMatthias Ringwald     btstack_assert(connection->state == GOEP_SERVER_OUTGOING_BUFFER_RESERVED);
7169988a575SMatthias Ringwald 
7170bbed0feSMatthias Ringwald     connection->state = GOEP_SERVER_CONNECTED;
7180bbed0feSMatthias Ringwald 
7193a22aa81SMatthias Ringwald     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
7200bbed0feSMatthias Ringwald     // set response code
721c8e39cadSMatthias Ringwald     buffer[0] = response_code;
7223a22aa81SMatthias Ringwald     uint16_t pos = big_endian_read_16(buffer, 1);
7233a22aa81SMatthias Ringwald     switch (connection->type) {
7243a22aa81SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
7253a22aa81SMatthias Ringwald         case GOEP_CONNECTION_L2CAP:
7263a22aa81SMatthias Ringwald             return l2cap_send(connection->bearer_cid, buffer, pos);
7273a22aa81SMatthias Ringwald             break;
7283a22aa81SMatthias Ringwald #endif
7293a22aa81SMatthias Ringwald         case GOEP_CONNECTION_RFCOMM:
7303a22aa81SMatthias Ringwald             return rfcomm_send_prepared(connection->bearer_cid, pos);
7313a22aa81SMatthias Ringwald         default:
7323a22aa81SMatthias Ringwald             btstack_unreachable();
7333a22aa81SMatthias Ringwald             return ERROR_CODE_SUCCESS;
7343a22aa81SMatthias Ringwald     }
7353a22aa81SMatthias Ringwald }
7363a22aa81SMatthias Ringwald 
goep_server_disconnect(uint16_t goep_cid)73703ebb521SMatthias Ringwald uint8_t goep_server_disconnect(uint16_t goep_cid){
73803ebb521SMatthias Ringwald     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
73903ebb521SMatthias Ringwald     if (connection == NULL) {
74003ebb521SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
74103ebb521SMatthias Ringwald     }
74203ebb521SMatthias Ringwald 
74303ebb521SMatthias Ringwald     if (connection->state < GOEP_SERVER_CONNECTED){
74403ebb521SMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
74503ebb521SMatthias Ringwald     }
74603ebb521SMatthias Ringwald 
74703ebb521SMatthias Ringwald     switch (connection->type) {
74803ebb521SMatthias Ringwald #ifdef ENABLE_GOEP_L2CAP
74903ebb521SMatthias Ringwald         case GOEP_CONNECTION_L2CAP:
75003ebb521SMatthias Ringwald             return l2cap_disconnect(connection->bearer_cid);
75103ebb521SMatthias Ringwald #endif
75203ebb521SMatthias Ringwald         case GOEP_CONNECTION_RFCOMM:
75303ebb521SMatthias Ringwald             return rfcomm_disconnect(connection->bearer_cid);
75403ebb521SMatthias Ringwald         default:
75503ebb521SMatthias Ringwald             btstack_unreachable();
75603ebb521SMatthias Ringwald             break;
75703ebb521SMatthias Ringwald     }
75803ebb521SMatthias Ringwald     return ERROR_CODE_SUCCESS;
75903ebb521SMatthias Ringwald }
76003ebb521SMatthias Ringwald 
goep_server_deinit(void)7613a22aa81SMatthias Ringwald void goep_server_deinit(void){
7623a22aa81SMatthias Ringwald     goep_server_cid_counter = 0;
7633a22aa81SMatthias Ringwald     goep_server_services = NULL;
7643a22aa81SMatthias Ringwald }
765