l2cap: introduce parameter object l2cap_ertm_config_t for l2cap_create_ertm_channel and l2cap_accept_ertm_connection

This commit is contained in:
Matthias Ringwald 2017-07-25 15:03:09 +02:00
parent 671fb338cc
commit 9c0e62d33a
3 changed files with 70 additions and 60 deletions

View File

@ -394,51 +394,49 @@ static int l2cap_ertm_send_supervisor_frame(l2cap_channel_t * channel, uint16_t
return l2cap_send_prepared(channel->local_cid, 2);
}
static uint8_t l2cap_ertm_validate_local_config(uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
static uint8_t l2cap_ertm_validate_local_config(l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
UNUSED(buffer);
UNUSED(size);
uint8_t result = ERROR_CODE_SUCCESS;
if (max_transmit < 1){
if (ertm_config->max_transmit < 1){
log_error("max_transmit must be >= 1");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
if (retransmission_timeout_ms < 2000){
if (ertm_config->retransmission_timeout_ms < 2000){
log_error("retransmission_timeout_ms must be >= 2000 ms");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
if (monitor_timeout_ms < 12000){
if (ertm_config->monitor_timeout_ms < 12000){
log_error("monitor_timeout_ms must be >= 12000 ms");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
if (local_mtu < 48){
if (ertm_config->local_mtu < 48){
log_error("local_mtu must be >= 48");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
if (num_rx_buffers < 1){
if (ertm_config->num_rx_buffers < 1){
log_error("num_rx_buffers must be >= 1");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
if (num_tx_buffers < 1){
if (ertm_config->num_tx_buffers < 1){
log_error("num_rx_buffers must be >= 1");
result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
}
return result;
}
static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms,
uint16_t monitor_timeout_ms, uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
channel->mode = L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION;
channel->ertm_mandatory = ertm_mandatory;
channel->local_max_transmit = max_transmit;
channel->local_retransmission_timeout_ms = retransmission_timeout_ms;
channel->local_monitor_timeout_ms = monitor_timeout_ms;
channel->local_mtu = local_mtu;
channel->num_rx_buffers = num_rx_buffers;
channel->num_tx_buffers = num_tx_buffers;
channel->ertm_mandatory = ertm_config->ertm_mandatory;
channel->local_max_transmit = ertm_config->max_transmit;
channel->local_retransmission_timeout_ms = ertm_config->retransmission_timeout_ms;
channel->local_monitor_timeout_ms = ertm_config->monitor_timeout_ms;
channel->local_mtu = ertm_config->local_mtu;
channel->num_rx_buffers = ertm_config->num_rx_buffers;
channel->num_tx_buffers = ertm_config->num_tx_buffers;
// align buffer to 16-byte boundary, just in case
int bytes_till_alignment = 16 - (((uintptr_t) buffer) & 0x0f);
@ -448,40 +446,38 @@ static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, int ertm_man
// setup state buffers
uint32_t pos = 0;
channel->rx_packets_state = (l2cap_ertm_rx_packet_state_t *) &buffer[pos];
pos += num_rx_buffers * sizeof(l2cap_ertm_rx_packet_state_t);
pos += ertm_config->num_rx_buffers * sizeof(l2cap_ertm_rx_packet_state_t);
channel->tx_packets_state = (l2cap_ertm_tx_packet_state_t *) &buffer[pos];
pos += num_tx_buffers * sizeof(l2cap_ertm_tx_packet_state_t);
pos += ertm_config->num_tx_buffers * sizeof(l2cap_ertm_tx_packet_state_t);
// setup reassembly buffer
channel->reassembly_buffer = &buffer[pos];
pos += local_mtu;
pos += ertm_config->local_mtu;
// divide rest of data equally
channel->local_mps = (size - pos) / (num_rx_buffers + num_tx_buffers);
channel->local_mps = (size - pos) / (ertm_config->num_rx_buffers + ertm_config->num_tx_buffers);
log_info("Local MPS: %u", channel->local_mtu);
channel->rx_packets_data = &buffer[pos];
pos += num_rx_buffers * channel->local_mtu;
pos += ertm_config->num_rx_buffers * channel->local_mtu;
channel->tx_packets_data = &buffer[pos];
}
uint8_t l2cap_create_ertm_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid){
l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid){
log_info("L2CAP_CREATE_CHANNEL addr %s, psm 0x%x, local mtu %u", bd_addr_to_str(address), psm, local_mtu);
log_info("L2CAP_CREATE_ERTM_CHANNEL addr %s, psm 0x%x, local mtu %u", bd_addr_to_str(address), psm, ertm_config->local_mtu);
// validate local config
uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
uint8_t result = l2cap_ertm_validate_local_config(ertm_config, buffer, size);
if (result) return result;
l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0);
l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, ertm_config->local_mtu, LEVEL_0);
if (!channel) {
return BTSTACK_MEMORY_ALLOC_FAILED;
}
// configure ERTM
l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms,
local_mtu, monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
l2cap_ertm_configure_channel(channel, ertm_config, buffer, size);
// add to connections list
btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
@ -514,8 +510,7 @@ static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel){
}
}
uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms,
uint16_t monitor_timeout_ms, uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
log_info("L2CAP_ACCEPT_ERTM_CONNECTION local_cid 0x%x", local_cid);
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
@ -525,11 +520,11 @@ uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, int ertm_mandatory, uin
}
// validate local config
uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
uint8_t result = l2cap_ertm_validate_local_config(ertm_config, buffer, size);
if (result) return result;
// configure L2CAP ERTM
l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
l2cap_ertm_configure_channel(channel, ertm_config, buffer, size);
// continue
channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;

View File

@ -129,6 +129,29 @@ typedef struct {
uint8_t retransmission_requested;
} l2cap_ertm_tx_packet_state_t;
typedef struct {
// If not mandatory, the use of ERTM can be decided by the remote
uint8_t ertm_mandatory;
// Number of retransmissions that L2CAP is allowed to try before accepting that a packet and the channel is lost.
uint8_t max_transmit;
// time before retransmission of i-frame / Recommended : 2000 ms (ACL Flush timeout not used)
uint16_t retransmission_timeout_ms;
// time after withc s-frames are sent / Recommended: 12000 ms (ACL Flush timeout not used)
uint16_t monitor_timeout_ms;
// MTU for incoming SDUs
uint16_t local_mtu;
// Number of buffers for outgoing data
uint8_t num_tx_buffers;
// Number of packets that can be received out of order (-> our tx_window size)
uint8_t num_rx_buffers;
} l2cap_ertm_config_t;
// info regarding an actual connection
typedef struct {
@ -382,22 +405,14 @@ uint8_t l2cap_create_channel(btstack_packet_handler_t packet_handler, bd_addr_t
* @param packet_handler
* @param address
* @param psm
* @param ertm_mandatory If not mandatory, the use of ERTM can be decided by the remote
* @param max_transmit Number of retransmissions that L2CAP is allowed to try before accepting that a packet and the channel is lost.
* @param retransmission_timeout_ms Recommended : 2000 ms (ACL Flush timeout not used)
* @param monitor_timeout_ms Recommended: 12000 ms (ACL Flush timeout not used)
* @param local_mtu
* @param num_tx_buffers Number of unacknowledged packets stored in buffer
* @param num_rx_buffers Number of packets that can be received out of order (-> our tx_window size)
* @param ertm_config
* @param buffer to store reassembled rx packet, out-of-order packets and unacknowledged outgoing packets with their tretransmission timers
* @param size of buffer
* @param local_cid
* @return status
*/
uint8_t l2cap_create_ertm_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size,
uint16_t * out_local_cid);
l2cap_ertm_config_t * ertm_contig, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid);
/**
* @brief Disconnects L2CAP channel with given identifier.
@ -431,19 +446,13 @@ void l2cap_accept_connection(uint16_t local_cid);
/**
* @brief Accepts incoming L2CAP connection for Enhanced Retransmission Mode
* @param ertm_mandatory If not mandatory, the use of ERTM can be decided by the remote
* @param max_transmit Number of retransmissions that L2CAP is allowed to try before accepting that a packet and the channel is lost. Recommended: 1
* @param retransmission_timeout_ms Recommended : 2000 ms (ACL Flush timeout not used)
* @param monitor_timeout_ms Recommended: 12000 ms (ACL Flush timeout not used)
* @param local_mtu
* @param num_tx_buffers Number of unacknowledged packets stored in buffer
* @param num_rx_buffers Number of packets that can be received out of order (-> our tx_window size)
* @param local_cid
* @param ertm_config
* @param buffer to store reassembled rx packet, out-of-order packets and unacknowledged outgoing packets with their tretransmission timers
* @param size of buffer
* @return status
*/
uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, int ertm_mandatory, uint8_t max_transmit,
uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms, uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size);
uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, l2cap_ertm_config_t * ertm_contig, uint8_t * buffer, uint32_t size);
/**
* @brief Deny incoming L2CAP connection.

View File

@ -68,12 +68,18 @@ static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x07, 0x32, 0xef};;
static uint16_t handle;
static uint16_t local_cid;
static int l2cap_ertm;
static int l2cap_ertm_mandatory;
static int l2cap_max_transmit = 2; // some tests require > 1
static int l2cap_local_mtu = 144;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static uint8_t ertm_buffer[10000];
static l2cap_ertm_config_t ertm_config = {
0, // ertm mandatory
2, // max transmit, some tests require > 1
2000,
12000,
144, // l2cap ertm mtu
4,
4,
};
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
@ -115,7 +121,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
uint16_t l2cap_cid = little_endian_read_16(packet, 12);
if (l2cap_ertm){
printf("L2CAP Accepting incoming connection request in ERTM\n");
l2cap_accept_ertm_connection(l2cap_cid, l2cap_ertm_mandatory, l2cap_max_transmit, 2000, 12000, l2cap_local_mtu, 4, 4, ertm_buffer, sizeof(ertm_buffer));
l2cap_accept_ertm_connection(l2cap_cid, &ertm_config, ertm_buffer, sizeof(ertm_buffer));
} else {
printf("L2CAP Accepting incoming connection request in Basic Mode\n");
l2cap_accept_connection(l2cap_cid);
@ -139,7 +145,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack
static void show_usage(void){
printf("\n--- CLI for L2CAP TEST ---\n");
printf("L2CAP Channel Mode %s\n", l2cap_ertm ? "Enahnced Retransmission" : "Basic");
printf("L2CAP Channel Mode %s\n", l2cap_ertm ? "Enhanced Retransmission" : "Basic");
printf("c - create connection to SDP at addr %s\n", bd_addr_to_str(remote));
printf("s - send some data\n");
printf("S - send more data\n");
@ -159,7 +165,7 @@ static void stdin_process(char buffer){
case 'c':
printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
if (l2cap_ertm){
l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, l2cap_ertm_mandatory, l2cap_max_transmit, 2000, 12000, l2cap_local_mtu, 4, 4, ertm_buffer, sizeof(ertm_buffer), &local_cid);
l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, &ertm_config, ertm_buffer, sizeof(ertm_buffer), &local_cid);
} else {
l2cap_create_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, 100, &local_cid);
}
@ -187,12 +193,12 @@ static void stdin_process(char buffer){
case 'e':
printf("L2CAP Enhanced Retransmission Mode (ERTM) optional\n");
l2cap_ertm = 1;
l2cap_ertm_mandatory = 0;
ertm_config.ertm_mandatory = 0;
break;
case 'E':
printf("L2CAP Enhanced Retransmission Mode (ERTM) mandatory\n");
l2cap_ertm = 1;
l2cap_ertm_mandatory = 1;
ertm_config.ertm_mandatory = 1;
break;
case 'p':
printf("Send L2CAP ECHO Request\n");