use sm_active_connection as mutex for setup context struct

This commit is contained in:
matthias.ringwald@gmail.com 2015-02-26 21:32:16 +00:00
parent 268602ef87
commit 477200f2ef
2 changed files with 114 additions and 84 deletions

159
ble/sm.c
View File

@ -99,16 +99,6 @@ typedef enum {
SM_AES128_ACTIVE
} sm_aes128_state_t;
typedef struct sm_pairing_packet {
uint8_t code;
uint8_t io_capability;
uint8_t oob_data_flag;
uint8_t auth_req;
uint8_t max_encryption_key_size;
uint8_t initiator_key_distribution;
uint8_t responder_key_distribution;
} sm_pairing_packet_t;
//
// GLOBAL DATA
//
@ -257,6 +247,9 @@ static void sm_run();
static void sm_done_for_handle(uint16_t handle);
static void sm_notify_client(uint8_t type, uint8_t addr_type, bd_addr_t address, uint32_t passkey, uint16_t index);
static sm_connection_t * sm_get_connection_for_handle(uint16_t handle);
static inline int sm_calc_actual_encryption_key_size(int other);
static int sm_validate_stk_generation_method();
static void sm_responder_setup(sm_connection_t * sm_conn);
static void log_info_hex16(const char * name, uint16_t value){
log_info("%-6s 0x%04x", name, value);
@ -768,15 +761,23 @@ static void sm_pdu_received_in_wrong_state(sm_connection_t * sm_conn){
static void sm_run(void){
// setup locking
// - if no connection locked
// TODO: iterate over all hci_connections instead of handling the single connection
sm_connection_t * connection = &single_connection;
// hack (probably) start security if requested before (setup lock recommended)
if (connection->sm_engine_state == SM_INITIATOR_CONNECTED && connection->sm_role == 0x00 && sm_authenticate_outgoing_connections){
connection->sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST;
// setup locking
// - if no connection locked and we're ready/waiting for setup context, fetch it and start
if (sm_active_connection == 0){
switch (connection->sm_engine_state) {
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
sm_responder_setup(connection);
break;
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:
sm_active_connection = connection->sm_handle;
connection->sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST;
break;
default:
break;
}
}
// assert that we can send at least commands
@ -925,7 +926,7 @@ static void sm_run(void){
uint8_t buffer[2];
buffer[0] = SM_CODE_SECURITY_REQUEST;
buffer[1] = SM_AUTHREQ_BONDING;
connection->sm_engine_state = SM_GENERAL_IDLE;
connection->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
return;
}
@ -1449,6 +1450,54 @@ static void sm_init_setup(sm_connection_t * sm_conn){
}
}
static void sm_responder_setup(sm_connection_t * sm_conn){
// start setup in responder role
sm_init_setup(sm_conn);
// recover pairing request
memcpy(&setup->sm_m_preq, &sm_conn->sm_m_preq, sizeof(sm_pairing_packet_t));
// check key size
sm_conn->sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size(setup->sm_s_pres.max_encryption_key_size);
if (sm_conn->sm_actual_encryption_key_size == 0){
sm_done_for_handle(sm_conn->sm_handle);
setup->sm_pairing_failed_reason = SM_REASON_ENCRYPTION_KEY_SIZE;
sm_conn->sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED;
return;
}
// setup key distribution
sm_setup_key_distribution(setup->sm_m_preq.responder_key_distribution);
// start SM timeout
sm_2timeout_start(sm_conn);
// decide on STK generation method
sm_setup_tk();
log_info("SMP: generation method %u", setup->sm_stk_generation_method);
// check if STK generation method is acceptable by client
if (!sm_validate_stk_generation_method()){
sm_done_for_handle(sm_conn->sm_handle);
setup->sm_pairing_failed_reason = SM_REASON_AUTHENTHICATION_REQUIREMENTS;
sm_conn->sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED;
return;
}
// JUST WORKS doens't provide authentication
sm_conn->sm_connection_authenticated = setup->sm_stk_generation_method == JUST_WORKS ? 0 : 1;
// generate random number first, if we need to show passkey
if (setup->sm_stk_generation_method == PK_INIT_INPUT){
sm_conn->sm_engine_state = SM_PH2_GET_RANDOM_TK;
return;
}
sm_conn->sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE;
}
static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
sm_connection_t * sm_conn;
@ -1500,10 +1549,21 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
// just connected -> everything else happens in sm_run()
if (sm_conn->sm_role){
// slave
sm_conn->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST;
if (sm_slave_request_security){
// request security if requested by app
sm_conn->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
} else {
// otherwise, wait for pairing request
sm_conn->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST;
}
break;
} else {
// master
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
if (sm_authenticate_outgoing_connections){
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
} else {
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}
}
break;
@ -1550,7 +1610,7 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
if (!sm_conn) break;
sm_conn->sm_connection_encrypted = packet[5];
log_info("Eencryption state change: %u", sm_conn->sm_connection_encrypted);
log_info("Encryption state change: %u", sm_conn->sm_connection_encrypted);
if (!sm_conn->sm_connection_encrypted) break;
if (sm_conn->sm_engine_state == SM_PH2_W4_CONNECTION_ENCRYPTED) {
if (sm_conn->sm_role){
@ -1718,64 +1778,18 @@ static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pac
break;
// Responder
case SM_GENERAL_IDLE:
case SM_GENERAL_IDLE:
case SM_RESPONDER_SEND_SECURITY_REQUEST:
case SM_RESPONDER_PH1_W4_PAIRING_REQUEST:
{
if (packet[0] != SM_CODE_PAIRING_REQUEST){
sm_pdu_received_in_wrong_state(sm_conn);
break;;
}
// start setup in responder role
sm_init_setup(sm_conn);
// request security if we're slave and requested by app (setup lock recommended)
if (sm_conn->sm_role == 0x01 && sm_slave_request_security){
sm_conn->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
}
// store pairing request
memcpy(&setup->sm_m_preq, packet, sizeof(sm_pairing_packet_t));
// check key size
sm_conn->sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size(setup->sm_s_pres.max_encryption_key_size);
if (sm_conn->sm_actual_encryption_key_size == 0){
sm_done_for_handle(sm_conn->sm_handle);
setup->sm_pairing_failed_reason = SM_REASON_ENCRYPTION_KEY_SIZE;
sm_conn->sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED;
break;
}
// setup key distribution
sm_setup_key_distribution(setup->sm_m_preq.responder_key_distribution);
// start SM timeout
sm_2timeout_start(sm_conn);
// decide on STK generation method
sm_setup_tk();
log_info("SMP: generation method %u", setup->sm_stk_generation_method);
// check if STK generation method is acceptable by client
if (!sm_validate_stk_generation_method()){
sm_done_for_handle(sm_conn->sm_handle);
setup->sm_pairing_failed_reason = SM_REASON_AUTHENTHICATION_REQUIREMENTS;
sm_conn->sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED;
break;
}
// JUST WORKS doens't provide authentication
sm_conn->sm_connection_authenticated = setup->sm_stk_generation_method == JUST_WORKS ? 0 : 1;
// generate random number first, if we need to show passkey
if (setup->sm_stk_generation_method == PK_INIT_INPUT){
sm_conn->sm_engine_state = SM_PH2_GET_RANDOM_TK;
break;
}
sm_conn->sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE;
break;
}
memcpy(&sm_conn->sm_m_preq, packet, sizeof(sm_pairing_packet_t));
sm_conn->sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED;
break;
case SM_RESPONDER_PH1_W4_PAIRING_CONFIRM:
if (packet[0] != SM_CODE_PAIRING_CONFIRM){
@ -1931,6 +1945,7 @@ void sm_test_set_irk(sm_key_t irk){
*/
void sm_send_security_request(uint16_t handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(handle);
if (sm_conn->sm_engine_state != SM_RESPONDER_PH1_W4_PAIRING_REQUEST) return;
sm_conn->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
sm_run();
}
@ -2016,7 +2031,7 @@ void sm_request_authorization(uint8_t addr_type, bd_addr_t address){
// used as a trigger to start central/master/initiator security procedures
if (sm_conn->sm_engine_state == SM_INITIATOR_CONNECTED){
sm_conn->sm_engine_state = SM_INITIATOR_PH1_SEND_PAIRING_REQUEST;
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
}
}
}

View File

@ -411,6 +411,7 @@ typedef enum {
SM_RESPONDER_SEND_SECURITY_REQUEST,
SM_RESPONDER_SEND_LTK_REQUESTED_NEGATIVE_REPLY,
SM_RESPONDER_PH1_W4_PAIRING_REQUEST,
SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED,
SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE,
SM_RESPONDER_PH1_W4_PAIRING_CONFIRM,
SM_RESPONDER_PH2_W4_PAIRING_RANDOM,
@ -419,6 +420,7 @@ typedef enum {
// INITITIATOR ROLE
SM_INITIATOR_CONNECTED,
SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST,
SM_INITIATOR_PH1_SEND_PAIRING_REQUEST,
SM_INITIATOR_PH1_W4_PAIRING_RESPONSE,
SM_INITIATOR_PH2_W4_PAIRING_CONFIRM,
@ -442,19 +444,30 @@ typedef enum {
AUTHORIZATION_GRANTED
} authorization_state_t;
typedef struct sm_pairing_packet {
uint8_t code;
uint8_t io_capability;
uint8_t oob_data_flag;
uint8_t auth_req;
uint8_t max_encryption_key_size;
uint8_t initiator_key_distribution;
uint8_t responder_key_distribution;
} sm_pairing_packet_t;
// connection info available as long as connection exists
typedef struct sm_connection {
uint16_t sm_handle;
uint8_t sm_role; // 0 - IamMaster, 1 = IamSlave
bd_addr_t sm_peer_address;
uint8_t sm_peer_addr_type;
uint16_t sm_handle;
uint8_t sm_role; // 0 - IamMaster, 1 = IamSlave
bd_addr_t sm_peer_address;
uint8_t sm_peer_addr_type;
security_manager_state_t sm_engine_state;
csrk_lookup_state_t sm_csrk_lookup_state;
uint8_t sm_connection_encrypted;
uint8_t sm_connection_authenticated; // [0..1]
uint8_t sm_actual_encryption_key_size;
authorization_state_t sm_connection_authorization_state;
timer_source_t sm_timeout;
uint8_t sm_connection_encrypted;
uint8_t sm_connection_authenticated; // [0..1]
uint8_t sm_actual_encryption_key_size;
sm_pairing_packet_t sm_m_preq; // only used during c1
authorization_state_t sm_connection_authorization_state;
timer_source_t sm_timeout;
} sm_connection_t;
typedef struct {
@ -500,11 +513,11 @@ typedef struct {
uint16_t acl_recombination_pos;
uint16_t acl_recombination_length;
// number ACL packets sent to controller
// number packets sent to controller
uint8_t num_acl_packets_sent;
uint8_t num_sco_packets_sent;
// connection parameter update
// LE Connection parameter update
le_con_parameter_update_state_t le_con_parameter_update_state;
uint16_t le_conn_interval_min;
uint16_t le_conn_interval_max;
@ -512,8 +525,10 @@ typedef struct {
uint16_t le_supervision_timeout;
uint16_t le_update_con_parameter_response;
#ifdef HAVE_BLE
// LE Security Manager
// sm_connection_t sm_connection;
sm_connection_t sm_connection;
#endif
} hci_connection_t;