xref: /btstack/src/classic/goep_server.c (revision a64cbea79fa5fb9daa58e135a19c6cce10f3e642)
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 
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_incoming_connection(btstack_packet_handler_t callback, uint16_t goep_cid, bd_addr_t bd_addr, hci_con_handle_t con_handle){
144     uint8_t event[13];
145     uint16_t pos = 0;
146     event[pos++] = HCI_EVENT_GOEP_META;
147     event[pos++] = 15 - 2;
148     event[pos++] = GOEP_SUBEVENT_INCOMING_CONNECTION;
149     little_endian_store_16(event, pos, goep_cid);
150     pos+=2;
151     memcpy(&event[pos], bd_addr, 6);
152     pos += 6;
153     little_endian_store_16(event, pos, con_handle);
154     pos += 2;
155     btstack_assert(pos == sizeof(event));
156     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
157 }
158 
159 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){
160     uint8_t event[15];
161     uint16_t pos = 0;
162     event[pos++] = HCI_EVENT_GOEP_META;
163     event[pos++] = 15 - 2;
164     event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED;
165     little_endian_store_16(event, pos, goep_cid);
166     pos+=2;
167     event[pos++] = status;
168     memcpy(&event[pos], bd_addr, 6);
169     pos += 6;
170     little_endian_store_16(event, pos, con_handle);
171     pos += 2;
172     event[pos++] = 1;
173     btstack_assert(pos == sizeof(event));
174     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
175 }
176 
177 static inline void goep_server_emit_connection_closed(btstack_packet_handler_t callback, uint16_t goep_cid){
178     uint8_t event[5];
179     uint16_t pos = 0;
180     event[pos++] = HCI_EVENT_GOEP_META;
181     event[pos++] = 5 - 3;
182     event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED;
183     little_endian_store_16(event, pos, goep_cid);
184     pos += 2;
185     btstack_assert(pos == sizeof(event));
186     callback(HCI_EVENT_PACKET, goep_cid, &event[0], pos);
187 }
188 
189 static inline void goep_server_emit_can_send_now_event(goep_server_connection_t * connection){
190     uint8_t event[5];
191     uint16_t pos = 0;
192     event[pos++] = HCI_EVENT_GOEP_META;
193     event[pos++] = 5 - 3;
194     event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW;
195     little_endian_store_16(event,pos,connection->goep_cid);
196     pos += 2;
197     btstack_assert(pos == sizeof(event));
198     connection->callback(HCI_EVENT_PACKET, connection->goep_cid, &event[0], pos);
199 }
200 
201 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){
202 
203     uint16_t goep_cid = context->goep_cid;
204     btstack_packet_handler_t packet_handler = context->callback;
205 
206     if (status) {
207         log_info("goep_client: open failed, status %u", status);
208         btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) context);
209         btstack_memory_goep_server_connection_free(context);
210     } else {
211         // context->bearer_mtu = mtu;
212         context->state = GOEP_SERVER_CONNECTED;
213         context->bearer_cid = bearer_cid;
214 #ifdef ENABLE_GOEP_L2CAP
215         if (context->type == GOEP_CONNECTION_L2CAP){
216             bearer_mtu = btstack_min(bearer_mtu, sizeof(goep_server_l2cap_packet_buffer));
217         }
218 #endif
219         context->bearer_mtu = bearer_mtu;
220         log_info("goep_server: connection opened. cid %u, max frame size %u", context->bearer_cid, bearer_mtu);
221     }
222 
223     goep_server_emit_connection_opened(packet_handler, goep_cid, addr, con_handle, status);
224 }
225 
226 static void goep_server_handle_connection_closed(goep_server_connection_t * goep_connection){
227     uint16_t goep_cid = goep_connection->goep_cid;
228     btstack_packet_handler_t packet_handler = goep_connection->callback;
229 
230     btstack_linked_list_remove(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
231     btstack_memory_goep_server_connection_free(goep_connection);
232 
233     goep_server_emit_connection_closed(packet_handler, goep_cid);
234 }
235 
236 #ifdef ENABLE_GOEP_L2CAP
237 static void goep_server_packet_handler_l2cap(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
238     UNUSED(channel);
239     UNUSED(size);
240 
241     bd_addr_t event_addr;
242     uint16_t l2cap_psm;
243     uint16_t l2cap_cid;
244     goep_server_connection_t * goep_connection;
245     goep_server_service_t *    goep_service;
246 
247     switch (packet_type){
248         case HCI_EVENT_PACKET:
249             switch (hci_event_packet_get_type(packet)) {
250                 case L2CAP_EVENT_INCOMING_CONNECTION:
251                     l2cap_psm = l2cap_event_incoming_connection_get_psm(packet);
252                     l2cap_cid  = l2cap_event_incoming_connection_get_local_cid(packet);
253                     goep_service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
254                     if (!goep_service){
255                         l2cap_decline_connection(l2cap_cid);
256                         break;
257                     }
258 
259                     // alloc structure
260                     goep_connection = btstack_memory_goep_server_connection_get();
261                     if (!goep_connection){
262                         l2cap_decline_connection(l2cap_cid);
263                         break;
264                     }
265 
266                     // setup connection
267                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
268                     goep_connection->bearer_cid = l2cap_cid;
269                     goep_connection->callback   = goep_service->callback;
270                     goep_connection->type       = GOEP_CONNECTION_L2CAP;
271                     goep_connection->state      = GOEP_SERVER_W4_ACCEPT_REJECT;
272                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
273 
274                     // notify user
275                     l2cap_event_incoming_connection_get_address(packet, event_addr);
276                     goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr,
277                                                          l2cap_event_incoming_connection_get_handle(packet));
278                     break;
279 
280                 case L2CAP_EVENT_CHANNEL_OPENED:
281                     l2cap_cid = l2cap_event_channel_opened_get_local_cid(packet);
282                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
283                     btstack_assert(goep_connection != NULL);
284                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
285                     l2cap_event_channel_opened_get_address(packet, event_addr);
286                     goep_server_handle_connection_opened(goep_connection, event_addr,
287                                                          l2cap_event_channel_opened_get_handle(packet),
288                                                          l2cap_event_channel_opened_get_status(packet),
289                                                          l2cap_cid,
290                                                          l2cap_event_channel_opened_get_remote_mtu(packet) );
291                     return;
292                 case L2CAP_EVENT_CAN_SEND_NOW:
293                     l2cap_cid = l2cap_event_can_send_now_get_local_cid(packet);
294                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
295                     btstack_assert(goep_connection != NULL);
296                     goep_server_emit_can_send_now_event(goep_connection);
297                     break;
298                 case L2CAP_EVENT_CHANNEL_CLOSED:
299                     l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet);
300                     goep_connection = goep_server_get_connection_for_l2cap_cid(l2cap_cid);
301                     btstack_assert(goep_connection != NULL);
302                     goep_server_handle_connection_closed(goep_connection);
303                     break;
304                 default:
305                     break;
306             }
307             break;
308         case L2CAP_DATA_PACKET:
309             goep_connection = goep_server_get_connection_for_l2cap_cid(channel);
310             btstack_assert(goep_connection != NULL);
311             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
312             break;
313         default:
314             break;
315     }
316 }
317 #endif
318 
319 static void goep_server_packet_handler_rfcomm(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
320     UNUSED(channel);
321     UNUSED(size);
322 
323     bd_addr_t event_addr;
324     uint8_t  rfcomm_channel;
325     uint16_t rfcomm_cid;
326     goep_server_service_t    * goep_service;
327     goep_server_connection_t * goep_connection;
328 
329     switch (packet_type){
330         case HCI_EVENT_PACKET:
331             switch (hci_event_packet_get_type(packet)) {
332                 case RFCOMM_EVENT_INCOMING_CONNECTION:
333                     rfcomm_channel = rfcomm_event_incoming_connection_get_server_channel(packet);
334                     rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
335 
336                     goep_service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
337                     if (!goep_service){
338                         rfcomm_decline_connection(rfcomm_cid);
339                         break;
340                     }
341 
342                     // alloc structure
343                     goep_connection = btstack_memory_goep_server_connection_get();
344                     if (!goep_connection){
345                         rfcomm_decline_connection(rfcomm_cid);
346                         break;
347                     }
348 
349                     // setup connection
350                     goep_connection->goep_cid   = goep_server_get_next_goep_cid();
351                     goep_connection->bearer_cid = rfcomm_cid;
352                     goep_connection->callback   = goep_service->callback;
353                     goep_connection->type       = GOEP_CONNECTION_RFCOMM;
354                     goep_connection->state      = GOEP_SERVER_W4_ACCEPT_REJECT;
355                     btstack_linked_list_add(&goep_server_connections, (btstack_linked_item_t *) goep_connection);
356 
357                     // notify user
358                     rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
359                     goep_server_emit_incoming_connection(goep_service->callback, goep_connection->goep_cid, event_addr,
360                                                          rfcomm_event_incoming_connection_get_con_handle(packet));
361                     break;
362 
363                 case RFCOMM_EVENT_CHANNEL_OPENED:
364                     rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
365                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
366                     btstack_assert(goep_connection != NULL);
367                     btstack_assert(goep_connection->state == GOEP_SERVER_W4_CONNECTED);
368                     rfcomm_event_channel_opened_get_bd_addr(packet, event_addr);
369                     goep_server_handle_connection_opened(goep_connection, event_addr,
370                                                          rfcomm_event_channel_opened_get_con_handle(packet),
371                                                          rfcomm_event_channel_opened_get_status(packet),
372                                                          rfcomm_cid,
373                                                          rfcomm_event_channel_opened_get_max_frame_size(packet) );
374                     break;
375 
376                 case RFCOMM_EVENT_CAN_SEND_NOW:
377                     rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
378                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
379                     btstack_assert(goep_connection != NULL);
380                     goep_server_emit_can_send_now_event(goep_connection);
381                     break;
382 
383                 case RFCOMM_EVENT_CHANNEL_CLOSED:
384                     rfcomm_cid = rfcomm_event_channel_closed_get_rfcomm_cid(packet);
385                     goep_connection = goep_server_get_connection_for_rfcomm_cid(rfcomm_cid);
386                     btstack_assert(goep_connection != NULL);
387                     goep_server_handle_connection_closed(goep_connection);
388                     break;
389 
390                 default:
391                     break;
392             }
393             break;
394 
395         case RFCOMM_DATA_PACKET:
396             goep_connection = goep_server_get_connection_for_rfcomm_cid(channel);
397             btstack_assert(goep_connection != NULL);
398             goep_connection->callback(GOEP_DATA_PACKET, goep_connection->goep_cid, packet, size);
399             break;
400 
401         default:
402             break;
403     }
404 }
405 
406 void goep_server_init(void){
407 }
408 
409 uint8_t goep_server_register_service(btstack_packet_handler_t callback, uint8_t rfcomm_channel, uint16_t rfcomm_max_frame_size,
410                 uint16_t l2cap_psm, uint16_t l2cap_mtu, gap_security_level_t security_level){
411 
412     log_info("rfcomm_channel 0x%02x rfcomm_max_frame_size %u l2cap_psm 0x%02x l2cap_mtu %u",
413              rfcomm_channel, rfcomm_max_frame_size, l2cap_psm, l2cap_mtu);
414 
415     // check if service is already registered
416     goep_server_service_t * service;
417     service = goep_server_get_service_for_rfcomm_channel(rfcomm_channel);
418     if (service != NULL) {
419         return RFCOMM_CHANNEL_ALREADY_REGISTERED;
420     }
421 
422 #ifdef ENABLE_GOEP_L2CAP
423     if (l2cap_psm != 0){
424         service = goep_server_get_service_for_l2cap_psm(l2cap_psm);
425         if (service != NULL) {
426             return L2CAP_SERVICE_ALREADY_REGISTERED;
427         }
428     }
429 #endif
430 
431     // alloc structure
432     service = btstack_memory_goep_server_service_get();
433     if (service == NULL) {
434         return BTSTACK_MEMORY_ALLOC_FAILED;
435     }
436 
437     // fill in
438     service->callback = callback;
439     service->rfcomm_channel = rfcomm_channel;
440     service->l2cap_psm = l2cap_psm;
441 
442     uint8_t status = ERROR_CODE_SUCCESS;
443     bool rfcomm_registered = false;
444 
445 #ifdef ENABLE_GOEP_L2CAP
446     bool l2cap_registered = false;
447     // register with L2CAP
448     if (l2cap_psm != 0){
449         status = l2cap_register_service(goep_server_packet_handler_l2cap, l2cap_psm, l2cap_mtu, security_level);
450         if (status == ERROR_CODE_SUCCESS){
451             l2cap_registered = true;
452         }
453     }
454 #endif
455 
456     // register with RFCOMM
457     if (status == ERROR_CODE_SUCCESS){
458         status = rfcomm_register_service(goep_server_packet_handler_rfcomm, rfcomm_channel, rfcomm_max_frame_size);
459         if (status == ERROR_CODE_SUCCESS){
460             rfcomm_registered = true;
461         }
462     }
463 
464     // add service on success
465     if (status == ERROR_CODE_SUCCESS){
466         btstack_linked_list_add(&goep_server_services, (btstack_linked_item_t *) service);
467         return ERROR_CODE_SUCCESS;
468     }
469 
470     // unrestore otherwise
471     btstack_memory_goep_server_service_free(service);
472 #ifdef ENABLE_GOEP_L2CAP
473     if (l2cap_registered){
474         l2cap_unregister_service(l2cap_psm);
475     }
476 #endif
477     if (rfcomm_registered){
478         rfcomm_unregister_service(rfcomm_channel);
479     }
480     return status;
481 }
482 
483 uint8_t goep_server_accept_connection(uint16_t goep_cid){
484     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
485     if (connection == NULL){
486         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
487     }
488     if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){
489         return ERROR_CODE_COMMAND_DISALLOWED;
490     }
491     connection->state = GOEP_SERVER_W4_CONNECTED;
492 #ifdef ENABLE_GOEP_L2CAP
493     if (connection->type == GOEP_CONNECTION_L2CAP){
494         return l2cap_ertm_accept_connection(connection->bearer_cid, &ertm_config, connection->ertm_buffer, GOEP_SERVER_ERTM_BUFFER);
495     }
496 #endif
497     return rfcomm_accept_connection(connection->bearer_cid);
498 }
499 
500 uint8_t goep_server_decline_connection(uint16_t goep_cid){
501     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
502     if (connection == NULL){
503         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
504     }
505     connection->state = GOEP_SERVER_W4_CONNECTED;
506     if (connection->state != GOEP_SERVER_W4_ACCEPT_REJECT){
507         return ERROR_CODE_COMMAND_DISALLOWED;
508     }
509 #ifdef ENABLE_GOEP_L2CAP
510     if (connection->type == GOEP_CONNECTION_L2CAP){
511         l2cap_decline_connection(connection->bearer_cid);
512         return ERROR_CODE_SUCCESS;
513     }
514 #endif
515     return rfcomm_decline_connection(connection->bearer_cid);
516 }
517 
518 uint8_t goep_server_request_can_send_now(uint16_t goep_cid){
519     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
520     if (connection == NULL){
521         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
522     }
523 
524     switch (connection->type){
525         case GOEP_CONNECTION_RFCOMM:
526             rfcomm_request_can_send_now_event(connection->bearer_cid);
527             break;
528 #ifdef ENABLE_GOEP_L2CAP
529         case GOEP_CONNECTION_L2CAP:
530             l2cap_request_can_send_now_event(connection->bearer_cid);
531             break;
532 #endif
533         default:
534             btstack_unreachable();
535             break;
536     }
537     return ERROR_CODE_SUCCESS;
538 }
539 
540 static uint8_t * goep_server_get_outgoing_buffer(goep_server_connection_t * connection){
541     switch (connection->type){
542 #ifdef ENABLE_GOEP_L2CAP
543         case GOEP_CONNECTION_L2CAP:
544             return goep_server_l2cap_packet_buffer;
545 #endif
546         case GOEP_CONNECTION_RFCOMM:
547             return rfcomm_get_outgoing_buffer();
548         default:
549             btstack_unreachable();
550             return NULL;
551     }
552 }
553 
554 static uint16_t goep_server_get_outgoing_buffer_len(goep_server_connection_t * connection){
555     return connection->bearer_mtu;
556 }
557 
558 static void goep_server_packet_init(goep_server_connection_t * connection){
559     switch (connection->type){
560 #ifdef ENABLE_GOEP_L2CAP
561         case GOEP_CONNECTION_L2CAP:
562             break;
563 #endif
564         case GOEP_CONNECTION_RFCOMM:
565             rfcomm_reserve_packet_buffer();
566             break;
567         default:
568             btstack_unreachable();
569             break;
570     }
571 }
572 
573 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){
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     goep_server_packet_init(connection);
580 
581     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU
582     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, connection->bearer_mtu);
583 
584     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
585     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
586     return obex_message_builder_response_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length, (uint32_t) goep_cid);
587 }
588 
589 uint8_t goep_server_response_create_general(uint16_t goep_cid, uint8_t opcode){
590     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
591     if (connection == NULL) {
592         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
593     }
594     goep_server_packet_init(connection);
595     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
596     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
597     return obex_message_builder_response_create_general(buffer, buffer_len, opcode);
598 }
599 
600 uint8_t goep_server_header_add_end_of_body(uint16_t goep_cid, const uint8_t * end_of_body, uint16_t length){
601     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
602     if (connection == NULL) {
603         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
604     }
605 
606     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
607     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
608     return obex_message_builder_body_add_static(buffer, buffer_len, end_of_body, length);
609 }
610 
611 uint8_t goep_server_header_add_who(uint16_t goep_cid, const uint8_t * target){
612     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
613     if (connection == NULL) {
614         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
615     }
616 
617     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
618     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
619     return obex_message_builder_header_add_who(buffer, buffer_len, target);
620 }
621 
622 uint8_t goep_server_header_add_srm_enable(uint16_t goep_cid){
623     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
624     if (connection == NULL) {
625         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
626     }
627 
628     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
629     uint16_t buffer_len = goep_server_get_outgoing_buffer_len(connection);
630     return obex_message_builder_header_add_srm_enable(buffer, buffer_len);
631 }
632 
633 uint8_t goep_server_execute(uint16_t goep_cid){
634     goep_server_connection_t * connection = goep_server_get_connection_for_goep_cid(goep_cid);
635     if (connection == NULL) {
636         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
637     }
638 
639     uint8_t * buffer = goep_server_get_outgoing_buffer(connection);
640     uint16_t pos = big_endian_read_16(buffer, 1);
641     switch (connection->type) {
642 #ifdef ENABLE_GOEP_L2CAP
643         case GOEP_CONNECTION_L2CAP:
644             return l2cap_send(connection->bearer_cid, buffer, pos);
645             break;
646 #endif
647         case GOEP_CONNECTION_RFCOMM:
648             return rfcomm_send_prepared(connection->bearer_cid, pos);
649             break;
650         default:
651             btstack_unreachable();
652             return ERROR_CODE_SUCCESS;
653     }
654 }
655 
656 void goep_server_deinit(void){
657     goep_server_cid_counter = 0;
658     goep_server_services = NULL;
659 }
660