xref: /btstack/src/classic/goep_server.c (revision 3a22aa8134d7c290df4b834dfe6e46937ee12839)
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 
55 #ifdef ENABLE_GOEP_L2CAP
56 #include "l2cap.h"
57 #include "obex_message_builder.h"
58 
59 static l2cap_ertm_config_t ertm_config = {
60     1,  // ertm mandatory
61     2,  // max transmit, some tests require > 1
62     2000,
63     12000,
64     (GOEP_SERVER_ERTM_BUFFER / 2),    // l2cap ertm mtu
65     2,
66     2,
67     1,      // 16-bit FCS
68 };
69 
70 static uint8_t goep_server_l2cap_packet_buffer[1000];
71 
72 #endif
73 
74 static btstack_linked_list_t goep_server_connections = NULL;
75 static btstack_linked_list_t goep_server_services = NULL;
76 static uint16_t goep_server_cid_counter = 0;
77 
78 static goep_server_service_t * goep_server_get_service_for_rfcomm_channel(uint8_t rfcomm_channel){
79     btstack_linked_item_t *it;
80     for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){
81         goep_server_service_t * service = ((goep_server_service_t *) it);
82         if (service->rfcomm_channel == rfcomm_channel){
83             return service;
84         };
85     }
86     return NULL;
87 }
88 
89 static goep_server_service_t * goep_server_get_service_for_l2cap_psm(uint16_t l2cap_psm){
90     btstack_linked_item_t *it;
91     for (it = (btstack_linked_item_t *) goep_server_services; it ; it = it->next){
92         goep_server_service_t * service = ((goep_server_service_t *) it);
93         if (service->l2cap_psm == l2cap_psm){
94             return service;
95         };
96     }
97     return NULL;
98 }
99 
100 static goep_server_connection_t * goep_server_get_connection_for_rfcomm_cid(uint16_t bearer_cid){
101     btstack_linked_item_t *it;
102     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
103         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
104         if (connection->type != GOEP_CONNECTION_RFCOMM) continue;
105         if (connection->bearer_cid == bearer_cid){
106             return connection;
107         };
108     }
109     return NULL;
110 }
111 
112 static goep_server_connection_t * goep_server_get_connection_for_l2cap_cid(uint16_t bearer_cid){
113     btstack_linked_item_t *it;
114     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
115         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
116         if (connection->type != GOEP_CONNECTION_L2CAP) continue;
117         if (connection->bearer_cid == bearer_cid){
118             return connection;
119         };
120     }
121     return NULL;
122 }
123 
124 static goep_server_connection_t * goep_server_get_connection_for_goep_cid(uint16_t goep_cid){
125     btstack_linked_item_t *it;
126     for (it = (btstack_linked_item_t *) goep_server_connections; it ; it = it->next){
127         goep_server_connection_t * connection = ((goep_server_connection_t *) it);
128         if (connection->goep_cid == goep_cid){
129             return connection;
130         };
131     }
132     return NULL;
133 }
134 
135 static uint16_t goep_server_get_next_goep_cid(void){
136     goep_server_cid_counter++;
137     if (goep_server_cid_counter == 0){
138         goep_server_cid_counter = 1;
139     }
140     return goep_server_cid_counter;
141 }
142 
143 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){
144     uint8_t event[15];
145     uint16_t pos = 0;
146     event[pos++] = HCI_EVENT_GOEP_META;
147     event[pos++] = 15 - 2;
148     event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED;
149     little_endian_store_16(event, pos, goep_cid);
150     pos+=2;
151     event[pos++] = status;
152     memcpy(&event[pos], bd_addr, 6);
153     pos += 6;
154     little_endian_store_16(event, pos, con_handle);
155     pos += 2;
156     event[pos++] = 1;
157     btstack_assert(pos == sizeof(event));
158     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
159 }
160 
161 static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){
162     uint8_t event[5];
163     uint16_t pos = 0;
164     event[pos++] = HCI_EVENT_GOEP_META;
165     event[pos++] = 5 - 3;
166     event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED;
167     little_endian_store_16(event, pos, goep_cid);
168     pos += 2;
169     btstack_assert(pos == sizeof(event));
170     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
171 }
172 
173 static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){
174     uint8_t event[5];
175     uint16_t pos = 0;
176     event[pos++] = HCI_EVENT_GOEP_META;
177     event[pos++] = 5 - 3;
178     event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW;
179     little_endian_store_16(event,pos,connection->goep_cid);
180     pos += 2;
181     btstack_assert(pos == sizeof(event));
182     connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos);
183 }
184 
185 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){
186 
187     uint16_t goep_cid = context->goep_cid;
188     btstack_packet_handler_t packet_handler = context->callback;
189 
190     if (status) {
191         log_info("goep_client: open failed, status %u", status);
192         btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context);
193         btstack_memory_goep_server_connection_free(context);
194     } else {
195         // context->bearer_mtu = mtu;
196         context->state = GOEP_SERVER_CONNECTED;
197         context->bearer_cid = bearer_cid;
198 #ifdef ENABLE_GOEP_L2CAP
199         if (context->type == GOEP_CONNECTION_L2CAP){
200             bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer));
201         }
202 #endif
203         context->bearer_mtu = bearer_mtu;
204         log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu);
205     }
206 
207     goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status);
208 }
209 
210 static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){
211     uint16_t goep_cid = goep_connection->goep_cid;
212     btstack_packet_handler_t packet_handler = goep_connection->callback;
213 
214     btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
215     btstack_memory_goep_server_connection_free(goep_connection);
216 
217     goep_server_emit_connection_closed(packet_handler, goep_cid);
218 }
219 
220 #ifdef ENABLE_GOEP_L2CAP
221 static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
222     UNUSED(channel);
223     UNUSED(size);
224 
225     bd_addr_t event_addr;
226     uint16_t l2cap_psm;
227     uint16_t l2cap_cid;
228     goep_server_connection_t * goep_connection;
229     goep_server_service_t *    goep_service;
230 
231     switch (packet_type){
232         case HCI_EVENT_PACKET:
233             switch (hci_event_packet_get_type(packet)) {
234                 case L2CAP_EVENT_INCOMING_CONNECTION:
235                     l2cap_psm = l2cap_event_incoming_connection_get_psm(packet);
236                     l2cap_cid  = l2cap_event_incoming_connection_get_local_cid(packet);
237                     goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
238                     if (!goep_service){
239                         l2cap_decline_connection(l2cap_cid);
240                         break;
241                     }
242 
243                     // alloc structure
244                     goep_connection = btstack_memory_goep_server_connection_get();
245                     if (!goep_connection){
246                         l2cap_decline_connection(l2cap_cid);
247                         break;
248                     }
249 
250                     // setup connection
251                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
252                     goep_connection->bearer_cid = l2cap_cid;
253                     goep_connection->callback   = goep_service->callback;
254                     goep_connection->type       = GOEP_CONNECTION_L2CAP;
255                     goep_connection->state      = GOEP_SERVER_W4_CONNECTED;
256                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
257                     l2cap_ertm_accept_connection(l2cap_cid, &ertm_config, goep_connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER);
258                     break;
259 
260                 case L2CAP_EVENT_CHANNEL_OPENED:
261                     l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet);
262                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
263                     btstack_assert(goep_connection != NULL);
264                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
265                     l2cap_event_channel_opened_get_address(packet, event_addr);
266                     goep_server_handle_connection_opened(goep_connection, event_addr,
267                                                          l2cap_event_channel_opened_get_handle(packet),
268                                                          l2cap_event_channel_opened_get_status(packet),
269                                                          l2cap_cid,
270                                                          l2cap_event_channel_opened_get_remote_mtu(packet) );
271                     return;
272                 case L2CAP_EVENT_CAN_SEND_NOW:
273                     l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet);
274                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
275                     btstack_assert(goep_connection != NULL);
276                     goep_server_emit_can_send_now_event(goep_connection);
277                     break;
278                 case L2CAP_EVENT_CHANNEL_CLOSED:
279                     l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet);
280                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
281                     btstack_assert(goep_connection != NULL);
282                     goep_server_handle_connection_closed(goep_connection);
283                     break;
284                 default:
285                     break;
286             }
287             break;
288         case L2CAP_DATA_PACKET:
289             goep_connection = goep_server_get_connection_for_l2cap_cid(channel);
290             btstack_assert(goep_connection != NULL);
291             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
292             break;
293         default:
294             break;
295     }
296 }
297 #endif
298 
299 static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
300     UNUSED(channel);
301     UNUSED(size);
302 
303     bd_addr_t event_addr;
304     uint8_t  rfcomm_channel;
305     uint16_t rfcomm_cid;
306     goep_server_service_t    * goep_service;
307     goep_server_connection_t * goep_connection;
308 
309     switch (packet_type){
310         case HCI_EVENT_PACKET:
311             switch (hci_event_packet_get_type(packet)) {
312                 case RFCOMM_EVENT_INCOMING_CONNECTION:
313                     rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet);
314                     rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
315 
316                     goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
317                     if (!goep_service){
318                         rfcomm_decline_connection(rfcomm_cid);
319                         break;
320                     }
321 
322                     // alloc structure
323                     goep_connection = btstack_memory_goep_server_connection_get();
324                     if (!goep_connection){
325                         rfcomm_decline_connection(rfcomm_cid);
326                         break;
327                     }
328 
329                     // setup connection
330                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
331                     goep_connection->bearer_cid = rfcomm_cid;
332                     goep_connection->callback   = goep_service->callback;
333                     goep_connection->type       = GOEP_CONNECTION_RFCOMM;
334                     goep_connection->state      = GOEP_SERVER_W4_CONNECTED;
335                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
336                     rfcomm_accept_connection(rfcomm_cid);
337                     break;
338 
339                 case RFCOMM_EVENT_CHANNEL_OPENED:
340                     rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
341                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
342                     btstack_assert(goep_connection != NULL);
343                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
344                     rfcomm_event_channel_opened_get_bd_addr(packet, event_addr);
345                     goep_server_handle_connection_opened(goep_connection, event_addr,
346                                                          rfcomm_event_channel_opened_get_con_handle(packet),
347                                                          rfcomm_event_channel_opened_get_status(packet),
348                                                          rfcomm_cid,
349                                                          rfcomm_event_channel_opened_get_max_frame_size(packet) );
350                     break;
351 
352                 case RFCOMM_EVENT_CAN_SEND_NOW:
353                     rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
354                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
355                     btstack_assert(goep_connection != NULL);
356                     goep_server_emit_can_send_now_event(goep_connection);
357                     break;
358 
359                 case RFCOMM_EVENT_CHANNEL_CLOSED:
360                     rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet);
361                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
362                     btstack_assert(goep_connection != NULL);
363                     goep_server_handle_connection_closed(goep_connection);
364                     break;
365 
366                 default:
367                     break;
368             }
369             break;
370 
371         case RFCOMM_DATA_PACKET:
372             goep_connection = goep_server_get_connection_for_rfcomm_cid(channel);
373             btstack_assert(goep_connection != NULL);
374             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
375             break;
376 
377         default:
378             break;
379     }
380 }
381 
382 void goep_server_init(void){
383 }
384 
385 uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size,
386                 uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){
387 
388     log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u",
389              rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu);
390 
391     // check if service is already registered
392     goep_server_service_t * service;
393     service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
394     if (service != NULL) {
395         return RFCOMM_CHANNEL_ALREADY_REGISTERED;
396     }
397 
398 #ifdef ENABLE_GOEP_L2CAP
399     if (l2cap_psm != 0){
400         service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
401         if (service != NULL) {
402             return L2CAP_SERVICE_ALREADY_REGISTERED;
403         }
404     }
405 #endif
406 
407     // alloc structure
408     service = btstack_memory_goep_server_service_get();
409     if (service == NULL) {
410         return BTSTACK_MEMORY_ALLOC_FAILED;
411     }
412 
413     // fill in
414     service->callback = callback;
415     service->rfcomm_channel = rfcomm_channel;
416     service->l2cap_psm = l2cap_psm;
417 
418     uint8_t status = ERROR_CODE_SUCCESS;
419     bool rfcomm_registered = false;
420 
421 #ifdef ENABLE_GOEP_L2CAP
422     bool l2cap_registered = false;
423     // register with L2CAP
424     if (l2cap_psm != 0){
425         status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level);
426         if (status == ERROR_CODE_SUCCESS){
427             l2cap_registered = true;
428         }
429     }
430 #endif
431 
432     // register with RFCOMM
433     if (status == ERROR_CODE_SUCCESS){
434         status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size);
435         if (status == ERROR_CODE_SUCCESS){
436             rfcomm_registered = true;
437         }
438     }
439 
440     // add service on success
441     if (status == ERROR_CODE_SUCCESS){
442         btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service);
443         return ERROR_CODE_SUCCESS;
444     }
445 
446     // unrestore otherwise
447     btstack_memory_goep_server_service_free(service);
448 #ifdef ENABLE_GOEP_L2CAP
449     if (l2cap_registered){
450         l2cap_unregister_service(l2cap_psm);
451     }
452 #endif
453     if (rfcomm_registered){
454         rfcomm_unregister_service(rfcomm_channel);
455     }
456     return status;
457 }
458 
459 uint8_t goep_server_request_can_send_now(uint16_t goep_cid){
460     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
461     if (connection == NULL){
462         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
463     }
464 
465     switch (connection->type){
466         case GOEP_CONNECTION_RFCOMM:
467             rfcomm_request_can_send_now_event(connection->bearer_cid);
468             break;
469 #ifdef ENABLE_GOEP_L2CAP
470         case GOEP_CONNECTION_L2CAP:
471             l2cap_request_can_send_now_event(connection->bearer_cid);
472             break;
473 #endif
474         default:
475             btstack_unreachable();
476             break;
477     }
478     return ERROR_CODE_SUCCESS;
479 }
480 
481 static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){
482     switch (connection->type){
483 #ifdef ENABLE_GOEP_L2CAP
484         case GOEP_CONNECTION_L2CAP:
485             return goep_server_l2cap_packet_buffer;
486 #endif
487         case GOEP_CONNECTION_RFCOMM:
488             return rfcomm_get_outgoing_buffer();
489         default:
490             btstack_unreachable();
491             return NULL;
492     }
493 }
494 
495 static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){
496     return connection->bearer_mtu;
497 }
498 
499 static void goep_server_packet_init(goep_server_connection_t * connection){
500     switch (connection->type){
501 #ifdef ENABLE_GOEP_L2CAP
502         case GOEP_CONNECTION_L2CAP:
503             break;
504 #endif
505         case GOEP_CONNECTION_RFCOMM:
506             rfcomm_reserve_packet_buffer();
507             break;
508         default:
509             btstack_unreachable();
510             break;
511     }
512 }
513 
514 uint8_t goep_server_set_connection_id(uint16_t goep_cid, uint32_t connection_id){
515     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
516     if (connection == NULL) {
517         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
518     }
519     connection->obex_connection_id = connection_id;
520     return ERROR_CODE_SUCCESS;
521 }
522 
523 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){
524     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
525     if (connection == NULL) {
526         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
527     }
528 
529     goep_server_packet_init(connection);
530 
531     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU
532     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu);
533 
534     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
535     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
536     return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, connection->obex_connection_id);
537 }
538 
539 uint8_t goep_server_response_create_general(uint16_t goep_cid, uint8_t opcode){
540     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
541     if (connection == NULL) {
542         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
543     }
544     goep_server_packet_init(connection);
545     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
546     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
547     return obex_message_builder_response_create_general(buffer, buffer_len, opcode);
548 }
549 
550 uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){
551     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
552     if (connection == NULL) {
553         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
554     }
555 
556     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
557     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
558     return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length);
559 }
560 
561 uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){
562     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
563     if (connection == NULL) {
564         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
565     }
566 
567     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
568     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
569     return obex_message_builder_header_add_who(buffer, buffer_len, target);
570 }
571 
572 uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){
573     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
574     if (connection == NULL) {
575         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
576     }
577 
578     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
579     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
580     return obex_message_builder_header_add_srm_enable(buffer, buffer_len);
581 }
582 
583 uint8_t goep_server_execute(uint16_t goep_cid){
584     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
585     if (connection == NULL) {
586         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
587     }
588 
589     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
590     uint16_t pos = big_endian_read_16(buffer, 1);
591     switch (connection->type) {
592 #ifdef ENABLE_GOEP_L2CAP
593         case GOEP_CONNECTION_L2CAP:
594             return l2cap_send(connection->bearer_cid, buffer, pos);
595             break;
596 #endif
597         case GOEP_CONNECTION_RFCOMM:
598             return rfcomm_send_prepared(connection->bearer_cid, pos);
599             break;
600         default:
601             btstack_unreachable();
602             return ERROR_CODE_SUCCESS;
603     }
604 }
605 
606 void goep_server_deinit(void){
607     goep_server_cid_counter = 0;
608     goep_server_services = NULL;
609 }
610