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 // additional pre- and post-packet buffer for packets to Bluetooth module
// - pre-buffer used for HCI Transport H4 variants // - 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_PRE_BUFFER_SIZE 1
#define HCI_OUTGOING_POST_BUFFER_SIZE 2 #define HCI_OUTGOING_POST_BUFFER_SIZE 0
// BNEP may uncompress the IP Header by 16 bytes // BNEP may uncompress the IP Header by 16 bytes
#ifndef HCI_INCOMING_PRE_BUFFER_SIZE #ifndef HCI_INCOMING_PRE_BUFFER_SIZE

View File

@ -111,8 +111,10 @@ 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 // 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]; 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 // 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+1]; 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; static int slip_write_active;
// H5 Link State // H5 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)) { while (btstack_slip_encoder_has_data() & (pos < LINK_SLIP_TX_CHUNK_LEN)) {
slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte(); slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte();
} }
if (!btstack_slip_encoder_has_data()){ 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 // Start of Frame
slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF; slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF;
} }
@ -232,12 +245,16 @@ static inline void hci_transport_slip_send_next_chunk(void){
hci_transport_slip_encode_chunk_and_send(0); hci_transport_slip_encode_chunk_and_send(0);
} }
// format: 0xc0 HEADER PACKET 0xc0 // format: 0xc0 HEADER PACKET [DIC] 0xc0
// @param uint8_t header[4] // @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; int pos = 0;
// store data integrity check info
slip_outgoing_dic = data_integrity_check;
slip_outgoing_dic_present = header[0] & 0x40;
// Start of Frame // Start of Frame
slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF; 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){ static void hci_transport_link_send_control(const uint8_t * message, int message_len){
uint8_t header[4]; 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); 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){ if (link_peer_supports_data_integrity_check){
// append data integrity check value / need to copy control message data_integrity_check = crc16_calc_for_slip_frame(header, message, message_len);
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;
} }
log_info("hci_transport_link_send_control: size %u, append dic %u", message_len, link_peer_supports_data_integrity_check); 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); 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){ 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]; 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); 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){ if (link_peer_supports_data_integrity_check){
// append data integrity check value data_integrity_check = crc16_calc_for_slip_frame(header, hci_packet, hci_packet_size);
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;
} }
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); 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 // reset inactvitiy timer
hci_transport_inactivity_timer_set(); hci_transport_inactivity_timer_set();
} }
static void hci_transport_link_send_ack_packet(void){ 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); log_info("link: send ack %u", link_ack_nr);
uint8_t header[4]; uint8_t header[4];
hci_transport_link_calc_header(header, 0, link_ack_nr, 0, 0, LINK_ACKNOWLEDGEMENT_TYPE, 0); 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){ static void hci_transport_link_run(void){