Skip to content

Commit

Permalink
callback to circumvent l2cap layer for received data; tweek the handl…
Browse files Browse the repository at this point in the history
…ing of timeouts to pass LL/CON/PER/BV-13-C; report passed instance correctly
  • Loading branch information
TorstenRobitzki committed Sep 20, 2023
1 parent f58f009 commit 1abca12
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 40 deletions.
14 changes: 12 additions & 2 deletions bluetoe/link_layer/include/bluetoe/link_layer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ namespace link_layer {
details::buffer_sizes< Options... >::rx_size,
link_layer< Server, ScheduledRadio, Options... >
>,
link_layer< Server, ScheduledRadio, Options... >,
details::l2cap_layer< Server, ScheduledRadio, Options... >::required_minimum_l2cap_buffer_size
>,
public details::white_list<
Expand All @@ -493,6 +494,7 @@ namespace link_layer {
details::buffer_sizes< Options... >::rx_size,
link_layer< Server, ScheduledRadio, Options... >
>,
link_layer< Server, ScheduledRadio, Options... >,
details::l2cap_layer< Server, ScheduledRadio, Options... >::required_minimum_l2cap_buffer_size
>,
link_layer< Server, ScheduledRadio, Options... >,
Expand All @@ -510,7 +512,12 @@ namespace link_layer {
link_layer< Server, ScheduledRadio, Options... >
> >,
public details::select_user_timer_impl<
link_layer< Server, ScheduledRadio, Options... >, Options ... >
link_layer< Server, ScheduledRadio, Options... >, Options ... >,
public bluetoe::details::find_by_meta_type<
details::ll_pdu_receive_data_callback_meta_type,
Options...,
no_l2cap_callback
>::type
{
public:
link_layer();
Expand Down Expand Up @@ -752,6 +759,7 @@ namespace link_layer {

static constexpr std::uint8_t connection_terminated_by_local_host = 0x16;
static constexpr std::uint8_t connection_timeout = 0x08;
static constexpr std::uint8_t connection_instant_passed = 0x28;

struct link_layer_feature {
enum : std::uint16_t {
Expand Down Expand Up @@ -942,7 +950,7 @@ namespace link_layer {

const auto time_since_last_event = this->time_since_last_event();

if ( time_since_last_event <= connection_timeout_
if ( time_since_last_event < connection_timeout_
&& !( state_ == state::connecting && time_since_last_event >= ( num_windows_til_timeout - 1 ) * connection_interval_ ) )
{
this->plan_next_connection_event_after_timeout( connection_interval_ );
Expand Down Expand Up @@ -1438,6 +1446,7 @@ namespace link_layer {
if ( static_cast< std::uint16_t >( defered_conn_event_counter_ - this->connection_event_counter() + 1 ) & 0x8000
|| defered_conn_event_counter_ == this->connection_event_counter() + 1 )
{
disconnecting_reason_ = connection_instant_passed;
result = ll_result::disconnect;
}
else
Expand Down Expand Up @@ -1473,6 +1482,7 @@ namespace link_layer {

if ( static_cast< std::uint16_t >( defered_conn_event_counter_ - this->connection_event_counter() ) & 0x8000 )
{
disconnecting_reason_ = connection_instant_passed;
result = ll_result::disconnect;
}
else
Expand Down
70 changes: 37 additions & 33 deletions bluetoe/link_layer/include/bluetoe/ll_l2cap_sdu_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ namespace link_layer {
*
* If the L2CAP MTU size is 23, this class shall no generate any overhead as SDUs are directly
* mapped to LL PDUs.
*
* @tparam ReceiveCallbacks type that has to provide a callback for raw received PDUs
*/
template < class BufferedRadio, std::size_t MTUSize >
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
class ll_l2cap_sdu_buffer : public BufferedRadio
{
public:
Expand Down Expand Up @@ -114,8 +116,8 @@ namespace link_layer {
* @brief specialisation for the minimum MTU size, which would not require any addition
* fragmentation / defragmentation
*/
template < class BufferedRadio >
class ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size > : public BufferedRadio
template < class BufferedRadio, class ReceiveCallbacks >
class ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size > : public BufferedRadio
{
public:
read_buffer allocate_l2cap_transmit_buffer( std::size_t size );
Expand All @@ -133,17 +135,17 @@ namespace link_layer {
};

// implementation
template < class BufferedRadio, std::size_t MTUSize >
ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::ll_l2cap_sdu_buffer()
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::ll_l2cap_sdu_buffer()
: receive_size_( 0 )
, receive_buffer_used_( 0 )
, transmit_size_( 0 )
, transmit_buffer_used_( 0 )
{
}

template < class BufferedRadio, std::size_t MTUSize >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::allocate_l2cap_transmit_buffer( std::size_t payload_size )
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::allocate_l2cap_transmit_buffer( std::size_t payload_size )
{
assert( payload_size <= MTUSize );

Expand All @@ -153,16 +155,16 @@ namespace link_layer {
return { transmit_buffer_, payload_size + overall_overhead };
}

template < class BufferedRadio, std::size_t MTUSize >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::allocate_ll_transmit_buffer( std::size_t payload_size )
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::allocate_ll_transmit_buffer( std::size_t payload_size )
{
try_send_pdus();

return this->allocate_transmit_buffer( payload_size + ll_overhead );
}

template < class BufferedRadio, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::commit_l2cap_transmit_buffer( read_buffer buffer )
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::commit_l2cap_transmit_buffer( read_buffer buffer )
{
const auto body = layout::body( buffer );
const std::size_t size = bluetoe::details::read_16bit( body.first ) + overall_overhead;
Expand All @@ -173,14 +175,14 @@ namespace link_layer {
try_send_pdus();
}

template < class BufferedRadio, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::commit_ll_transmit_buffer( read_buffer buffer )
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::commit_ll_transmit_buffer( read_buffer buffer )
{
this->commit_transmit_buffer( buffer );
}

template < class BufferedRadio, std::size_t MTUSize >
write_buffer ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::next_ll_l2cap_received()
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
write_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::next_ll_l2cap_received()
{
try_send_pdus();

Expand All @@ -197,6 +199,8 @@ namespace link_layer {
if ( type == pdu_type_link_layer )
return pdu;

static_cast< ReceiveCallbacks* >( this )->pdu_receive_data_callback( pdu );

// l2cap message
const auto body = layout::body( pdu );
const std::size_t body_size = body.second - body.first;
Expand Down Expand Up @@ -234,8 +238,8 @@ namespace link_layer {
return { nullptr, 0 };
}

template < class BufferedRadio, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::add_to_receive_buffer( const std::uint8_t* begin, const std::uint8_t* end )
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::add_to_receive_buffer( const std::uint8_t* begin, const std::uint8_t* end )
{
const std::size_t copy_size = std::min< std::size_t >( receive_size_, end - begin );

Expand All @@ -244,8 +248,8 @@ namespace link_layer {
receive_size_ -= copy_size;
}

template < class BufferedRadio, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::try_send_pdus()
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::try_send_pdus()
{
while ( transmit_size_ )
{
Expand Down Expand Up @@ -289,8 +293,8 @@ namespace link_layer {
transmit_buffer_used_ = 0;
}

template < class BufferedRadio, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::free_ll_l2cap_received()
template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::free_ll_l2cap_received()
{
if (receive_buffer_used_)
{
Expand All @@ -305,38 +309,38 @@ namespace link_layer {


// implementation
template < class BufferedRadio >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::allocate_l2cap_transmit_buffer( std::size_t size )
template < class BufferedRadio, class ReceiveCallbacks >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::allocate_l2cap_transmit_buffer( std::size_t size )
{
return this->allocate_transmit_buffer( size + overall_overhead );
}

template < class BufferedRadio >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::allocate_ll_transmit_buffer( std::size_t size )
template < class BufferedRadio, class ReceiveCallbacks >
read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::allocate_ll_transmit_buffer( std::size_t size )
{
return this->allocate_transmit_buffer( size + ll_overhead );
}

template < class BufferedRadio >
void ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::commit_l2cap_transmit_buffer( read_buffer buffer )
template < class BufferedRadio, class ReceiveCallbacks >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::commit_l2cap_transmit_buffer( read_buffer buffer )
{
return this->commit_transmit_buffer( buffer );
}

template < class BufferedRadio >
void ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::commit_ll_transmit_buffer( read_buffer buffer )
template < class BufferedRadio, class ReceiveCallbacks >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::commit_ll_transmit_buffer( read_buffer buffer )
{
return this->commit_transmit_buffer( buffer );
}

template < class BufferedRadio >
write_buffer ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::next_ll_l2cap_received() const
template < class BufferedRadio, class ReceiveCallbacks >
write_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::next_ll_l2cap_received() const
{
return this->next_received();
}

template < class BufferedRadio >
void ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size >::free_ll_l2cap_received()
template < class BufferedRadio, class ReceiveCallbacks >
void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::free_ll_l2cap_received()
{
return this->free_received();
}
Expand Down
29 changes: 29 additions & 0 deletions bluetoe/link_layer/include/bluetoe/ll_options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace link_layer
struct buffer_sizes_meta_type {};
struct desired_connection_parameters_meta_type {};
struct custom_l2cap_layer_meta_type {};
struct ll_pdu_receive_data_callback_meta_type {};
}

/**
Expand Down Expand Up @@ -259,6 +260,34 @@ namespace link_layer
using l2cap_layer = L2CapLayer< LinkLayer >;
/** @endcond */
};

template < class Obj, Obj& obj >
struct l2cap_callback
{
/** @cond HIDDEN_SYMBOLS */
void pdu_receive_data_callback( const write_buffer& ll_pdu_containing_l2cap_package )
{
obj.l2cap_callback( ll_pdu_containing_l2cap_package );
}

struct meta_type :
details::ll_pdu_receive_data_callback_meta_type,
details::valid_link_layer_option_meta_type {};
};

struct no_l2cap_callback
{
/** @cond HIDDEN_SYMBOLS */
void pdu_receive_data_callback( const write_buffer& )
{
}

struct meta_type :
details::ll_pdu_receive_data_callback_meta_type,
details::valid_link_layer_option_meta_type {};
};


}
}

Expand Down
8 changes: 4 additions & 4 deletions tests/link_layer/ll_connection_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ BOOST_FIXTURE_TEST_CASE( window_size_is_increasing_with_connection_event_timeout
/*
* Once the link layer received a PDU from the central, the supervision timeout is in charge
* In this example, the timeout is 720ms, the connection interval is 30ms, so the timeout is
* reached after 24 connection intervals (that's the 25th schedule request; plus the first one after the con request).
* reached after 24 connection intervals (that's the 25th schedule request).
*/
BOOST_FIXTURE_TEST_CASE( supervision_timeout_is_in_charge, only_one_pdu_from_central )
{
BOOST_CHECK_EQUAL( connection_events().size(), 26u );
BOOST_CHECK_EQUAL( connection_events().size(), 25u );
}

void add_channel_map_request( unconnected& c, std::uint16_t instance, std::uint64_t map )
Expand Down Expand Up @@ -369,7 +369,7 @@ BOOST_FIXTURE_TEST_CASE( connection_update_correct_timeout_used, unconnected )

run();

BOOST_CHECK_EQUAL( connection_events().size(), std::size_t{ 8 + 5 } );
BOOST_CHECK_EQUAL( connection_events().size(), std::size_t{ 8 + 4 } );
}

static void simulate_connection_update_request(
Expand All @@ -394,7 +394,7 @@ BOOST_FIXTURE_TEST_CASE( connection_update_request_window_size_0, unconnected )
{
simulate_connection_update_request( *this, 5, 0, 40, 0, 25, 6 );

BOOST_CHECK_EQUAL( connection_events().size(), 17u );
BOOST_CHECK_EQUAL( connection_events().size(), 16u );
}

BOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_window_offset, unconnected )
Expand Down
8 changes: 7 additions & 1 deletion tests/link_layer/ll_l2cap_sdu_buffer_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,21 @@ namespace {
std::copy( data.begin(), data.end(), buffer.buffer );
}

void pdu_receive_data_callback( const bluetoe::link_layer::write_buffer pdu )
{
received_data_pdus_.push_back( pdu_t( pdu.buffer, pdu.buffer + pdu.size ) );
}

private:
using pdu_t = std::vector< std::uint8_t >;
std::vector< pdu_t > received_pdus_;
std::size_t available_transmit_buffers_;
std::vector< pdu_t > tranmitted_pdus_;
std::uint8_t transmit_buffer_[256];
std::vector< pdu_t > received_data_pdus_;
};

class buffer_under_test : public bluetoe::link_layer::ll_l2cap_sdu_buffer< radio_mock_t, 100 >
class buffer_under_test : public bluetoe::link_layer::ll_l2cap_sdu_buffer< radio_mock_t, radio_mock_t, 100 >
{
public:
void expect_next_received( std::initializer_list< std::uint8_t > expected )
Expand Down

0 comments on commit 1abca12

Please sign in to comment.