From bf0bef968406f622cbdb6105f0870dc7e49038bd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 28 Oct 2021 10:57:16 -0700 Subject: [PATCH] Split listdir entries across two packets when the MTU of the BLE connection is smaller than the 28 bytes of the header. (The smallest possible MTU is 20.) Fixes #5511 --- ports/nrf/common-hal/_bleio/PacketBuffer.c | 9 +++++--- supervisor/shared/bluetooth/file_transfer.c | 25 ++++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ports/nrf/common-hal/_bleio/PacketBuffer.c b/ports/nrf/common-hal/_bleio/PacketBuffer.c index 6f53fb96aa..f7d35cbdb5 100644 --- a/ports/nrf/common-hal/_bleio/PacketBuffer.c +++ b/ports/nrf/common-hal/_bleio/PacketBuffer.c @@ -356,9 +356,12 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, c if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { return -1; } - uint16_t outgoing_packet_length = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self); + mp_int_t outgoing_packet_length = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self); + if (outgoing_packet_length < 0) { + return -1; + } - uint16_t total_len = len + header_len; + mp_int_t total_len = len + header_len; if (total_len > outgoing_packet_length) { // Supplied data will not fit in a single BLE packet. mp_raise_ValueError_varg(translate("Total data to write is larger than %q"), MP_QSTR_outgoing_packet_length); @@ -369,7 +372,7 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, c } outgoing_packet_length = MIN(outgoing_packet_length, self->max_packet_size); - if (len + self->pending_size > outgoing_packet_length) { + if (len + self->pending_size > (size_t)outgoing_packet_length) { // No room to append len bytes to packet. Wait until we get a free buffer, // and keep checking that we haven't been disconnected. while (self->pending_size != 0 && diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c index de05c7fbf9..d1841c87d0 100644 --- a/supervisor/shared/bluetooth/file_transfer.c +++ b/supervisor/shared/bluetooth/file_transfer.c @@ -525,18 +525,33 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) { return ANY_COMMAND; } +STATIC void send_listdir_entry_header(const struct listdir_entry *entry, mp_int_t max_packet_size) { + mp_int_t response_size = sizeof(struct listdir_entry); + if (max_packet_size >= response_size) { + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, response_size, NULL, 0); + return; + } + // Split into 16 + 12 size packets to fit into 20 byte minimum packet size. + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, 16, NULL, 0); + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, ((const uint8_t *)entry) + 16, response_size - 16, NULL, 0); +} + STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { const struct listdir_command *command = (struct listdir_command *)raw_buf; struct listdir_entry *entry = (struct listdir_entry *)raw_buf; size_t header_size = sizeof(struct listdir_command); - size_t response_size = sizeof(struct listdir_entry); + mp_int_t max_packet_size = common_hal_bleio_packet_buffer_get_outgoing_packet_length(&_transfer_packet_buffer); + if (max_packet_size < 0) { + // -1 means we're disconnected + return ANY_COMMAND; + } // We reuse the command buffer so that we can produce long packets without // making the stack large. if (command->path_length > (COMMAND_SIZE - header_size - 1)) { // -1 for the null we'll write // TODO: throw away any more packets of path. entry->command = LISTDIR_ENTRY; entry->status = STATUS_ERROR; - common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, response_size, NULL, 0); + send_listdir_entry_header(entry, max_packet_size); return ANY_COMMAND; } // We need to receive another packet to have the full path. @@ -560,7 +575,7 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { if (res != FR_OK) { entry->status = STATUS_ERROR_NO_FILE; - common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, response_size, NULL, 0); + send_listdir_entry_header(entry, max_packet_size); return ANY_COMMAND; } FILINFO file_info; @@ -594,7 +609,7 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { size_t name_length = strlen(file_info.fname); entry->path_length = name_length; - common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, response_size, NULL, 0); + send_listdir_entry_header(entry, max_packet_size); size_t fn_offset = 0; while (fn_offset < name_length) { size_t fn_size = MIN(name_length - fn_offset, 4); @@ -607,7 +622,7 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { entry->entry_number = entry->entry_count; entry->flags = 0; entry->file_size = 0; - common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)entry, response_size, NULL, 0); + send_listdir_entry_header(entry, max_packet_size); return ANY_COMMAND; }