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