mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-29 21:32:38 +00:00
avrcp_controller: reassemble fragmented AVCTP packets
This commit is contained in:
parent
ce66cc7ade
commit
c3b8c0a2ef
@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
- AVRCP: new field `button_pressed` in `AVRCP_SUBEVENT_OPERATION`
|
||||
- AVRCP: `AVRCP_SUBEVENT_OPERATION` emitted for button release
|
||||
- AVRCP Controller: avrcp_controller_start_press_and_hold_cmd helps to support device buttons
|
||||
- AVRCP Controller: reassemble fragmented AVCTP packets
|
||||
- AVDTP: `avdtp_register_media_config_validator` allows to validate media codec configuration
|
||||
- A2DP Source: `ENABLE_A2DP_SOURCE_EXPLICIT_CONFIG` disables auto config. Requires call to `a2dp_source_set_config_{CODEC}'
|
||||
|
||||
|
@ -111,6 +111,14 @@ typedef enum {
|
||||
AVRCP_END_PACKET
|
||||
} avrcp_packet_type_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
AVCTP_SINGLE_PACKET= 0,
|
||||
AVCTP_START_PACKET ,
|
||||
AVCTP_CONTINUE_PACKET ,
|
||||
AVCTP_END_PACKET
|
||||
} avctp_packet_type_t;
|
||||
|
||||
typedef enum {
|
||||
AVRCP_COMMAND_FRAME = 0,
|
||||
AVRCP_RESPONSE_FRAME
|
||||
@ -375,7 +383,7 @@ typedef struct {
|
||||
avctp_connection_state_t state;
|
||||
bool wait_to_send;
|
||||
uint8_t transaction_label;
|
||||
// used for AVCTP fragmentation
|
||||
// used for fragmentation
|
||||
uint8_t num_packets;
|
||||
uint16_t bytes_to_send;
|
||||
|
||||
@ -555,6 +563,12 @@ typedef struct {
|
||||
uint8_t num_received_fragments;
|
||||
|
||||
uint8_t accept_response;
|
||||
|
||||
#ifdef ENABLE_AVCTP_FRAGMENTATION
|
||||
uint16_t avctp_reassembly_size;
|
||||
uint8_t avctp_reassembly_buffer[200];
|
||||
#endif
|
||||
|
||||
} avrcp_connection_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -690,33 +690,92 @@ avrcp_controller_handle_notification(avrcp_connection_t *connection, avrcp_comma
|
||||
avrcp_controller_emit_notification_for_event_id(connection->avrcp_cid, event_id, ctype, payload + pos, size - pos);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_AVCTP_FRAGMENTATION
|
||||
static void avctp_reassemble_message(avrcp_connection_t * connection, avctp_packet_type_t packet_type, uint8_t *packet, uint16_t size){
|
||||
// after header (transaction label and packet type)
|
||||
uint16_t pos;
|
||||
uint16_t bytes_to_store;
|
||||
|
||||
switch (packet_type){
|
||||
case AVCTP_START_PACKET:
|
||||
if (size < 2) return;
|
||||
|
||||
// store header
|
||||
pos = 0;
|
||||
connection->avctp_reassembly_buffer[pos] = packet[pos];
|
||||
pos++;
|
||||
connection->avctp_reassembly_size = pos;
|
||||
|
||||
// NOTE: num packets not needed for reassembly, ignoring it does not pose security risk -> no need to store it
|
||||
pos++;
|
||||
|
||||
// PID in reassembled packet is at offset 1, it will be read later after the avctp_reassemble_message with AVCTP_END_PACKET is called
|
||||
|
||||
bytes_to_store = btstack_min(size - pos, sizeof(connection->avctp_reassembly_buffer) - connection->avctp_reassembly_size);
|
||||
memcpy(&connection->avctp_reassembly_buffer[connection->avctp_reassembly_size], &packet[pos], bytes_to_store);
|
||||
connection->avctp_reassembly_size += bytes_to_store;
|
||||
break;
|
||||
|
||||
case AVCTP_CONTINUE_PACKET:
|
||||
case AVCTP_END_PACKET:
|
||||
if (size < 1) return;
|
||||
|
||||
// store remaining data, ignore header
|
||||
pos = 1;
|
||||
bytes_to_store = btstack_min(size - pos, sizeof(connection->avctp_reassembly_buffer) - connection->avctp_reassembly_size);
|
||||
memcpy(&connection->avctp_reassembly_buffer[connection->avctp_reassembly_size], &packet[pos], bytes_to_store);
|
||||
connection->avctp_reassembly_size += bytes_to_store;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
|
||||
if (size < 6u) return;
|
||||
|
||||
uint8_t pdu_id;
|
||||
uint8_t vendor_dependent_packet_type;
|
||||
avrcp_packet_type_t vendor_dependent_packet_type;
|
||||
|
||||
connection->last_confirmed_transaction_id = packet[0] >> 4;
|
||||
uint16_t pos = 0;
|
||||
connection->last_confirmed_transaction_id = packet[pos] >> 4;
|
||||
avrcp_frame_type_t frame_type = (avrcp_frame_type_t)((packet[pos] >> 1) & 0x01);
|
||||
avctp_packet_type_t packet_type = (avctp_packet_type_t)((packet[pos] >> 2) & 0x03);
|
||||
pos++;
|
||||
|
||||
avrcp_frame_type_t frame_type = (avrcp_frame_type_t)((packet[0] >> 1) & 0x01);
|
||||
if (frame_type != AVRCP_RESPONSE_FRAME) return;
|
||||
|
||||
avrcp_packet_type_t packet_type = (avrcp_packet_type_t)((packet[0] >> 2) & 0x03);
|
||||
|
||||
switch (packet_type){
|
||||
case AVRCP_SINGLE_PACKET:
|
||||
case AVCTP_SINGLE_PACKET:
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_AVCTP_FRAGMENTATION
|
||||
case AVCTP_START_PACKET:
|
||||
case AVCTP_CONTINUE_PACKET:
|
||||
avctp_reassemble_message(connection, packet_type, packet, size);
|
||||
return;
|
||||
|
||||
case AVCTP_END_PACKET:
|
||||
avctp_reassemble_message(connection, packet_type, packet, size);
|
||||
|
||||
packet = connection->avctp_reassembly_buffer;
|
||||
size = connection->avctp_reassembly_size;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
log_info("Fragmentation is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t pos = 3;
|
||||
pos += 2; // PID
|
||||
|
||||
avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++];
|
||||
|
||||
#ifdef ENABLE_LOG_INFO
|
||||
uint8_t byte_value = packet[pos];
|
||||
avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (byte_value >> 3);
|
||||
avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07);
|
||||
avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07);
|
||||
#endif
|
||||
pos++;
|
||||
|
||||
@ -763,8 +822,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
vendor_dependent_packet_type = (avrcp_packet_type_t)(packet[pos++] & 0x03);
|
||||
param_length = big_endian_read_16(packet, pos);
|
||||
pos += 2;
|
||||
log_info("operands length %d, remaining size %d", param_length, size - pos);
|
||||
|
||||
|
||||
if ((size - pos) < param_length) return;
|
||||
|
||||
// handle asynchronous notifications, without changing state
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define ENABLE_LE_PERIPHERAL
|
||||
#define ENABLE_LE_SIGNED_WRITE
|
||||
#define ENABLE_SDP_EXTRA_QUERIES
|
||||
#define ENABLE_AVCTP_FRAGMENTATION
|
||||
|
||||
// BTstack configuration. buffers, sizes, ...
|
||||
#define HCI_ACL_PAYLOAD_SIZE 1024
|
||||
|
Loading…
x
Reference in New Issue
Block a user