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