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
This commit is contained in:
Scott Shawcroft 2021-10-28 10:57:16 -07:00
parent a8b69f2852
commit bf0bef9684
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
2 changed files with 26 additions and 8 deletions

View File

@ -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 &&

View File

@ -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;
}