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