xref: /btstack/src/classic/goep_server.c (revision 5248bd90c851e9f5d237c4a5bb20c0b876507180)
1 /*
2  * Copyright (C) 2019 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "goep_server.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <string.h>
44 
45 #include "hci_cmd.h"
46 #include "btstack_debug.h"
47 #include "btstack_defines.h"
48 #include "hci.h"
49 #include "btstack_memory.h"
50 #include "hci_dump.h"
51 #include "btstack_event.h"
52 
53 #include "classic/goep_server.h"
54 #include "classic/obex_message_builder.h"
55 
56 #ifdef ENABLE_GOEP_L2CAP
57 #include "l2cap.h"
58 #include "obex_message_builder.h"
59 
60 static l2cap_ertm_config_t ertm_config = {
61     1,  // ertm mandatory
62     2,  // max transmit, some tests require > 1
63     2000,
64     12000,
65     (GOEP_SERVER_ERTM_BUFFER / 2),    // l2cap ertm mtu
66     2,
67     2,
68     1,      // 16-bit FCS
69 };
70 
71 static uint8_t goep_server_l2cap_packet_buffer[1000];
72 
73 #endif
74 
75 static btstack_linked_list_t goep_server_connections = NULL;
76 static btstack_linked_list_t goep_server_services = NULL;
77 static uint16_t goep_server_cid_counter = 0;
78 
79 static goep_server_service_t * goep_server_get_service_for_rfcomm_channel(uint8_t rfcomm_channel){
80     btstack_linked_item_t *it;
81     for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){
82         goep_server_service_t * service = ((goep_server_service_t *) it);
83         if (service->rfcomm_channel == rfcomm_channel){
84             return service;
85         };
86     }
87     return NULL;
88 }
89 
90 static goep_server_service_t * goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm){
91     btstack_linked_item_t *it;
92     for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){
93         goep_server_service_t * service = ((goep_server_service_t *) it);
94         if (service->l2cap_psm == l2cap_psm){
95             return service;
96         };
97     }
98     return NULL;
99 }
100 
101 static goep_server_connection_t * goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid){
102     btstack_linked_item_t *it;
103     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
104         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
105         if (connection->type != GOEP_CONNECTION_RFCOMM) continue;
106         if (connection->bearer_cid == bearer_cid){
107             return connection;
108         };
109     }
110     return NULL;
111 }
112 
113 static goep_server_connection_t * goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid){
114     btstack_linked_item_t *it;
115     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
116         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
117         if (connection->type != GOEP_CONNECTION_L2CAP) continue;
118         if (connection->bearer_cid == bearer_cid){
119             return connection;
120         };
121     }
122     return NULL;
123 }
124 
125 static goep_server_connection_t * goep_server_get_connection_for_goep_cid(uint16_t goep_cid){
126     btstack_linked_item_t *it;
127     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
128         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
129         if (connection->goep_cid == goep_cid){
130             return connection;
131         };
132     }
133     return NULL;
134 }
135 
136 static uint16_t goep_server_get_next_goep_cid(void){
137     goep_server_cid_counter++;
138     if (goep_server_cid_counter == 0){
139         goep_server_cid_counter = 1;
140     }
141     return goep_server_cid_counter;
142 }
143 
144 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){
145     uint8_t event[15];
146     uint16_t pos = 0;
147     event[pos++] = HCI_EVENT_GOEP_META;
148     event[pos++] = 15 - 2;
149     event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED;
150     little_endian_store_16(event, pos, goep_cid);
151     pos+=2;
152     event[pos++] = status;
153     memcpy(&event[pos], bd_addr, 6);
154     pos += 6;
155     little_endian_store_16(event, pos, con_handle);
156     pos += 2;
157     event[pos++] = 1;
158     btstack_assert(pos == sizeof(event));
159     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
160 }
161 
162 static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){
163     uint8_t event[5];
164     uint16_t pos = 0;
165     event[pos++] = HCI_EVENT_GOEP_META;
166     event[pos++] = 5 - 3;
167     event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED;
168     little_endian_store_16(event, pos, goep_cid);
169     pos += 2;
170     btstack_assert(pos == sizeof(event));
171     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
172 }
173 
174 static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){
175     uint8_t event[5];
176     uint16_t pos = 0;
177     event[pos++] = HCI_EVENT_GOEP_META;
178     event[pos++] = 5 - 3;
179     event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW;
180     little_endian_store_16(event,pos,connection->goep_cid);
181     pos += 2;
182     btstack_assert(pos == sizeof(event));
183     connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos);
184 }
185 
186 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){
187 
188     uint16_t goep_cid = context->goep_cid;
189     btstack_packet_handler_t packet_handler = context->callback;
190 
191     if (status) {
192         log_info("goep_client: open failed, status %u", status);
193         btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context);
194         btstack_memory_goep_server_connection_free(context);
195     } else {
196         // context->bearer_mtu = mtu;
197         context->state = GOEP_SERVER_CONNECTED;
198         context->bearer_cid = bearer_cid;
199 #ifdef ENABLE_GOEP_L2CAP
200         if (context->type == GOEP_CONNECTION_L2CAP){
201             bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer));
202         }
203 #endif
204         context->bearer_mtu = bearer_mtu;
205         log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu);
206     }
207 
208     goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status);
209 }
210 
211 static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){
212     uint16_t goep_cid = goep_connection->goep_cid;
213     btstack_packet_handler_t packet_handler = goep_connection->callback;
214 
215     btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
216     btstack_memory_goep_server_connection_free(goep_connection);
217 
218     goep_server_emit_connection_closed(packet_handler, goep_cid);
219 }
220 
221 #ifdef ENABLE_GOEP_L2CAP
222 static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
223     UNUSED(channel);
224     UNUSED(size);
225 
226     bd_addr_t event_addr;
227     uint16_t l2cap_psm;
228     uint16_t l2cap_cid;
229     goep_server_connection_t * goep_connection;
230     goep_server_service_t *    goep_service;
231 
232     switch (packet_type){
233         case HCI_EVENT_PACKET:
234             switch (hci_event_packet_get_type(packet)) {
235                 case L2CAP_EVENT_INCOMING_CONNECTION:
236                     l2cap_psm = l2cap_event_incoming_connection_get_psm(packet);
237                     l2cap_cid  = l2cap_event_incoming_connection_get_local_cid(packet);
238                     goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
239                     if (!goep_service){
240                         l2cap_decline_connection(l2cap_cid);
241                         break;
242                     }
243 
244                     // alloc structure
245                     goep_connection = btstack_memory_goep_server_connection_get();
246                     if (!goep_connection){
247                         l2cap_decline_connection(l2cap_cid);
248                         break;
249                     }
250 
251                     // setup connection
252                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
253                     goep_connection->bearer_cid = l2cap_cid;
254                     goep_connection->callback   = goep_service->callback;
255                     goep_connection->type       = GOEP_CONNECTION_L2CAP;
256                     goep_connection->state      = GOEP_SERVER_W4_CONNECTED;
257                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
258                     l2cap_ertm_accept_connection(l2cap_cid, &ertm_config, goep_connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER);
259                     break;
260 
261                 case L2CAP_EVENT_CHANNEL_OPENED:
262                     l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet);
263                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
264                     btstack_assert(goep_connection != NULL);
265                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
266                     l2cap_event_channel_opened_get_address(packet, event_addr);
267                     goep_server_handle_connection_opened(goep_connection, event_addr,
268                                                          l2cap_event_channel_opened_get_handle(packet),
269                                                          l2cap_event_channel_opened_get_status(packet),
270                                                          l2cap_cid,
271                                                          l2cap_event_channel_opened_get_remote_mtu(packet) );
272                     return;
273                 case L2CAP_EVENT_CAN_SEND_NOW:
274                     l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet);
275                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
276                     btstack_assert(goep_connection != NULL);
277                     goep_server_emit_can_send_now_event(goep_connection);
278                     break;
279                 case L2CAP_EVENT_CHANNEL_CLOSED:
280                     l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet);
281                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
282                     btstack_assert(goep_connection != NULL);
283                     goep_server_handle_connection_closed(goep_connection);
284                     break;
285                 default:
286                     break;
287             }
288             break;
289         case L2CAP_DATA_PACKET:
290             goep_connection = goep_server_get_connection_for_l2cap_cid(channel);
291             btstack_assert(goep_connection != NULL);
292             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
293             break;
294         default:
295             break;
296     }
297 }
298 #endif
299 
300 static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
301     UNUSED(channel);
302     UNUSED(size);
303 
304     bd_addr_t event_addr;
305     uint8_t  rfcomm_channel;
306     uint16_t rfcomm_cid;
307     goep_server_service_t    * goep_service;
308     goep_server_connection_t * goep_connection;
309 
310     switch (packet_type){
311         case HCI_EVENT_PACKET:
312             switch (hci_event_packet_get_type(packet)) {
313                 case RFCOMM_EVENT_INCOMING_CONNECTION:
314                     rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet);
315                     rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
316 
317                     goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
318                     if (!goep_service){
319                         rfcomm_decline_connection(rfcomm_cid);
320                         break;
321                     }
322 
323                     // alloc structure
324                     goep_connection = btstack_memory_goep_server_connection_get();
325                     if (!goep_connection){
326                         rfcomm_decline_connection(rfcomm_cid);
327                         break;
328                     }
329 
330                     // setup connection
331                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
332                     goep_connection->bearer_cid = rfcomm_cid;
333                     goep_connection->callback   = goep_service->callback;
334                     goep_connection->type       = GOEP_CONNECTION_RFCOMM;
335                     goep_connection->state      = GOEP_SERVER_W4_CONNECTED;
336                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
337                     rfcomm_accept_connection(rfcomm_cid);
338                     break;
339 
340                 case RFCOMM_EVENT_CHANNEL_OPENED:
341                     rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
342                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
343                     btstack_assert(goep_connection != NULL);
344                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
345                     rfcomm_event_channel_opened_get_bd_addr(packet, event_addr);
346                     goep_server_handle_connection_opened(goep_connection, event_addr,
347                                                          rfcomm_event_channel_opened_get_con_handle(packet),
348                                                          rfcomm_event_channel_opened_get_status(packet),
349                                                          rfcomm_cid,
350                                                          rfcomm_event_channel_opened_get_max_frame_size(packet) );
351                     break;
352 
353                 case RFCOMM_EVENT_CAN_SEND_NOW:
354                     rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
355                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
356                     btstack_assert(goep_connection != NULL);
357                     goep_server_emit_can_send_now_event(goep_connection);
358                     break;
359 
360                 case RFCOMM_EVENT_CHANNEL_CLOSED:
361                     rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet);
362                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
363                     btstack_assert(goep_connection != NULL);
364                     goep_server_handle_connection_closed(goep_connection);
365                     break;
366 
367                 default:
368                     break;
369             }
370             break;
371 
372         case RFCOMM_DATA_PACKET:
373             goep_connection = goep_server_get_connection_for_rfcomm_cid(channel);
374             btstack_assert(goep_connection != NULL);
375             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
376             break;
377 
378         default:
379             break;
380     }
381 }
382 
383 void goep_server_init(void){
384 }
385 
386 uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size,
387                 uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){
388 
389     log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u",
390              rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu);
391 
392     // check if service is already registered
393     goep_server_service_t * service;
394     service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
395     if (service != NULL) {
396         return RFCOMM_CHANNEL_ALREADY_REGISTERED;
397     }
398 
399 #ifdef ENABLE_GOEP_L2CAP
400     if (l2cap_psm != 0){
401         service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
402         if (service != NULL) {
403             return L2CAP_SERVICE_ALREADY_REGISTERED;
404         }
405     }
406 #endif
407 
408     // alloc structure
409     service = btstack_memory_goep_server_service_get();
410     if (service == NULL) {
411         return BTSTACK_MEMORY_ALLOC_FAILED;
412     }
413 
414     // fill in
415     service->callback = callback;
416     service->rfcomm_channel = rfcomm_channel;
417     service->l2cap_psm = l2cap_psm;
418 
419     uint8_t status = ERROR_CODE_SUCCESS;
420     bool rfcomm_registered = false;
421 
422 #ifdef ENABLE_GOEP_L2CAP
423     bool l2cap_registered = false;
424     // register with L2CAP
425     if (l2cap_psm != 0){
426         status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level);
427         if (status == ERROR_CODE_SUCCESS){
428             l2cap_registered = true;
429         }
430     }
431 #endif
432 
433     // register with RFCOMM
434     if (status == ERROR_CODE_SUCCESS){
435         status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size);
436         if (status == ERROR_CODE_SUCCESS){
437             rfcomm_registered = true;
438         }
439     }
440 
441     // add service on success
442     if (status == ERROR_CODE_SUCCESS){
443         btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service);
444         return ERROR_CODE_SUCCESS;
445     }
446 
447     // unrestore otherwise
448     btstack_memory_goep_server_service_free(service);
449 #ifdef ENABLE_GOEP_L2CAP
450     if (l2cap_registered){
451         l2cap_unregister_service(l2cap_psm);
452     }
453 #endif
454     if (rfcomm_registered){
455         rfcomm_unregister_service(rfcomm_channel);
456     }
457     return status;
458 }
459 
460 uint8_t goep_server_request_can_send_now(uint16_t goep_cid){
461     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
462     if (connection == NULL){
463         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
464     }
465 
466     switch (connection->type){
467         case GOEP_CONNECTION_RFCOMM:
468             rfcomm_request_can_send_now_event(connection->bearer_cid);
469             break;
470 #ifdef ENABLE_GOEP_L2CAP
471         case GOEP_CONNECTION_L2CAP:
472             l2cap_request_can_send_now_event(connection->bearer_cid);
473             break;
474 #endif
475         default:
476             btstack_unreachable();
477             break;
478     }
479     return ERROR_CODE_SUCCESS;
480 }
481 
482 static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){
483     switch (connection->type){
484 #ifdef ENABLE_GOEP_L2CAP
485         case GOEP_CONNECTION_L2CAP:
486             return goep_server_l2cap_packet_buffer;
487 #endif
488         case GOEP_CONNECTION_RFCOMM:
489             return rfcomm_get_outgoing_buffer();
490         default:
491             btstack_unreachable();
492             return NULL;
493     }
494 }
495 
496 static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){
497     return connection->bearer_mtu;
498 }
499 
500 static void goep_server_packet_init(goep_server_connection_t * connection){
501     switch (connection->type){
502 #ifdef ENABLE_GOEP_L2CAP
503         case GOEP_CONNECTION_L2CAP:
504             break;
505 #endif
506         case GOEP_CONNECTION_RFCOMM:
507             rfcomm_reserve_packet_buffer();
508             break;
509         default:
510             btstack_unreachable();
511             break;
512     }
513 }
514 
515 uint8_t goep_server_set_connection_id(uint16_t goep_cid, uint32_t connection_id){
516     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
517     if (connection == NULL) {
518         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
519     }
520     connection->obex_connection_id = connection_id;
521     return ERROR_CODE_SUCCESS;
522 }
523 
524 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){
525     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
526     if (connection == NULL) {
527         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
528     }
529 
530     goep_server_packet_init(connection);
531 
532     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU
533     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu);
534 
535     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
536     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
537     return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, connection->obex_connection_id);
538 }
539 
540 uint8_t goep_server_response_create_general(uint16_t goep_cid, uint8_t opcode){
541     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
542     if (connection == NULL) {
543         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
544     }
545     goep_server_packet_init(connection);
546     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
547     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
548     return obex_message_builder_response_create_general(buffer, buffer_len, opcode);
549 }
550 
551 uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){
552     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
553     if (connection == NULL) {
554         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
555     }
556 
557     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
558     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
559     return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length);
560 }
561 
562 uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){
563     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
564     if (connection == NULL) {
565         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
566     }
567 
568     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
569     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
570     return obex_message_builder_header_add_who(buffer, buffer_len, target);
571 }
572 
573 uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){
574     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
575     if (connection == NULL) {
576         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
577     }
578 
579     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
580     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
581     return obex_message_builder_header_add_srm_enable(buffer, buffer_len);
582 }
583 
584 uint8_t goep_server_execute(uint16_t goep_cid){
585     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
586     if (connection == NULL) {
587         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
588     }
589 
590     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
591     uint16_t pos = big_endian_read_16(buffer, 1);
592     switch (connection->type) {
593 #ifdef ENABLE_GOEP_L2CAP
594         case GOEP_CONNECTION_L2CAP:
595             return l2cap_send(connection->bearer_cid, buffer, pos);
596             break;
597 #endif
598         case GOEP_CONNECTION_RFCOMM:
599             return rfcomm_send_prepared(connection->bearer_cid, pos);
600             break;
601         default:
602             btstack_unreachable();
603             return ERROR_CODE_SUCCESS;
604     }
605 }
606 
607 void goep_server_deinit(void){
608     goep_server_cid_counter = 0;
609     goep_server_services = NULL;
610 }
611