btstack/ble/sm_minimal.c
2015-03-05 15:05:35 +00:00

233 lines
8.2 KiB
C

/*
* Copyright (C) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#include <stdio.h>
#include <strings.h>
#include "debug.h"
#include "hci.h"
#include "l2cap.h"
#include "le_device_db.h"
#include "sm.h"
#include "gap_le.h"
//
// SM internal types and globals
//
static void sm_run();
// used to notify applicationss that user interaction is neccessary, see sm_notify_t below
static btstack_packet_handler_t sm_client_packet_handler = NULL;
static security_manager_state_t sm_state_responding = SM_GENERAL_IDLE;
static uint16_t sm_response_handle = 0;
static uint8_t sm_pairing_failed_reason = 0;
void sm_set_er(sm_key_t er){}
void sm_set_ir(sm_key_t ir){}
void sm_test_set_irk(sm_key_t irk){}
void sm_register_oob_data_callback( int (*get_oob_data_callback)(uint8_t addres_type, bd_addr_t addr, uint8_t * oob_data)){}
void sm_set_accepted_stk_generation_methods(uint8_t accepted_stk_generation_methods){}
void sm_set_encryption_key_size_range(uint8_t min_size, uint8_t max_size){}
void sm_set_authentication_requirements(uint8_t auth_req){}
void sm_set_io_capabilities(io_capability_t io_capability){}
void sm_send_security_request(uint16_t handle){}
void sm_bonding_decline(uint8_t addr_type, bd_addr_t address){}
void sm_just_works_confirm(uint8_t addr_type, bd_addr_t address){}
void sm_passkey_input(uint8_t addr_type, bd_addr_t address, uint32_t passkey){}
// @returns 0 if not encrypted, 7-16 otherwise
int sm_encryption_key_size(uint8_t addr_type, bd_addr_t address){
return 0;
}
// @returns 1 if bonded with OOB/Passkey (AND MITM protection)
int sm_authenticated(uint8_t addr_type, bd_addr_t address){
return 0;
}
// @returns authorization_state for the current session
authorization_state_t sm_authorization_state(uint8_t addr_type, bd_addr_t address){
return AUTHORIZATION_DECLINED;
}
// request authorization
void sm_request_authorization(uint8_t addr_type, bd_addr_t address){}
// called by client app on authorization request
void sm_authorization_decline(uint8_t addr_type, bd_addr_t address){}
void sm_authorization_grant(uint8_t addr_type, bd_addr_t address){}
// Support for signed writes
int sm_cmac_ready(){
return 0;
}
void sm_cmac_start(sm_key_t k, uint16_t message_len, uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t hash[8])){}
/**
* @brief Identify device in LE Device DB
* @param handle
* @returns index from le_device_db or -1 if not found/identified
*/
int sm_le_device_index(uint16_t handle ){
return -1;
}
void sm_register_packet_handler(btstack_packet_handler_t handler){
sm_client_packet_handler = handler;
}
static void sm_pdu_received_in_wrong_state(){
sm_pairing_failed_reason = SM_REASON_UNSPECIFIED_REASON;
sm_state_responding = SM_GENERAL_SEND_PAIRING_FAILED;
}
static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
if (packet_type != SM_DATA_PACKET) return;
if (handle != sm_response_handle){
log_info("sm_packet_handler: packet from handle %u, but expecting from %u", handle, sm_response_handle);
return;
}
if (packet[0] == SM_CODE_PAIRING_FAILED){
sm_state_responding = SM_GENERAL_SEND_PAIRING_FAILED;
return;
}
switch (sm_state_responding){
case SM_GENERAL_IDLE: {
if (packet[0] != SM_CODE_PAIRING_REQUEST){
sm_pdu_received_in_wrong_state();
break;;
}
sm_state_responding = SM_GENERAL_SEND_PAIRING_FAILED;
sm_pairing_failed_reason = SM_REASON_PAIRING_NOT_SUPPORTED;
break;
}
default:
break;
}
// try to send preparared packet
sm_run();
}
static void sm_event_packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (packet[0]) {
case HCI_EVENT_LE_META:
switch (packet[2]) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
// only single connection for peripheral
if (sm_response_handle){
log_info("Already connected, ignoring incoming connection");
return;
}
sm_response_handle = READ_BT_16(packet, 4);
sm_state_responding = SM_GENERAL_IDLE;
break;
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST:
log_info("LTK Request: state %u", sm_state_responding);
sm_state_responding = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
break;
default:
break;
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
sm_state_responding = SM_GENERAL_IDLE;
sm_response_handle = 0;
break;
}
// forward packet to higher layer
if (sm_client_packet_handler){
sm_client_packet_handler(packet_type, 0, packet, size);
}
}
// try to send preparared packet
sm_run();
}
static void sm_run(void){
// assert that we can send either one
switch (sm_state_responding){
case SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY:
if (!hci_can_send_command_packet_now()) return;
hci_send_cmd(&hci_le_long_term_key_negative_reply, sm_response_handle);
sm_state_responding = SM_GENERAL_IDLE;
return;
case SM_GENERAL_SEND_PAIRING_FAILED: {
if (!l2cap_can_send_fixed_channel_packet_now(sm_response_handle)) return;
uint8_t buffer[2];
buffer[0] = SM_CODE_PAIRING_FAILED;
buffer[1] = sm_pairing_failed_reason;
l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_state_responding = SM_GENERAL_IDLE;
break;
}
default:
break;
}
}
void sm_init(){
// attach to lower layers
l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
l2cap_register_packet_handler(sm_event_packet_handler);
}
// GAP LE
void gap_random_address_set_mode(gap_random_address_type_t random_address_type){}
void gap_random_address_set_update_period(int period_ms){}