Skip to content

Commit

Permalink
Checking parameters within LL_CONNECTION_PARAM_REQ; fixing #124
Browse files Browse the repository at this point in the history
  • Loading branch information
TorstenRobitzki committed Oct 2, 2023
1 parent 3651359 commit 1825df8
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 38 deletions.
126 changes: 88 additions & 38 deletions bluetoe/link_layer/include/bluetoe/ll_options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,56 @@ namespace link_layer

namespace details
{
struct requested_connection_parameters
{
std::uint16_t min_interval;
std::uint16_t max_interval;
std::uint16_t latency;
std::uint16_t timeout;
};

struct desired_connection_parameters_base
{
static constexpr std::size_t size = 24;
static constexpr std::uint8_t ll_control_pdu_code = 3;
static constexpr std::uint8_t LL_CONNECTION_PARAM_REQ = 0x0F;
static constexpr std::uint8_t LL_CONNECTION_PARAM_RSP = 0x10;
static constexpr std::uint8_t LL_REJECT_EXT_IND = 0x11;
static constexpr std::uint8_t invalid_ll_paramerters = 0x1E;

template < class Layout >
static bool parse_and_check_params( const write_buffer& request, read_buffer response, requested_connection_parameters& params )
{
static constexpr std::uint16_t interval_minimum = 5u;
static constexpr std::uint16_t interval_maximum = 3200u;
static constexpr std::uint16_t latency_maximum = 500u;

const std::uint8_t* const body = Layout::body( request ).first;

using bluetoe::details::read_16bit;

params.min_interval = read_16bit( body + 1 );
params.max_interval = read_16bit( body + 3 );
params.latency = read_16bit( body + 5 );
params.timeout = read_16bit( body + 7 );

if ( params.max_interval < params.min_interval
|| params.min_interval < interval_minimum
|| params.max_interval > interval_maximum
|| params.latency > latency_maximum )
{
fill< Layout >( response, {
ll_control_pdu_code, 3,
LL_REJECT_EXT_IND,
LL_CONNECTION_PARAM_REQ,
invalid_ll_paramerters
} );

return false;
}

return true;
}
};
}

Expand Down Expand Up @@ -183,43 +228,44 @@ namespace link_layer
const std::uint8_t* const body = Layout::body( request ).first;
std::uint8_t* const write_body = Layout::body( response ).first;

using bluetoe::details::read_16bit;

std::uint16_t min_interval = std::max( read_16bit( body + 1 ), Interval_min );
std::uint16_t max_interval = std::min( read_16bit( body + 3 ), Interval_max );
std::uint16_t latency = read_16bit( body + 5 );
std::uint16_t timeout = read_16bit( body + 7 );

if ( min_interval > max_interval )
{
min_interval = Interval_min;
max_interval = Interval_max;
}

if ( latency < Latency_min || latency > Latency_max )
{
latency = ( Latency_min + Latency_max ) / 2;
}

if ( timeout < Timeout_min || timeout > Timeout_max )
details::requested_connection_parameters params;
if ( parse_and_check_params< Layout >( request, response, params ) )
{
timeout = ( Timeout_min + Timeout_max ) / 2;
params.min_interval = std::max( params.min_interval, Interval_min );
params.max_interval = std::min( params.max_interval, Interval_max );

if ( params.min_interval > params.max_interval )
{
params.min_interval = Interval_min;
params.max_interval = Interval_max;
}

if ( params.latency < Latency_min || params.latency > Latency_max )
{
params.latency = ( Latency_min + Latency_max ) / 2;
}

if ( params.timeout < Timeout_min || params.timeout > Timeout_max )
{
params.timeout = ( Timeout_min + Timeout_max ) / 2;
}

fill< Layout >( response, {
ll_control_pdu_code, size,
LL_CONNECTION_PARAM_RSP,
static_cast< std::uint8_t >( params.min_interval ),
static_cast< std::uint8_t >( params.min_interval >> 8 ),
static_cast< std::uint8_t >( params.max_interval ),
static_cast< std::uint8_t >( params.max_interval >> 8 ),
static_cast< std::uint8_t >( params.latency ),
static_cast< std::uint8_t >( params.latency >> 8 ),
static_cast< std::uint8_t >( params.timeout ),
static_cast< std::uint8_t >( params.timeout >> 8 )
} );

std::copy( &body[ 9 ], &body[ size ], &write_body[ 9 ] );
}

fill< Layout >( response, {
ll_control_pdu_code, size,
LL_CONNECTION_PARAM_RSP,
static_cast< std::uint8_t >( min_interval ),
static_cast< std::uint8_t >( min_interval >> 8 ),
static_cast< std::uint8_t >( max_interval ),
static_cast< std::uint8_t >( max_interval >> 8 ),
static_cast< std::uint8_t >( latency ),
static_cast< std::uint8_t >( latency >> 8 ),
static_cast< std::uint8_t >( timeout ),
static_cast< std::uint8_t >( timeout >> 8 )
} );

std::copy( &body[ 9 ], &body[ size ], &write_body[ 9 ] );
}
/** @endcond */
};
Expand All @@ -235,12 +281,16 @@ namespace link_layer
static void fill_response(
const write_buffer& request, read_buffer response )
{
const std::uint8_t* const body = Layout::body( request ).first;
std::uint8_t* const write_body = Layout::body( response ).first;
details::requested_connection_parameters params;
if ( parse_and_check_params< Layout >( request, response, params ) )
{
const std::uint8_t* const body = Layout::body( request ).first;
std::uint8_t* const write_body = Layout::body( response ).first;

fill< Layout >( response, { ll_control_pdu_code, size, LL_CONNECTION_PARAM_RSP } );
fill< Layout >( response, { ll_control_pdu_code, size, LL_CONNECTION_PARAM_RSP } );

std::copy( &body[ 1 ], &body[ 1 + size - 1 ], &write_body[ 1 ] );
std::copy( &body[ 1 ], &body[ 1 + size - 1 ], &write_body[ 1 ] );
}
}
};
/** @endcond */
Expand Down
140 changes: 140 additions & 0 deletions tests/link_layer/connection_parameter_update_procedure_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,143 @@ BOOST_FIXTURE_TEST_CASE( requested_timeout_outside_of_desired_values, link_layer
0xff, 0xff // Offset5 (none)
} );
}

using connection_parameters_configurations = std::tuple<
link_layer_with_desired_connection_parameters,
link_layer_with_signaling_channel >;

/**
* LL/CON/PER/BI-16-C
*/
BOOST_AUTO_TEST_CASE_TEMPLATE( Reject_Invalid_Connection_Parameter_Request_Parameters, fixture_t, connection_parameters_configurations )
{
fixture_t link_layer;

link_layer.ll_control_pdu( {
0x0F, // LL_CONNECTION_PARAM_REQ
20, 0x00, // min interval
10, 0x00, // max interval
3, 0x00, // latency
(3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout
0x00, // prefered periodicity (none)
0xff, 0xff, // ReferenceConnEventCount
0xff, 0xff, // Offset0 (none)
0xff, 0xff, // Offset1 (none)
0xff, 0xff, // Offset2 (none)
0xff, 0xff, // Offset3 (none)
0xff, 0xff, // Offset4 (none)
0xff, 0xff // Offset5 (none)
} );

link_layer.ll_empty_pdus(3);

link_layer.run( 5 );

link_layer.check_outgoing_ll_control_pdu( {
0x11, // LL_REJECT_EXT_IND
0x0F, // LL_CONNECTION_PARAM_REQ
0x1E // ErrorCode
} );
}

/**
* LL/CON/PER/BI-08-C I
*/
BOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_I, fixture_t, connection_parameters_configurations )
{
fixture_t link_layer;

link_layer.ll_control_pdu( {
0x0F, // LL_CONNECTION_PARAM_REQ
4, 0x00, // min interval
10, 0x00, // max interval
3, 0x00, // latency
(3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout
0x00, // prefered periodicity (none)
0xff, 0xff, // ReferenceConnEventCount
0xff, 0xff, // Offset0 (none)
0xff, 0xff, // Offset1 (none)
0xff, 0xff, // Offset2 (none)
0xff, 0xff, // Offset3 (none)
0xff, 0xff, // Offset4 (none)
0xff, 0xff // Offset5 (none)
} );

link_layer.ll_empty_pdus(3);

link_layer.run( 5 );

link_layer.check_outgoing_ll_control_pdu( {
0x11, // LL_REJECT_EXT_IND
0x0F, // LL_CONNECTION_PARAM_REQ
0x1E // ErrorCode
} );
}

/**
* LL/CON/PER/BI-08-C II
*/
BOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_II, fixture_t, connection_parameters_configurations )
{
fixture_t link_layer;

link_layer.ll_control_pdu( {
0x0F, // LL_CONNECTION_PARAM_REQ
5, 0x00, // min interval
0x81, 0x0C, // max interval
3, 0x00, // latency
(3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout
0x00, // prefered periodicity (none)
0xff, 0xff, // ReferenceConnEventCount
0xff, 0xff, // Offset0 (none)
0xff, 0xff, // Offset1 (none)
0xff, 0xff, // Offset2 (none)
0xff, 0xff, // Offset3 (none)
0xff, 0xff, // Offset4 (none)
0xff, 0xff // Offset5 (none)
} );

link_layer.ll_empty_pdus(3);

link_layer.run( 5 );

link_layer.check_outgoing_ll_control_pdu( {
0x11, // LL_REJECT_EXT_IND
0x0F, // LL_CONNECTION_PARAM_REQ
0x1E // ErrorCode
} );
}

/**
* LL/CON/PER/BI-08-C III
*/
BOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_III, fixture_t, connection_parameters_configurations )
{
fixture_t link_layer;

link_layer.ll_control_pdu( {
0x0F, // LL_CONNECTION_PARAM_REQ
5, 0x00, // min interval
10, 0x00, // max interval
0xf5, 0x01, // latency 501
(3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout
0x00, // prefered periodicity (none)
0xff, 0xff, // ReferenceConnEventCount
0xff, 0xff, // Offset0 (none)
0xff, 0xff, // Offset1 (none)
0xff, 0xff, // Offset2 (none)
0xff, 0xff, // Offset3 (none)
0xff, 0xff, // Offset4 (none)
0xff, 0xff // Offset5 (none)
} );

link_layer.ll_empty_pdus(3);

link_layer.run( 5 );

link_layer.check_outgoing_ll_control_pdu( {
0x11, // LL_REJECT_EXT_IND
0x0F, // LL_CONNECTION_PARAM_REQ
0x1E // ErrorCode
} );
}

0 comments on commit 1825df8

Please sign in to comment.