h5: fix corruption of outgoing fragmented ACL packets.

This commit is contained in:
Matthias Ringwald 2017-03-03 12:23:58 +01:00
parent f7d194e559
commit c65ae2a0ed
2 changed files with 33 additions and 24 deletions

View File

@ -94,9 +94,8 @@ extern "C" {
// additional pre- and post-packet buffer for packets to Bluetooth module
// - pre-buffer used for HCI Transport H4 variants
// - post-buffer used for HCI Transport H5
#define HCI_OUTGOING_PRE_BUFFER_SIZE 1
#define HCI_OUTGOING_POST_BUFFER_SIZE 2
#define HCI_OUTGOING_PRE_BUFFER_SIZE 1
#define HCI_OUTGOING_POST_BUFFER_SIZE 0
// BNEP may uncompress the IP Header by 16 bytes
#ifndef HCI_INCOMING_PRE_BUFFER_SIZE

View File

@ -111,9 +111,11 @@ static const uint8_t link_control_sleep[] = { 0x07, 0x78};
// incoming pre-bufffer + 4 bytes H5 header + max(acl header + acl payload, event header + event data) + 2 bytes opt CRC
static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 6 + HCI_PACKET_BUFFER_SIZE];
// outgoing slip encoded buffer. +1 to assert that last SOF fits in buffer
static uint8_t slip_outgoing_buffer[LINK_SLIP_TX_CHUNK_LEN+1];
static int slip_write_active;
// outgoing slip encoded buffer. +4 to assert that DIC fits in buffer. +1 to assert that last SOF fits in buffer.
static uint8_t slip_outgoing_buffer[LINK_SLIP_TX_CHUNK_LEN+4+1];
static uint16_t slip_outgoing_dic;
static uint16_t slip_outgoing_dic_present;
static int slip_write_active;
// H5 Link State
static hci_transport_link_state_t link_state;
@ -219,7 +221,18 @@ static void hci_transport_slip_encode_chunk_and_send(int pos){
while (btstack_slip_encoder_has_data() & (pos < LINK_SLIP_TX_CHUNK_LEN)) {
slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte();
}
if (!btstack_slip_encoder_has_data()){
// Payload encoded, append DIC if present.
// note: slip_outgoing_buffer is guaranteed to be big enough to add DIC + SOF after LINK_SLIP_TX_CHUNK_LEN
if (slip_outgoing_dic_present){
uint8_t dic_buffer[2];
big_endian_store_16(dic_buffer, 0, slip_outgoing_dic);
btstack_slip_encoder_start(dic_buffer, 2);
while (btstack_slip_encoder_has_data()){
slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte();
}
}
// Start of Frame
slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF;
}
@ -232,11 +245,15 @@ static inline void hci_transport_slip_send_next_chunk(void){
hci_transport_slip_encode_chunk_and_send(0);
}
// format: 0xc0 HEADER PACKET 0xc0
// format: 0xc0 HEADER PACKET [DIC] 0xc0
// @param uint8_t header[4]
static void hci_transport_slip_send_frame(const uint8_t * header, const uint8_t * packet, uint16_t packet_size){
static void hci_transport_slip_send_frame(const uint8_t * header, const uint8_t * packet, uint16_t packet_size, uint16_t data_integrity_check){
int pos = 0;
// store data integrity check info
slip_outgoing_dic = data_integrity_check;
slip_outgoing_dic_present = header[0] & 0x40;
// Start of Frame
slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF;
@ -279,18 +296,13 @@ static void hci_transport_link_calc_header(uint8_t * header,
static void hci_transport_link_send_control(const uint8_t * message, int message_len){
uint8_t header[4];
hci_transport_link_calc_header(header, 0, 0, link_peer_supports_data_integrity_check, 0, LINK_CONTROL_PACKET_TYPE, message_len);
uint8_t message_with_dic[LINK_CONTROL_MAX_LEN + 2];
uint16_t data_integrity_check = 0;
if (link_peer_supports_data_integrity_check){
// append data integrity check value / need to copy control message
memcpy(message_with_dic, message, message_len);
uint16_t dic = crc16_calc_for_slip_frame(header, message, message_len);
big_endian_store_16(message_with_dic, message_len, dic);
message_len += 2;
message = message_with_dic;
data_integrity_check = crc16_calc_for_slip_frame(header, message, message_len);
}
log_info("hci_transport_link_send_control: size %u, append dic %u", message_len, link_peer_supports_data_integrity_check);
log_info_hexdump(message, message_len);
hci_transport_slip_send_frame(header, message, message_len);
hci_transport_slip_send_frame(header, message, message_len, data_integrity_check);
}
static void hci_transport_link_send_sync(void){
@ -333,27 +345,25 @@ static void hci_transport_link_send_queued_packet(void){
uint8_t header[4];
hci_transport_link_calc_header(header, link_seq_nr, link_ack_nr, link_peer_supports_data_integrity_check, 1, hci_packet_type, hci_packet_size);
uint16_t dic = 0;
uint16_t data_integrity_check = 0;
if (link_peer_supports_data_integrity_check){
// append data integrity check value
dic = crc16_calc_for_slip_frame(header, hci_packet, hci_packet_size);
big_endian_store_16(hci_packet, hci_packet_size, dic);
hci_packet_size += 2;
data_integrity_check = crc16_calc_for_slip_frame(header, hci_packet, hci_packet_size);
}
log_info("hci_transport_link_send_queued_packet: seq %u, ack %u, size %u, append dic %u", link_seq_nr, link_ack_nr, hci_packet_size, link_peer_supports_data_integrity_check);
log_info("hci_transport_link_send_queued_packet: seq %u, ack %u, size %u. Append dic %u, dic = 0x%04x", link_seq_nr, link_ack_nr, hci_packet_size, link_peer_supports_data_integrity_check, data_integrity_check);
log_info_hexdump(hci_packet, hci_packet_size);
hci_transport_slip_send_frame(header, hci_packet, hci_packet_size);
hci_transport_slip_send_frame(header, hci_packet, hci_packet_size, data_integrity_check);
// reset inactvitiy timer
hci_transport_inactivity_timer_set();
}
static void hci_transport_link_send_ack_packet(void){
// Pure ACK package is without DIC as there is no payload either
log_info("link: send ack %u", link_ack_nr);
uint8_t header[4];
hci_transport_link_calc_header(header, 0, link_ack_nr, 0, 0, LINK_ACKNOWLEDGEMENT_TYPE, 0);
hci_transport_slip_send_frame(header, NULL, 0);
hci_transport_slip_send_frame(header, NULL, 0, 0);
}
static void hci_transport_link_run(void){