From 0b84a1242eccbbbba6604909f41fd99102539ee0 Mon Sep 17 00:00:00 2001 From: Chinmay Chhajed Date: Tue, 22 Dec 2020 12:36:07 +0530 Subject: [PATCH] Bluedroid: Fixes for some vulnerabilities. This commit fixes 'Impersonation in Passkey entry protocol' (CVE-2020-26558) and suggests fixes for other vulnerabilites like 'Impersonation in the Pin Pairing Protocol' (CVE-2020-26555) and 'Authentication of the LE Legacy Pairing Protocol' CVE-2020-26558 can be easily implemented if the peer device can impersonate our public key. This commit adds a check by comparing our and received public key and returns failed pairing if keys are same. This commit also adds comments suggesting to use secure connection when supported by all devices. --- .../api/include/api/esp_gap_ble_api.h | 1300 ++++++++++ .../bt/host/bluedroid/stack/smp/smp_act.c | 2187 +++++++++++++++++ 2 files changed, 3487 insertions(+) create mode 100644 components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h create mode 100644 components/bt/host/bluedroid/stack/smp/smp_act.c diff --git a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h new file mode 100644 index 0000000000..61ba0a8ba8 --- /dev/null +++ b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -0,0 +1,1300 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_GAP_BLE_API_H__ +#define __ESP_GAP_BLE_API_H__ + +#include +#include + +#include "esp_err.h" +#include "esp_bt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/**@{ + * BLE_ADV_DATA_FLAG data flag bit definition used for advertising data flag + */ +#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0) +#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1) +#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2) +#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3) +#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4) +#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 ) +/** + * @} + */ + +/* relate to BTM_LE_KEY_xxx in stack/btm_api.h */ +#define ESP_LE_KEY_NONE 0 /* relate to BTM_LE_KEY_NONE in stack/btm_api.h */ +#define ESP_LE_KEY_PENC (1 << 0) /*!< encryption key, encryption information of peer device */ /* relate to BTM_LE_KEY_PENC in stack/btm_api.h */ +#define ESP_LE_KEY_PID (1 << 1) /*!< identity key of the peer device */ /* relate to BTM_LE_KEY_PID in stack/btm_api.h */ +#define ESP_LE_KEY_PCSRK (1 << 2) /*!< peer SRK */ /* relate to BTM_LE_KEY_PCSRK in stack/btm_api.h */ +#define ESP_LE_KEY_PLK (1 << 3) /*!< Link key*/ /* relate to BTM_LE_KEY_PLK in stack/btm_api.h */ +#define ESP_LE_KEY_LLK (ESP_LE_KEY_PLK << 4) /* relate to BTM_LE_KEY_LLK in stack/btm_api.h */ +#define ESP_LE_KEY_LENC (ESP_LE_KEY_PENC << 4) /*!< master role security information:div */ /* relate to BTM_LE_KEY_LENC in stack/btm_api.h */ +#define ESP_LE_KEY_LID (ESP_LE_KEY_PID << 4) /*!< master device ID key */ /* relate to BTM_LE_KEY_LID in stack/btm_api.h */ +#define ESP_LE_KEY_LCSRK (ESP_LE_KEY_PCSRK << 4) /*!< local CSRK has been deliver to peer */ /* relate to BTM_LE_KEY_LCSRK in stack/btm_api.h */ +typedef uint8_t esp_ble_key_type_t; + +/* relate to BTM_LE_AUTH_xxx in stack/btm_api.h */ +#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */ +#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */ +#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */ +#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/ +#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */ +#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */ +#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */ +#define ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) /*!< 1101 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM_BOND in stack/btm_api.h */ +typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit pattern */ + +#define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE 0 +#define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE 1 + +#define ESP_BLE_OOB_DISABLE 0 +#define ESP_BLE_OOB_ENABLE 1 + +/* relate to BTM_IO_CAP_xxx in stack/btm_api.h */ +#define ESP_IO_CAP_OUT 0 /*!< DisplayOnly */ /* relate to BTM_IO_CAP_OUT in stack/btm_api.h */ +#define ESP_IO_CAP_IO 1 /*!< DisplayYesNo */ /* relate to BTM_IO_CAP_IO in stack/btm_api.h */ +#define ESP_IO_CAP_IN 2 /*!< KeyboardOnly */ /* relate to BTM_IO_CAP_IN in stack/btm_api.h */ +#define ESP_IO_CAP_NONE 3 /*!< NoInputNoOutput */ /* relate to BTM_IO_CAP_NONE in stack/btm_api.h */ +#define ESP_IO_CAP_KBDISP 4 /*!< Keyboard display */ /* relate to BTM_IO_CAP_KBDISP in stack/btm_api.h */ + +#define ESP_BLE_APPEARANCE_UNKNOWN 0x0000 /* relate to BTM_BLE_APPEARANCE_UNKNOWN in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_PHONE 0x0040 /* relate to BTM_BLE_APPEARANCE_GENERIC_PHONE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_COMPUTER 0x0080 /* relate to BTM_BLE_APPEARANCE_GENERIC_COMPUTER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_WATCH 0x00C0 /* relate to BTM_BLE_APPEARANCE_GENERIC_WATCH in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_SPORTS_WATCH 0x00C1 /* relate to BTM_BLE_APPEARANCE_SPORTS_WATCH in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_CLOCK 0x0100 /* relate to BTM_BLE_APPEARANCE_GENERIC_CLOCK in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_DISPLAY 0x0140 /* relate to BTM_BLE_APPEARANCE_GENERIC_DISPLAY in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_REMOTE 0x0180 /* relate to BTM_BLE_APPEARANCE_GENERIC_REMOTE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 /* relate to BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_TAG 0x0200 /* relate to BTM_BLE_APPEARANCE_GENERIC_TAG in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_KEYRING 0x0240 /* relate to BTM_BLE_APPEARANCE_GENERIC_KEYRING in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 /* relate to BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 /* relate to BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_THERMOMETER 0x0300 /* relate to BTM_BLE_APPEARANCE_GENERIC_THERMOMETER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_THERMOMETER_EAR 0x0301 /* relate to BTM_BLE_APPEARANCE_THERMOMETER_EAR in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_HEART_RATE 0x0340 /* relate to BTM_BLE_APPEARANCE_GENERIC_HEART_RATE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HEART_RATE_BELT 0x0341 /* relate to BTM_BLE_APPEARANCE_HEART_RATE_BELT in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 /* relate to BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 /* relate to BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 /* relate to BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_HID 0x03C0 /* relate to BTM_BLE_APPEARANCE_GENERIC_HID in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_KEYBOARD 0x03C1 /* relate to BTM_BLE_APPEARANCE_HID_KEYBOARD in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_MOUSE 0x03C2 /* relate to BTM_BLE_APPEARANCE_HID_MOUSE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_JOYSTICK 0x03C3 /* relate to BTM_BLE_APPEARANCE_HID_JOYSTICK in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_GAMEPAD 0x03C4 /* relate to BTM_BLE_APPEARANCE_HID_GAMEPAD in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 /* relate to BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_CARD_READER 0x03C6 /* relate to BTM_BLE_APPEARANCE_HID_CARD_READER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_DIGITAL_PEN 0x03C7 /* relate to BTM_BLE_APPEARANCE_HID_DIGITAL_PEN in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 /* relate to BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_GLUCOSE 0x0400 /* relate to BTM_BLE_APPEARANCE_GENERIC_GLUCOSE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_WALKING 0x0440 /* relate to BTM_BLE_APPEARANCE_GENERIC_WALKING in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_WALKING_IN_SHOE 0x0441 /* relate to BTM_BLE_APPEARANCE_WALKING_IN_SHOE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_WALKING_ON_SHOE 0x0442 /* relate to BTM_BLE_APPEARANCE_WALKING_ON_SHOE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_WALKING_ON_HIP 0x0443 /* relate to BTM_BLE_APPEARANCE_WALKING_ON_HIP in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_CYCLING 0x0480 /* relate to BTM_BLE_APPEARANCE_GENERIC_CYCLING in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_CYCLING_COMPUTER 0x0481 /* relate to BTM_BLE_APPEARANCE_CYCLING_COMPUTER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_CYCLING_SPEED 0x0482 /* relate to BTM_BLE_APPEARANCE_CYCLING_SPEED in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_CYCLING_CADENCE 0x0483 /* relate to BTM_BLE_APPEARANCE_CYCLING_CADENCE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_CYCLING_POWER 0x0484 /* relate to BTM_BLE_APPEARANCE_CYCLING_POWER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 /* relate to BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 /* relate to BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 /* relate to BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 /* relate to BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_WEIGHT 0x0C80 /* relate to BTM_BLE_APPEARANCE_GENERIC_WEIGHT in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0 /* relate to BTM_BLE_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_POWERED_WHEELCHAIR 0x0CC1 /* relate to BTM_BLE_APPEARANCE_POWERED_WHEELCHAIR in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_MOBILITY_SCOOTER 0x0CC2 /* relate to BTM_BLE_APPEARANCE_MOBILITY_SCOOTER in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_CONTINUOUS_GLUCOSE_MONITOR 0x0D00 /* relate to BTM_BLE_APPEARANCE_GENERIC_CONTINUOUS_GLUCOSE_MONITOR in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40 /* relate to BTM_BLE_APPEARANCE_GENERIC_INSULIN_PUMP in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_INSULIN_PUMP_DURABLE_PUMP 0x0D41 /* relate to BTM_BLE_APPEARANCE_INSULIN_PUMP_DURABLE_PUMP in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_INSULIN_PUMP_PATCH_PUMP 0x0D44 /* relate to BTM_BLE_APPEARANCE_INSULIN_PUMP_PATCH_PUMP in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_INSULIN_PEN 0x0D48 /* relate to BTM_BLE_APPEARANCE_INSULIN_PEN in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80 /* relate to BTM_BLE_APPEARANCE_GENERIC_MEDICATION_DELIVERY in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 /* relate to BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 /* relate to BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 /* relate to BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 /* relate to BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD in stack/btm_ble_api.h */ +#define ESP_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 /* relate to BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV in stack/btm_ble_api.h */ + +typedef uint8_t esp_ble_io_cap_t; /*!< combination of the io capability */ + +/// GAP BLE callback event type +typedef enum { + ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT = 0, /*!< When advertising data set complete, the event comes */ + ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT, /*!< When scan response data set complete, the event comes */ + ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT, /*!< When scan parameters set complete, the event comes */ + ESP_GAP_BLE_SCAN_RESULT_EVT, /*!< When one scan result ready, the event comes each time */ + ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ + ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT, /*!< When raw advertising data set complete, the event comes */ + ESP_GAP_BLE_ADV_START_COMPLETE_EVT, /*!< When start advertising complete, the event comes */ + ESP_GAP_BLE_SCAN_START_COMPLETE_EVT, /*!< When start scan complete, the event comes */ + ESP_GAP_BLE_AUTH_CMPL_EVT, /* Authentication complete indication. */ + ESP_GAP_BLE_KEY_EVT, /* BLE key event for peer device keys */ + ESP_GAP_BLE_SEC_REQ_EVT, /* BLE security request */ + ESP_GAP_BLE_PASSKEY_NOTIF_EVT, /* passkey notification event */ + ESP_GAP_BLE_PASSKEY_REQ_EVT, /* passkey request event */ + ESP_GAP_BLE_OOB_REQ_EVT, /* OOB request event */ + ESP_GAP_BLE_LOCAL_IR_EVT, /* BLE local IR event */ + ESP_GAP_BLE_LOCAL_ER_EVT, /* BLE local ER event */ + ESP_GAP_BLE_NC_REQ_EVT, /* Numeric Comparison request event */ + ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT, /*!< When stop adv complete, the event comes */ + ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT, /*!< When stop scan complete, the event comes */ + ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT, /*!< When set the static rand address complete, the event comes */ + ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT, /*!< When update connection parameters complete, the event comes */ + ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT, /*!< When set pkt length complete, the event comes */ + ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT, /*!< When Enable/disable privacy on the local device complete, the event comes */ + ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT, /*!< When remove the bond device complete, the event comes */ + ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT, /*!< When clear the bond device clear complete, the event comes */ + ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT, /*!< When get the bond device list complete, the event comes */ + ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT, /*!< When read the rssi complete, the event comes */ + ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT, /*!< When add or remove whitelist complete, the event comes */ + ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT, /*!< When update duplicate exceptional list complete, the event comes */ + ESP_GAP_BLE_EVT_MAX, +} esp_gap_ble_cb_event_t; +/// This is the old name, just for backwards compatibility +#define ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT + +/// Advertising data maximum length +#define ESP_BLE_ADV_DATA_LEN_MAX 31 +/// Scan response data maximum length +#define ESP_BLE_SCAN_RSP_DATA_LEN_MAX 31 + +/* relate to BTM_BLE_AD_TYPE_xxx in stack/btm_ble_api.h */ +/// The type of advertising data(not adv_type) +typedef enum { + ESP_BLE_AD_TYPE_FLAG = 0x01, /* relate to BTM_BLE_AD_TYPE_FLAG in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_16SRV_PART = 0x02, /* relate to BTM_BLE_AD_TYPE_16SRV_PART in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_16SRV_CMPL = 0x03, /* relate to BTM_BLE_AD_TYPE_16SRV_CMPL in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_32SRV_PART = 0x04, /* relate to BTM_BLE_AD_TYPE_32SRV_PART in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_32SRV_CMPL = 0x05, /* relate to BTM_BLE_AD_TYPE_32SRV_CMPL in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_128SRV_PART = 0x06, /* relate to BTM_BLE_AD_TYPE_128SRV_PART in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_128SRV_CMPL = 0x07, /* relate to BTM_BLE_AD_TYPE_128SRV_CMPL in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_NAME_SHORT = 0x08, /* relate to BTM_BLE_AD_TYPE_NAME_SHORT in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_NAME_CMPL = 0x09, /* relate to BTM_BLE_AD_TYPE_NAME_CMPL in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_TX_PWR = 0x0A, /* relate to BTM_BLE_AD_TYPE_TX_PWR in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_DEV_CLASS = 0x0D, /* relate to BTM_BLE_AD_TYPE_DEV_CLASS in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SM_TK = 0x10, /* relate to BTM_BLE_AD_TYPE_SM_TK in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SM_OOB_FLAG = 0x11, /* relate to BTM_BLE_AD_TYPE_SM_OOB_FLAG in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_INT_RANGE = 0x12, /* relate to BTM_BLE_AD_TYPE_INT_RANGE in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SOL_SRV_UUID = 0x14, /* relate to BTM_BLE_AD_TYPE_SOL_SRV_UUID in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_128SOL_SRV_UUID = 0x15, /* relate to BTM_BLE_AD_TYPE_128SOL_SRV_UUID in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SERVICE_DATA = 0x16, /* relate to BTM_BLE_AD_TYPE_SERVICE_DATA in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_PUBLIC_TARGET = 0x17, /* relate to BTM_BLE_AD_TYPE_PUBLIC_TARGET in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_RANDOM_TARGET = 0x18, /* relate to BTM_BLE_AD_TYPE_RANDOM_TARGET in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_APPEARANCE = 0x19, /* relate to BTM_BLE_AD_TYPE_APPEARANCE in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_ADV_INT = 0x1A, /* relate to BTM_BLE_AD_TYPE_ADV_INT in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_LE_DEV_ADDR = 0x1b, /* relate to BTM_BLE_AD_TYPE_LE_DEV_ADDR in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_LE_ROLE = 0x1c, /* relate to BTM_BLE_AD_TYPE_LE_ROLE in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SPAIR_C256 = 0x1d, /* relate to BTM_BLE_AD_TYPE_SPAIR_C256 in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_SPAIR_R256 = 0x1e, /* relate to BTM_BLE_AD_TYPE_SPAIR_R256 in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_32SOL_SRV_UUID = 0x1f, /* relate to BTM_BLE_AD_TYPE_32SOL_SRV_UUID in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_32SERVICE_DATA = 0x20, /* relate to BTM_BLE_AD_TYPE_32SERVICE_DATA in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_128SERVICE_DATA = 0x21, /* relate to BTM_BLE_AD_TYPE_128SERVICE_DATA in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_LE_SECURE_CONFIRM = 0x22, /* relate to BTM_BLE_AD_TYPE_LE_SECURE_CONFIRM in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_LE_SECURE_RANDOM = 0x23, /* relate to BTM_BLE_AD_TYPE_LE_SECURE_RANDOM in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_URI = 0x24, /* relate to BTM_BLE_AD_TYPE_URI in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_INDOOR_POSITION = 0x25, /* relate to BTM_BLE_AD_TYPE_INDOOR_POSITION in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_TRANS_DISC_DATA = 0x26, /* relate to BTM_BLE_AD_TYPE_TRANS_DISC_DATA in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_LE_SUPPORT_FEATURE = 0x27, /* relate to BTM_BLE_AD_TYPE_LE_SUPPORT_FEATURE in stack/btm_ble_api.h */ + ESP_BLE_AD_TYPE_CHAN_MAP_UPDATE = 0x28, /* relate to BTM_BLE_AD_TYPE_CHAN_MAP_UPDATE in stack/btm_ble_api.h */ + ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE = 0xFF, /* relate to BTM_BLE_AD_MANUFACTURER_SPECIFIC_TYPE in stack/btm_ble_api.h */ +} esp_ble_adv_data_type; + +/// Advertising mode +typedef enum { + ADV_TYPE_IND = 0x00, + ADV_TYPE_DIRECT_IND_HIGH = 0x01, + ADV_TYPE_SCAN_IND = 0x02, + ADV_TYPE_NONCONN_IND = 0x03, + ADV_TYPE_DIRECT_IND_LOW = 0x04, +} esp_ble_adv_type_t; + +/// Advertising channel mask +typedef enum { + ADV_CHNL_37 = 0x01, + ADV_CHNL_38 = 0x02, + ADV_CHNL_39 = 0x04, + ADV_CHNL_ALL = 0x07, +} esp_ble_adv_channel_t; + +typedef enum { + ///Allow both scan and connection requests from anyone + ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY = 0x00, + ///Allow both scan req from White List devices only and connection req from anyone + ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY, + ///Allow both scan req from anyone and connection req from White List devices only + ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST, + ///Allow scan and connection requests from White List devices only + ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST, + ///Enumeration end value for advertising filter policy value check +} esp_ble_adv_filter_t; + + +/* relate to BTA_DM_BLE_SEC_xxx in bta/bta_api.h */ +typedef enum { + ESP_BLE_SEC_ENCRYPT = 1, /* relate to BTA_DM_BLE_SEC_ENCRYPT in bta/bta_api.h. If the device has already + bonded, the stack will used LTK to encrypt with the remote device directly. + Else if the device hasn't bonded, the stack will used the default authentication request + used the esp_ble_gap_set_security_param function set by the user. */ + ESP_BLE_SEC_ENCRYPT_NO_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_NO_MITM in bta/bta_api.h. If the device has already + bonded, the stack will check the LTK Whether the authentication request has been met, if met, used the LTK + to encrypt with the remote device directly, else Re-pair with the remote device. + Else if the device hasn't bonded, the stack will used NO MITM authentication request in the current link instead of + used the authreq in the esp_ble_gap_set_security_param function set by the user. */ + ESP_BLE_SEC_ENCRYPT_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_MITM in bta/bta_api.h. If the device has already + bonded, the stack will check the LTK Whether the authentication request has been met, if met, used the LTK + to encrypt with the remote device directly, else Re-pair with the remote device. + Else if the device hasn't bonded, the stack will used MITM authentication request in the current link instead of + used the authreq in the esp_ble_gap_set_security_param function set by the user. */ +}esp_ble_sec_act_t; + +typedef enum { + ESP_BLE_SM_PASSKEY = 0, + /* Authentication requirements of local device */ + ESP_BLE_SM_AUTHEN_REQ_MODE, + /* The IO capability of local device */ + ESP_BLE_SM_IOCAP_MODE, + /* Initiator Key Distribution/Generation */ + ESP_BLE_SM_SET_INIT_KEY, + /* Responder Key Distribution/Generation */ + ESP_BLE_SM_SET_RSP_KEY, + /* Maximum Encryption key size to support */ + ESP_BLE_SM_MAX_KEY_SIZE, + /* Minimum Encryption key size requirement from Peer */ + ESP_BLE_SM_MIN_KEY_SIZE, + /* Set static Passkey */ + ESP_BLE_SM_SET_STATIC_PASSKEY, + /* Reset static Passkey */ + ESP_BLE_SM_CLEAR_STATIC_PASSKEY, + /* Accept only specified SMP Authentication requirement */ + ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, + /* Enable/Disable OOB support */ + ESP_BLE_SM_OOB_SUPPORT, + /* Appl encryption key size */ + ESP_BLE_APP_ENC_KEY_SIZE, + ESP_BLE_SM_MAX_PARAM, +} esp_ble_sm_param_t; + +/// Advertising parameters +typedef struct { + uint16_t adv_int_min; /*!< Minimum advertising interval for + undirected and low duty cycle directed advertising. + Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second) + Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec */ + uint16_t adv_int_max; /*!< Maximum advertising interval for + undirected and low duty cycle directed advertising. + Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second) + Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec Advertising max interval */ + esp_ble_adv_type_t adv_type; /*!< Advertising type */ + esp_ble_addr_type_t own_addr_type; /*!< Owner bluetooth device address type */ + esp_bd_addr_t peer_addr; /*!< Peer device bluetooth device address */ + esp_ble_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type, only support public address type and random address type */ + esp_ble_adv_channel_t channel_map; /*!< Advertising channel map */ + esp_ble_adv_filter_t adv_filter_policy; /*!< Advertising filter policy */ +} esp_ble_adv_params_t; + +/// Advertising data content, according to "Supplement to the Bluetooth Core Specification" +typedef struct { + bool set_scan_rsp; /*!< Set this advertising data as scan response or not*/ + bool include_name; /*!< Advertising data include device name or not */ + bool include_txpower; /*!< Advertising data include TX power */ + int min_interval; /*!< Advertising data show slave preferred connection min interval. + The connection interval in the following manner: + connIntervalmin = Conn_Interval_Min * 1.25 ms + Conn_Interval_Min range: 0x0006 to 0x0C80 + Value of 0xFFFF indicates no specific minimum. + Values not defined above are reserved for future use.*/ + + int max_interval; /*!< Advertising data show slave preferred connection max interval. + The connection interval in the following manner: + connIntervalmax = Conn_Interval_Max * 1.25 ms + Conn_Interval_Max range: 0x0006 to 0x0C80 + Conn_Interval_Max shall be equal to or greater than the Conn_Interval_Min. + Value of 0xFFFF indicates no specific maximum. + Values not defined above are reserved for future use.*/ + + int appearance; /*!< External appearance of device */ + uint16_t manufacturer_len; /*!< Manufacturer data length */ + uint8_t *p_manufacturer_data; /*!< Manufacturer data point */ + uint16_t service_data_len; /*!< Service data length */ + uint8_t *p_service_data; /*!< Service data point */ + uint16_t service_uuid_len; /*!< Service uuid length */ + uint8_t *p_service_uuid; /*!< Service uuid array point */ + uint8_t flag; /*!< Advertising flag of discovery mode, see BLE_ADV_DATA_FLAG detail */ +} esp_ble_adv_data_t; + +/// Ble scan type +typedef enum { + BLE_SCAN_TYPE_PASSIVE = 0x0, /*!< Passive scan */ + BLE_SCAN_TYPE_ACTIVE = 0x1, /*!< Active scan */ +} esp_ble_scan_type_t; + +/// Ble scan filter type +typedef enum { + BLE_SCAN_FILTER_ALLOW_ALL = 0x0, /*!< Accept all : + 1. advertisement packets except directed advertising packets not addressed to this device (default). */ + BLE_SCAN_FILTER_ALLOW_ONLY_WLST = 0x1, /*!< Accept only : + 1. advertisement packets from devices where the advertiser’s address is in the White list. + 2. Directed advertising packets which are not addressed for this device shall be ignored. */ + BLE_SCAN_FILTER_ALLOW_UND_RPA_DIR = 0x2, /*!< Accept all : + 1. undirected advertisement packets, and + 2. directed advertising packets where the initiator address is a resolvable private address, and + 3. directed advertising packets addressed to this device. */ + BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR = 0x3, /*!< Accept all : + 1. advertisement packets from devices where the advertiser’s address is in the White list, and + 2. directed advertising packets where the initiator address is a resolvable private address, and + 3. directed advertising packets addressed to this device.*/ +} esp_ble_scan_filter_t; + +/// Ble scan duplicate type +typedef enum { + BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */ + BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */ + BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 – 0xFF, Reserved for future use */ +} esp_ble_scan_duplicate_t; + +/// Ble scan parameters +typedef struct { + esp_ble_scan_type_t scan_type; /*!< Scan type */ + esp_ble_addr_type_t own_addr_type; /*!< Owner address type */ + esp_ble_scan_filter_t scan_filter_policy; /*!< Scan filter policy */ + uint16_t scan_interval; /*!< Scan interval. This is defined as the time interval from + when the Controller started its last LE scan until it begins the subsequent LE scan. + Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms) + Time = N * 0.625 msec + Time Range: 2.5 msec to 10.24 seconds*/ + uint16_t scan_window; /*!< Scan window. The duration of the LE scan. LE_Scan_Window + shall be less than or equal to LE_Scan_Interval + Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms) + Time = N * 0.625 msec + Time Range: 2.5 msec to 10240 msec */ + esp_ble_scan_duplicate_t scan_duplicate; /*!< The Scan_Duplicates parameter controls whether the Link Layer should filter out + duplicate advertising reports (BLE_SCAN_DUPLICATE_ENABLE) to the Host, or if the Link Layer should generate + advertising reports for each packet received */ +} esp_ble_scan_params_t; + +/// connection parameters information +typedef struct { + uint16_t interval; /*!< connection interval */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. + Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec + Time Range: 100 msec to 32 seconds */ +} esp_gap_conn_params_t; + +/// Connection update parameters +typedef struct { + esp_bd_addr_t bda; /*!< Bluetooth device address */ + uint16_t min_int; /*!< Min connection interval */ + uint16_t max_int; /*!< Max connection interval */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. + Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec + Time Range: 100 msec to 32 seconds */ +} esp_ble_conn_update_params_t; + +/** +* @brief BLE pkt date length keys +*/ +typedef struct +{ + uint16_t rx_len; /*!< pkt rx data length value */ + uint16_t tx_len; /*!< pkt tx data length value */ +}esp_ble_pkt_data_length_params_t; + +/** +* @brief BLE encryption keys +*/ +typedef struct +{ + esp_bt_octet16_t ltk; /*!< The long term key*/ + esp_bt_octet8_t rand; /*!< The random number*/ + uint16_t ediv; /*!< The ediv value*/ + uint8_t sec_level; /*!< The security level of the security link*/ + uint8_t key_size; /*!< The key size(7~16) of the security link*/ +} esp_ble_penc_keys_t; /*!< The key type*/ + +/** +* @brief BLE CSRK keys +*/ +typedef struct +{ + uint32_t counter; /*!< The counter */ + esp_bt_octet16_t csrk; /*!< The csrk key */ + uint8_t sec_level; /*!< The security level */ +} esp_ble_pcsrk_keys_t; /*!< The pcsrk key type */ + +/** +* @brief BLE pid keys +*/ +typedef struct +{ + esp_bt_octet16_t irk; /*!< The irk value */ + esp_ble_addr_type_t addr_type; /*!< The address type */ + esp_bd_addr_t static_addr; /*!< The static address */ +} esp_ble_pid_keys_t; /*!< The pid key type */ + +/** +* @brief BLE Encryption reproduction keys +*/ +typedef struct +{ + esp_bt_octet16_t ltk; /*!< The long term key */ + uint16_t div; /*!< The div value */ + uint8_t key_size; /*!< The key size of the security link */ + uint8_t sec_level; /*!< The security level of the security link */ +} esp_ble_lenc_keys_t; /*!< The key type */ + +/** +* @brief BLE SRK keys +*/ +typedef struct +{ + uint32_t counter; /*!< The counter value */ + uint16_t div; /*!< The div value */ + uint8_t sec_level; /*!< The security level of the security link */ + esp_bt_octet16_t csrk; /*!< The csrk key value */ +} esp_ble_lcsrk_keys; /*!< The csrk key type */ + +/** +* @brief Structure associated with ESP_KEY_NOTIF_EVT +*/ +typedef struct +{ + esp_bd_addr_t bd_addr; /*!< peer address */ + uint32_t passkey; /*!< the numeric value for comparison. If just_works, do not show this number to UI */ +} esp_ble_sec_key_notif_t; /*!< BLE key notify type*/ + +/** +* @brief Structure of the security request +*/ +typedef struct +{ + esp_bd_addr_t bd_addr; /*!< peer address */ +} esp_ble_sec_req_t; /*!< BLE security request type*/ + +/** +* @brief union type of the security key value +*/ +typedef union +{ + esp_ble_penc_keys_t penc_key; /*!< received peer encryption key */ + esp_ble_pcsrk_keys_t pcsrk_key; /*!< received peer device SRK */ + esp_ble_pid_keys_t pid_key; /*!< peer device ID key */ + esp_ble_lenc_keys_t lenc_key; /*!< local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + esp_ble_lcsrk_keys lcsrk_key; /*!< local device CSRK = d1(ER,DIV,1)*/ +} esp_ble_key_value_t; /*!< ble key value type*/ + +/** +* @brief struct type of the bond key information value +*/ +typedef struct +{ + esp_ble_key_mask_t key_mask; /*!< the key mask to indicate witch key is present */ + esp_ble_penc_keys_t penc_key; /*!< received peer encryption key */ + esp_ble_pcsrk_keys_t pcsrk_key; /*!< received peer device SRK */ + esp_ble_pid_keys_t pid_key; /*!< peer device ID key */ +} esp_ble_bond_key_info_t; /*!< ble bond key information value type */ + +/** +* @brief struct type of the bond device value +*/ +typedef struct +{ + esp_bd_addr_t bd_addr; /*!< peer address */ + esp_ble_bond_key_info_t bond_key; /*!< the bond key information */ +} esp_ble_bond_dev_t; /*!< the ble bond device type */ + + +/** +* @brief union type of the security key value +*/ +typedef struct +{ + esp_bd_addr_t bd_addr; /*!< peer address */ + esp_ble_key_type_t key_type; /*!< key type of the security link */ + esp_ble_key_value_t p_key_value; /*!< the pointer to the key value */ +} esp_ble_key_t; /*!< the union to the ble key value type*/ + +/** +* @brief structure type of the ble local id keys value +*/ +typedef struct { + esp_bt_octet16_t ir; /*!< the 16 bits of the ir value */ + esp_bt_octet16_t irk; /*!< the 16 bits of the ir key value */ + esp_bt_octet16_t dhk; /*!< the 16 bits of the dh key value */ +} esp_ble_local_id_keys_t; /*!< the structure of the ble local id keys value type*/ + + +/** + * @brief Structure associated with ESP_AUTH_CMPL_EVT + */ +typedef struct +{ + esp_bd_addr_t bd_addr; /*!< BD address peer device. */ + bool key_present; /*!< Valid link key value in key element */ + esp_link_key key; /*!< Link key associated with peer device. */ + uint8_t key_type; /*!< The type of Link Key */ + bool success; /*!< TRUE of authentication succeeded, FALSE if failed. */ + uint8_t fail_reason; /*!< The HCI reason/error code for when success=FALSE */ + esp_ble_addr_type_t addr_type; /*!< Peer device address type */ + esp_bt_dev_type_t dev_type; /*!< Device type */ + esp_ble_auth_req_t auth_mode; /*!< authentication mode */ +} esp_ble_auth_cmpl_t; /*!< The ble authentication complete cb type */ + +/** + * @brief union associated with ble security + */ +typedef union +{ + esp_ble_sec_key_notif_t key_notif; /*!< passkey notification */ + esp_ble_sec_req_t ble_req; /*!< BLE SMP related request */ + esp_ble_key_t ble_key; /*!< BLE SMP keys used when pairing */ + esp_ble_local_id_keys_t ble_id_keys; /*!< BLE IR event */ + esp_ble_auth_cmpl_t auth_cmpl; /*!< Authentication complete indication. */ +} esp_ble_sec_t; /*!< BLE security type */ + +/// Sub Event of ESP_GAP_BLE_SCAN_RESULT_EVT +typedef enum { + ESP_GAP_SEARCH_INQ_RES_EVT = 0, /*!< Inquiry result for a peer device. */ + ESP_GAP_SEARCH_INQ_CMPL_EVT = 1, /*!< Inquiry complete. */ + ESP_GAP_SEARCH_DISC_RES_EVT = 2, /*!< Discovery result for a peer device. */ + ESP_GAP_SEARCH_DISC_BLE_RES_EVT = 3, /*!< Discovery result for BLE GATT based service on a peer device. */ + ESP_GAP_SEARCH_DISC_CMPL_EVT = 4, /*!< Discovery complete. */ + ESP_GAP_SEARCH_DI_DISC_CMPL_EVT = 5, /*!< Discovery complete. */ + ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT = 6, /*!< Search cancelled */ + ESP_GAP_SEARCH_INQ_DISCARD_NUM_EVT = 7, /*!< The number of pkt discarded by flow control */ +} esp_gap_search_evt_t; + +/** + * @brief Ble scan result event type, to indicate the + * result is scan response or advertising data or other + */ +typedef enum { + ESP_BLE_EVT_CONN_ADV = 0x00, /*!< Connectable undirected advertising (ADV_IND) */ + ESP_BLE_EVT_CONN_DIR_ADV = 0x01, /*!< Connectable directed advertising (ADV_DIRECT_IND) */ + ESP_BLE_EVT_DISC_ADV = 0x02, /*!< Scannable undirected advertising (ADV_SCAN_IND) */ + ESP_BLE_EVT_NON_CONN_ADV = 0x03, /*!< Non connectable undirected advertising (ADV_NONCONN_IND) */ + ESP_BLE_EVT_SCAN_RSP = 0x04, /*!< Scan Response (SCAN_RSP) */ +} esp_ble_evt_type_t; + +typedef enum{ + ESP_BLE_WHITELIST_REMOVE = 0X00, /*!< remove mac from whitelist */ + ESP_BLE_WHITELIST_ADD = 0X01, /*!< add address to whitelist */ +}esp_ble_wl_opration_t; + +typedef enum { + ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD = 0, /*!< Add device info into duplicate scan exceptional list */ + ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_REMOVE, /*!< Remove device info from duplicate scan exceptional list */ + ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_CLEAN, /*!< Clean duplicate scan exceptional list */ +} esp_bt_duplicate_exceptional_subcode_type_t; + +#define BLE_BIT(n) (1UL<<(n)) + +typedef enum { + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR = 0, /*!< BLE advertising address , device info will be added into ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ADDR_LIST */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID, /*!< BLE mesh link ID, it is for BLE mesh, device info will be added into ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_LINK_ID_LIST */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_BEACON_TYPE, /*!< BLE mesh beacon AD type, the format is | Len | 0x2B | Beacon Type | Beacon Data | */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROV_SRV_ADV, /*!< BLE mesh provisioning service uuid, the format is | 0x02 | 0x01 | flags | 0x03 | 0x03 | 0x1827 | .... |` */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROXY_SRV_ADV, /*!< BLE mesh adv with proxy service uuid, the format is | 0x02 | 0x01 | flags | 0x03 | 0x03 | 0x1828 | .... |` */ +} esp_ble_duplicate_exceptional_info_type_t; + +typedef enum { + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ADDR_LIST = BLE_BIT(0), /*!< duplicate scan exceptional addr list */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_LINK_ID_LIST = BLE_BIT(1), /*!< duplicate scan exceptional mesh link ID list */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_BEACON_TYPE_LIST = BLE_BIT(2), /*!< duplicate scan exceptional mesh beacon type list */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_PROV_SRV_ADV_LIST = BLE_BIT(3), /*!< duplicate scan exceptional mesh adv with provisioning service uuid */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_PROXY_SRV_ADV_LIST = BLE_BIT(4), /*!< duplicate scan exceptional mesh adv with provisioning service uuid */ + ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ALL_LIST = 0xFFFF, /*!< duplicate scan exceptional all list */ +} esp_duplicate_scan_exceptional_list_type_t; + +typedef uint8_t esp_duplicate_info_t[ESP_BD_ADDR_LEN]; + +/** + * @brief Gap callback parameters union + */ +typedef union { + /** + * @brief ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT + */ + struct ble_adv_data_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set advertising data operation success status */ + } adv_data_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT + */ + struct ble_scan_rsp_data_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set scan response data operation success status */ + } scan_rsp_data_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT + */ + struct ble_scan_param_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set scan param operation success status */ + } scan_param_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_RESULT_EVT + */ + struct ble_scan_result_evt_param { + esp_gap_search_evt_t search_evt; /*!< Search event type */ + esp_bd_addr_t bda; /*!< Bluetooth device address which has been searched */ + esp_bt_dev_type_t dev_type; /*!< Device type */ + esp_ble_addr_type_t ble_addr_type; /*!< Ble device address type */ + esp_ble_evt_type_t ble_evt_type; /*!< Ble scan result event type */ + int rssi; /*!< Searched device's RSSI */ + uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX + ESP_BLE_SCAN_RSP_DATA_LEN_MAX]; /*!< Received EIR */ + int flag; /*!< Advertising data flag bit */ + int num_resps; /*!< Scan result number */ + uint8_t adv_data_len; /*!< Adv data length */ + uint8_t scan_rsp_len; /*!< Scan response length */ + uint32_t num_dis; /*!< The number of discard packets */ + } scan_rst; /*!< Event parameter of ESP_GAP_BLE_SCAN_RESULT_EVT */ + /** + * @brief ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT + */ + struct ble_adv_data_raw_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set raw advertising data operation success status */ + } adv_data_raw_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT + */ + struct ble_scan_rsp_data_raw_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set raw advertising data operation success status */ + } scan_rsp_data_raw_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_ADV_START_COMPLETE_EVT + */ + struct ble_adv_start_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate advertising start operation success status */ + } adv_start_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_START_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SCAN_START_COMPLETE_EVT + */ + struct ble_scan_start_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate scan start operation success status */ + } scan_start_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_START_COMPLETE_EVT */ + + esp_ble_sec_t ble_security; /*!< ble gap security union type */ + /** + * @brief ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT + */ + struct ble_scan_stop_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate scan stop operation success status */ + } scan_stop_cmpl; /*!< Event parameter of ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT + */ + struct ble_adv_stop_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate adv stop operation success status */ + } adv_stop_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT + */ + struct ble_set_rand_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate set static rand address operation success status */ + } set_rand_addr_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT */ + /** + * @brief ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT + */ + struct ble_update_conn_params_evt_param { + esp_bt_status_t status; /*!< Indicate update connection parameters success status */ + esp_bd_addr_t bda; /*!< Bluetooth device address */ + uint16_t min_int; /*!< Min connection interval */ + uint16_t max_int; /*!< Max connection interval */ + uint16_t latency; /*!< Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3 */ + uint16_t conn_int; /*!< Current connection interval */ + uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. + Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec */ + }update_conn_params; /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */ + /** + * @brief ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT + */ + struct ble_pkt_data_length_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set pkt data length operation success status */ + esp_ble_pkt_data_length_params_t params; /*!< pkt data length value */ + } pkt_data_lenth_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT + */ + struct ble_local_privacy_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the set local privacy operation success status */ + } local_privacy_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT + */ + struct ble_remove_bond_dev_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the remove bond device operation success status */ + esp_bd_addr_t bd_addr; /*!< The device address which has been remove from the bond list */ + }remove_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT + */ + struct ble_clear_bond_dev_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the clear bond device operation success status */ + }clear_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT + */ + struct ble_get_bond_dev_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the get bond device operation success status */ + uint8_t dev_num; /*!< Indicate the get number device in the bond list */ + esp_ble_bond_dev_t *bond_dev; /*!< the pointer to the bond device Structure */ + }get_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT + */ + struct ble_read_rssi_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the read adv tx power operation success status */ + int8_t rssi; /*!< The ble remote device rssi value, the range is from -127 to 20, the unit is dbm, + if the RSSI cannot be read, the RSSI metric shall be set to 127. */ + esp_bd_addr_t remote_addr; /*!< The remote device address */ + } read_rssi_cmpl; /*!< Event parameter of ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT + */ + struct ble_update_whitelist_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate the add or remove whitelist operation success status */ + esp_ble_wl_opration_t wl_opration; /*!< The value is ESP_BLE_WHITELIST_ADD if add address to whitelist operation success, ESP_BLE_WHITELIST_REMOVE if remove address from the whitelist operation success */ + } update_whitelist_cmpl; /*!< Event parameter of ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT + */ + struct ble_update_duplicate_exceptional_list_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate update duplicate scan exceptional list operation success status */ + uint8_t subcode; /*!< Define in esp_bt_duplicate_exceptional_subcode_type_t */ + uint16_t length; /*!< The length of device_info */ + esp_duplicate_info_t device_info; /*!< device information, when subcode is ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_CLEAN, the value is invalid */ + } update_duplicate_exceptional_list_cmpl; /*!< Event parameter of ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT */ +} esp_ble_gap_cb_param_t; + +/** + * @brief GAP callback function type + * @param event : Event type + * @param param : Point to callback parameter, currently is union type + */ +typedef void (* esp_gap_ble_cb_t)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + +/** + * @brief This function is called to occur gap event, such as scan result + * + * @param[in] callback: callback function + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_register_callback(esp_gap_ble_cb_t callback); + + +/** + * @brief This function is called to override the BTA default ADV parameters. + * + * @param[in] adv_data: Pointer to User defined ADV data structure. This + * memory space can not be freed until callback of config_adv_data + * is received. + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_config_adv_data (esp_ble_adv_data_t *adv_data); + + + +/** + * @brief This function is called to set scan parameters + * + * @param[in] scan_params: Pointer to User defined scan_params data structure. This + * memory space can not be freed until callback of set_scan_params + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_set_scan_params(esp_ble_scan_params_t *scan_params); + + +/** + * @brief This procedure keep the device scanning the peer device which advertising on the air + * + * @param[in] duration: Keeping the scanning time, the unit is second. + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_start_scanning(uint32_t duration); + + +/** + * @brief This function call to stop the device scanning the peer device which advertising on the air + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_stop_scanning(void); + +/** + * @brief This function is called to start advertising. + * + * @param[in] adv_params: pointer to User defined adv_params data structure. + + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_start_advertising (esp_ble_adv_params_t *adv_params); + + + +/** + * @brief This function is called to stop advertising. + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_stop_advertising(void); + + + +/** + * @brief Update connection parameters, can only be used when connection is up. + * + * @param[in] params - connection update parameters + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params); + + +/** + * @brief This function is to set maximum LE data packet size + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_data_length); + +/** + * @brief This function sets the static Random Address and Non-Resolvable Private Address for the application + * + * @param[in] rand_addr: the random address which should be setting + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr); + +/** + * @brief This function clears the random address for the application + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_clear_rand_addr(void); + + + +/** + * @brief Enable/disable privacy on the local device + * + * @param[in] privacy_enable - enable/disable privacy on remote device. + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_config_local_privacy (bool privacy_enable); + +/** + * @brief set local gap appearance icon + * + * + * @param[in] icon - External appearance value, these values are defined by the Bluetooth SIG, please refer to + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_config_local_icon (uint16_t icon); + +/** +* @brief Add or remove device from white list +* +* @param[in] add_remove: the value is true if added the ble device to the white list, and false remove to the white list. +* @param[in] remote_bda: the remote device address add/remove from the white list. +* @param[in] wl_addr_type: whitelist address type +* @return +* - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_update_whitelist(bool add_remove, esp_bd_addr_t remote_bda, esp_ble_wl_addr_type_t wl_addr_type); + +/** +* @brief Get the whitelist size in the controller +* +* @param[out] length: the white list length. +* @return +* - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_get_whitelist_size(uint16_t *length); + +/** +* @brief This function is called to set the preferred connection +* parameters when default connection parameter is not desired before connecting. +* This API can only be used in the master role. +* +* @param[in] bd_addr: BD address of the peripheral +* @param[in] min_conn_int: minimum preferred connection interval +* @param[in] max_conn_int: maximum preferred connection interval +* @param[in] slave_latency: preferred slave latency +* @param[in] supervision_tout: preferred supervision timeout +* +* @return +* - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr, + uint16_t min_conn_int, uint16_t max_conn_int, + uint16_t slave_latency, uint16_t supervision_tout); + +/** + * @brief Set device name to the local device + * + * @param[in] name - device name. + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_set_device_name(const char *name); + +/** + * @brief This function is called to get local used address and adress type. + * uint8_t *esp_bt_dev_get_address(void) get the public address + * + * @param[in] local_used_addr - current local used ble address (six bytes) + * @param[in] addr_type - ble address type + * + * @return - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t * addr_type); +/** + * @brief This function is called to get ADV data for a specific type. + * + * @param[in] adv_data - pointer of ADV data which to be resolved + * @param[in] type - finding ADV data type + * @param[out] length - return the length of ADV data not including type + * + * @return pointer of ADV data + * + */ +uint8_t *esp_ble_resolve_adv_data(uint8_t *adv_data, uint8_t type, uint8_t *length); + +/** + * @brief This function is called to set raw advertising data. User need to fill + * ADV data by self. + * + * @param[in] raw_data : raw advertising data + * @param[in] raw_data_len : raw advertising data length , less than 31 bytes + * + * @return + * - ESP_OK : success + * - other : failed + * + */ +esp_err_t esp_ble_gap_config_adv_data_raw(uint8_t *raw_data, uint32_t raw_data_len); + +/** + * @brief This function is called to set raw scan response data. User need to fill + * scan response data by self. + * + * @param[in] raw_data : raw scan response data + * @param[in] raw_data_len : raw scan response data length , less than 31 bytes + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_data_len); + +/** + * @brief This function is called to read the RSSI of remote device. + * The address of link policy results are returned in the gap callback function with + * ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT event. + * + * @param[in] remote_addr : The remote connection device address. + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_read_rssi(esp_bd_addr_t remote_addr); + +/** + * @brief This function is called to add a device info into the duplicate scan exceptional list. + * + * + * @param[in] type: device info type, it is defined in esp_ble_duplicate_exceptional_info_type_t + * when type is MESH_BEACON_TYPE, MESH_PROV_SRV_ADV or MESH_PROXY_SRV_ADV , device_info is invalid. + * @param[in] device_info: the device information. + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_add_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info); + +/** + * @brief This function is called to remove a device info from the duplicate scan exceptional list. + * + * + * @param[in] type: device info type, it is defined in esp_ble_duplicate_exceptional_info_type_t + * when type is MESH_BEACON_TYPE, MESH_PROV_SRV_ADV or MESH_PROXY_SRV_ADV , device_info is invalid. + * @param[in] device_info: the device information. + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_remove_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info); + +/** + * @brief This function is called to clean the duplicate scan exceptional list. + * This API will delete all device information in the duplicate scan exceptional list. + * + * + * @param[in] list_type: duplicate scan exceptional list type, the value can be one or more of esp_duplicate_scan_exceptional_list_type_t. + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_clean_duplicate_scan_exceptional_list(esp_duplicate_scan_exceptional_list_type_t list_type); + +#if (SMP_INCLUDED == TRUE) +/** +* @brief Set a GAP security parameter value. Overrides the default value. +* +* Secure connection is highly recommended to avoid some major +* vulnerabilities like 'Impersonation in the Pin Pairing Protocol' +* (CVE-2020-26555) and 'Authentication of the LE Legacy Pairing +* Protocol'. +* +* To accept only `secure connection mode`, it is necessary do as following: +* +* 1. Set bit `ESP_LE_AUTH_REQ_SC_ONLY` (`param_type` is +* `ESP_BLE_SM_AUTHEN_REQ_MODE`), bit `ESP_LE_AUTH_BOND` and bit +* `ESP_LE_AUTH_REQ_MITM` is optional as required. +* +* 2. Set to `ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE` (`param_type` is +* `ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH`). +* +* @param[in] param_type : the type of the param which to be set +* @param[in] value : the param value +* @param[in] len : the length of the param value +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_set_security_param(esp_ble_sm_param_t param_type, + void *value, uint8_t len); + +/** +* @brief Grant security request access. +* +* @param[in] bd_addr : BD address of the peer +* @param[in] accept : accept the security request or not +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_security_rsp(esp_bd_addr_t bd_addr, bool accept); + + +/** +* @brief Set a gap parameter value. Use this function to change +* the default GAP parameter values. +* +* @param[in] bd_addr : the address of the peer device need to encryption +* @param[in] sec_act : This is the security action to indicate +* what kind of BLE security level is required for +* the BLE link if the BLE is supported +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_set_encryption(esp_bd_addr_t bd_addr, esp_ble_sec_act_t sec_act); + +/** +* @brief Reply the key value to the peer device in the legacy connection stage. +* +* @param[in] bd_addr : BD address of the peer +* @param[in] accept : passkey entry successful or declined. +* @param[in] passkey : passkey value, must be a 6 digit number, +* can be lead by 0. +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t passkey); + + +/** +* @brief Reply the confirm value to the peer device in the secure connection stage. +* +* @param[in] bd_addr : BD address of the peer device +* @param[in] accept : numbers to compare are the same or different. +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_confirm_reply(esp_bd_addr_t bd_addr, bool accept); + +/** +* @brief Removes a device from the security database list of +* peer device. It manages unpairing event while connected. +* +* @param[in] bd_addr : BD address of the peer device +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_remove_bond_device(esp_bd_addr_t bd_addr); + +/** +* @brief Get the device number from the security database list of peer device. +* It will return the device bonded number immediately. +* +* @return - >= 0 : bonded devices number. +* - ESP_FAIL : failed +* +*/ +int esp_ble_get_bond_device_num(void); + + +/** +* @brief Get the device from the security database list of peer device. +* It will return the device bonded information immediately. +* @param[inout] dev_num: Indicate the dev_list array(buffer) size as input. +* If dev_num is large enough, it means the actual number as output. +* Suggest that dev_num value equal to esp_ble_get_bond_device_num(). +* +* @param[out] dev_list: an array(buffer) of `esp_ble_bond_dev_t` type. Use for storing the bonded devices address. +* The dev_list should be allocated by who call this API. +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_list); + +/** +* @brief This function is called to provide the OOB data for +* SMP in response to ESP_GAP_BLE_OOB_REQ_EVT +* +* @param[in] bd_addr: BD address of the peer device. +* @param[in] TK: TK value, the TK value shall be a 128-bit random number +* @param[in] len: length of tk, should always be 128-bit +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len); + +#endif /* #if (SMP_INCLUDED == TRUE) */ + +/** +* @brief This function is to disconnect the physical connection of the peer device +* gattc may have multiple virtual GATT server connections when multiple app_id registered. +* esp_ble_gattc_close (esp_gatt_if_t gattc_if, uint16_t conn_id) only close one virtual GATT server connection. +* if there exist other virtual GATT server connections, it does not disconnect the physical connection. +* esp_ble_gap_disconnect(esp_bd_addr_t remote_device) disconnect the physical connection directly. +* +* +* +* @param[in] remote_device : BD address of the peer device +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device); + +/** +* @brief This function is called to read the connection +* parameters information of the device +* +* @param[in] bd_addr: BD address of the peer device. +* @param[out] conn_params: the connection parameters information +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_ble_get_current_conn_params(esp_bd_addr_t bd_addr, esp_gap_conn_params_t *conn_params); + +/** +* @brief This function is called to authorized a link after Authentication(MITM protection) +* +* @param[in] bd_addr: BD address of the peer device. +* @param[out] authorize: Authorized the link or not. +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t esp_gap_ble_set_authorization(esp_bd_addr_t bd_addr, bool authorize); +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_GAP_BLE_API_H__ */ diff --git a/components/bt/host/bluedroid/stack/smp/smp_act.c b/components/bt/host/bluedroid/stack/smp/smp_act.c new file mode 100644 index 0000000000..0ff45ad4aa --- /dev/null +++ b/components/bt/host/bluedroid/stack/smp/smp_act.c @@ -0,0 +1,2187 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include +#include "device/interop.h" +#include "common/bt_target.h" +#include "btm_int.h" +#include "stack/l2c_api.h" +#include "smp_int.h" +#include "p_256_ecc_pp.h" +//#include "utils/include/bt_utils.h" + +#if SMP_INCLUDED == TRUE +const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = { + /* initiator */ + { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF} + }, /* keyboard display */ + /* responder */ + { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY} + } /* keyboard display */ + /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */ +}; + +#define SMP_KEY_DIST_TYPE_MAX 4 +const tSMP_ACT smp_distribute_act [] = { +#if (BLE_INCLUDED == TRUE) + smp_generate_ltk, + smp_send_id_info, + smp_generate_csrk, + smp_set_derive_link_key +#else + NULL, + NULL, + NULL, + NULL +#endif ///BLE_INCLUDED == TRUE +}; + +extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void); +extern UINT8 bta_dm_co_ble_get_auth_req(void); + +static bool lmp_version_below(BD_ADDR bda, uint8_t version) +{ + tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE); + if (acl == NULL || acl->lmp_version == 0) { + SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__); + return false; + } + SMP_TRACE_DEBUG("%s LMP version %d < %d", __func__, acl->lmp_version, version); + return acl->lmp_version < version; +} + +/******************************************************************************* +** Function smp_update_key_mask +** Description This function updates the key mask for sending or receiving. +*******************************************************************************/ +static void smp_update_key_mask (tSMP_CB *p_cb, UINT8 key_type, BOOLEAN recv) +{ + SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x\n", + __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key); + + if (((p_cb->le_secure_connections_mode_is_used) || + (p_cb->smp_over_br)) && + ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK))) { + /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of + ** being exchanged with the peer */ + p_cb->local_i_key &= ~key_type; + p_cb->local_r_key &= ~key_type; + } else if (p_cb->role == HCI_ROLE_SLAVE) { + if (recv) { + p_cb->local_i_key &= ~key_type; + } else { + p_cb->local_r_key &= ~key_type; + } + } else { + if (recv) { + p_cb->local_r_key &= ~key_type; + } else { + p_cb->local_i_key &= ~key_type; + } + } + + SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x\n", p_cb->local_i_key, + p_cb->local_r_key); +} + +/******************************************************************************* +** Function smp_send_app_cback +** Description notifies application about the events the application is interested in +*******************************************************************************/ +void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_EVT_DATA cb_data; + tSMP_STATUS callback_rc; + SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d\n", __func__, p_cb->cb_evt); + if (p_cb->p_callback && p_cb->cb_evt != 0) { + switch (p_cb->cb_evt) { + case SMP_IO_CAP_REQ_EVT: + cb_data.io_req.auth_req = p_cb->peer_auth_req; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = p_cb->local_i_key ; + cb_data.io_req.resp_keys = p_cb->local_r_key ; + SMP_TRACE_DEBUG ( "io_cap = %d", cb_data.io_req.io_cap); + break; + + case SMP_NC_REQ_EVT: + cb_data.passkey = p_data->passkey; + break; + case SMP_SC_OOB_REQ_EVT: + cb_data.req_oob_type = p_data->req_oob_type; + break; + case SMP_SC_LOC_OOB_DATA_UP_EVT: + cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data; + break; + + case SMP_BR_KEYS_REQ_EVT: + cb_data.io_req.auth_req = 0; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = 0; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY; + cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY; + break; + + default: + break; + } + + callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data); + + SMP_TRACE_DEBUG("callback_rc=%d p_cb->cb_evt=%d\n", callback_rc, p_cb->cb_evt ); + + if (callback_rc == SMP_SUCCESS) { + switch (p_cb->cb_evt) { + case SMP_IO_CAP_REQ_EVT: + p_cb->loc_auth_req = cb_data.io_req.auth_req; + p_cb->local_io_capability = cb_data.io_req.io_cap; + p_cb->loc_oob_flag = cb_data.io_req.oob_data; + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + if (!(p_cb->loc_auth_req & SMP_AUTH_BOND)) { + SMP_TRACE_WARNING ("Non bonding: No keys will be exchanged"); + p_cb->local_i_key = 0; + p_cb->local_r_key = 0; + } + + SMP_TRACE_DEBUG ("rcvd auth_req: 0x%02x, io_cap: %d \ + loc_oob_flag: %d loc_enc_size: %d," + "local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag, + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + if (p_cb->secure_connections_only_mode_required) { + p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT; + } + + if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) + || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) + || interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, + (const bt_bdaddr_t *)&p_cb->pairing_bda)) { + p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT; + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + SMP_TRACE_DEBUG("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key); + + smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL); + break; +#if (CLASSIC_BT_INCLUDED == TRUE) + case SMP_BR_KEYS_REQ_EVT: + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\ + local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL); + break; +#endif ///CLASSIC_BT_INCLUDED == TRUE + } + } + } + + if (!p_cb->cb_evt && p_cb->discard_sec_req) { + p_cb->discard_sec_req = FALSE; + smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL); + } + + SMP_TRACE_DEBUG("%s return\n", __func__); +} + +/******************************************************************************* +** Function smp_send_pair_fail +** Description pairing failure to peer device if needed. +*******************************************************************************/ +void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->status = *(UINT8 *)p_data; + p_cb->failure = *(UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status, p_cb->failure); + + if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS) { + smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb); + p_cb->wait_for_authorization_complete = TRUE; + } +} + +/******************************************************************************* +** Function smp_send_pair_req +** Description actions related to sending pairing request +*******************************************************************************/ +void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + /* erase all keys when master sends pairing req*/ + if (p_dev_rec) { + btm_sec_clear_ble_keys(p_dev_rec); + } +#endif ///BLE_INCLUDED == TRUE + /* do not manipulate the key, let app decide, + leave out to BTM to mandate key distribution for bonding case */ + smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_rsp +** Description actions related to sending pairing response +*******************************************************************************/ +void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + +#if (BLE_INCLUDED == TRUE) + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb)) { + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + smp_use_oob_private_key(p_cb, NULL); + } else { + smp_decide_association_model(p_cb, NULL); + } + } +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_send_confirm +** Description send confirmation to the peer +*******************************************************************************/ +void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); +} + +#if 0 //Unused +/******************************************************************************* +** Function smp_send_init +** Description process pairing initializer to slave device +*******************************************************************************/ +void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_INIT, p_cb); +} +#endif + +/******************************************************************************* +** Function smp_send_rand +** Description send pairing random to the peer +*******************************************************************************/ +void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_RAND, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_public_key +** Description send pairing public key command to the peer +*******************************************************************************/ +void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb); +} + +/******************************************************************************* +** Function SMP_SEND_COMMITMENT +** Description send commitment command to the peer +*******************************************************************************/ +void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb); +} + +/******************************************************************************* +** Function smp_send_dhkey_check +** Description send DHKey Check command to the peer +*******************************************************************************/ +void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb); +} + +/******************************************************************************* +** Function smp_send_keypress_notification +** Description send Keypress Notification command to the peer +*******************************************************************************/ +void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->local_keypress_notification = *(UINT8 *) p_data; + smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb); +} + +/******************************************************************************* +** Function smp_send_enc_info +** Description send encryption information command. +*******************************************************************************/ +void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d\n", __func__, p_cb->loc_enc_size); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + + smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb); + + /* save the DIV and key size information when acting as slave device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.div = p_cb->div; + le_key.key_size = p_cb->loc_enc_size; + le_key.sec_level = p_cb->sec_level; + +#if (BLE_INCLUDED == TRUE) + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + + SMP_TRACE_DEBUG ("%s\n", __func__); + + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_send_id_info +** Description send ID information command. +*******************************************************************************/ +void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE); + + smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb); + +#if (BLE_INCLUDED == TRUE) + tBTM_LE_KEY_VALUE le_key; + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID, + &le_key, TRUE); + } +#endif ///BLE_INCLUDED == TRUE + + smp_key_distribution_by_transport(p_cb, NULL); +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_send_csrk_info +** Description send CSRK command. +*******************************************************************************/ +void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LCSRK_KEYS key; + SMP_TRACE_DEBUG("%s\n", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE); + + if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) { + key.div = p_cb->div; + key.sec_level = p_cb->sec_level; + key.counter = 0; /* initialize the local counter */ + memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN); + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, TRUE); + } + + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_send_ltk_reply +** Description send LTK reply +*******************************************************************************/ +void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + /* send stk as LTK response */ + btm_ble_ltk_request_reply(p_cb->pairing_bda, TRUE, p_data->key.p_data); +} + +/******************************************************************************* +** Function smp_proc_sec_req +** Description process security request. +*******************************************************************************/ +void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data; + tBTM_BLE_SEC_REQ_ACT sec_req_act; + UINT8 reason; + + SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req); + + p_cb->cb_evt = 0; + btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act); + + SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act); + + switch (sec_req_act) { + case BTM_BLE_SEC_REQ_ACT_ENCRYPT: + SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__); + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + break; + + case BTM_BLE_SEC_REQ_ACT_PAIR: + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + /* respond to non SC pairing request as failure in SC only mode */ + if (p_cb->secure_connections_only_mode_required && + (auth_req & SMP_SC_SUPPORT_BIT) == 0) { + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } else { + /* initialize local i/r key to be default keys */ + p_cb->peer_auth_req = auth_req; + p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY ; + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } + break; + + case BTM_BLE_SEC_REQ_ACT_DISCARD: + p_cb->discard_sec_req = TRUE; + break; + + default: + /* do nothing */ + break; + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_sec_grant +** Description process security grant. +*******************************************************************************/ +void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res = *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data); + } else { /*otherwise, start pairing */ + /* send IO request callback */ + p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_proc_pair_fail +** Description process pairing failure from peer device +*******************************************************************************/ +void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; +} + +/******************************************************************************* +** Function smp_get_auth_mode +** Description Get the SMP pairing auth mode +*******************************************************************************/ +uint16_t smp_get_auth_mode (tSMP_ASSO_MODEL model) +{ + SMP_TRACE_DEBUG("%s model %d", __func__, model); + uint16_t auth = 0; + if (model == SMP_MODEL_ENCRYPTION_ONLY || model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + //No MITM + if(model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + //SC SMP_SC_SUPPORT_BIT + auth |= SMP_SC_SUPPORT_BIT; + } + } else if (model <= SMP_MODEL_KEY_NOTIF) { + //NO SC, MITM + auth |= SMP_AUTH_YN_BIT; + } else if (model <= SMP_MODEL_SEC_CONN_OOB) { + //SC, MITM + auth |= SMP_SC_SUPPORT_BIT; + auth |= SMP_AUTH_YN_BIT; + } else { + auth = 0; + } + return auth; +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_pair_cmd +** Description Process the SMP pairing request/response from peer device +*******************************************************************************/ +void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s\n", __func__); + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) { + btm_sec_clear_ble_keys(p_dev_rec); + } + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) { + reason = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + p_cb->accept_specified_sec_auth = bta_dm_co_ble_get_accept_auth_enable(); + p_cb->origin_loc_auth_req = bta_dm_co_ble_get_auth_req(); + if (p_cb->role == HCI_ROLE_SLAVE) { + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { + /* peer (master) started pairing sending Pairing Request */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } else { /* update local i/r key according to pairing request */ + /* pairing started with this side (slave) sending Security Request */ + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR("%s pairing failed - slave requires secure connection only mode", + __func__); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("%s pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + if (smp_request_oob_data(p_cb)) { + return; + } + } else { + smp_send_pair_rsp(p_cb, NULL); + } + } + } else { /* Master receives pairing response */ + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR ("Master requires secure connection only mode \ + but it can't be provided -> Master fails pairing"); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("%s pairing failed - master requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + if (smp_request_oob_data(p_cb)) { + return; + } + } else { + smp_decide_association_model(p_cb, NULL); + } + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_confirm +** Description process pairing confirm from peer device +*******************************************************************************/ +void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + /* save the SConfirm for comparison later */ + STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM; +} + +#if 0 //Unused +/******************************************************************************* +** Function smp_proc_init +** Description process pairing initializer from peer device +*******************************************************************************/ +void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} +#endif + +/******************************************************************************* +** Function smp_proc_rand +** Description process pairing random (nonce) from peer device +*******************************************************************************/ +void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} + +/******************************************************************************* +** Function smp_process_pairing_public_key +** Description process pairing public key command from the peer device +** - saves the peer public key; +** - sets the flag indicating that the peer public key is received; +** - calls smp_wait_for_both_public_keys(...). +** +*******************************************************************************/ +void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN); + STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN); + + /* Check if the peer device's and own public key are not same. If they are same then + * return pairing fail. This check is needed to avoid 'Impersonation in Passkey entry + * protocol' vulnerability (CVE-2020-26558).*/ + if ((memcmp(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, sizeof(BT_OCTET32)) == 0) && + (memcmp(p_cb->loc_publ_key.y, p_cb->peer_publ_key.y, sizeof(BT_OCTET32)) == 0)) { + p_cb->status = SMP_PAIR_AUTH_FAIL; + p_cb->failure = SMP_PAIR_AUTH_FAIL; + reason = SMP_PAIR_AUTH_FAIL; + SMP_TRACE_ERROR("%s, Peer and own device cannot have same public key.", __func__); + smp_sm_event(p_cb, SMP_PAIRING_FAILED_EVT, &reason); + return ; + } + /* In order to prevent the x and y coordinates of the public key from being modified, + we need to check whether the x and y coordinates are on the given elliptic curve. */ + if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) { + SMP_TRACE_ERROR("%s, Invalid Public key.", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY; + + smp_wait_for_both_public_keys(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_process_pairing_commitment +** Description process pairing commitment from peer device +*******************************************************************************/ +void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM; + + if (p != NULL) { + STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN); + } +} + +/******************************************************************************* +** Function smp_process_dhkey_check +** Description process DHKey Check from peer device +*******************************************************************************/ +void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK; +} + +/******************************************************************************* +** Function smp_process_keypress_notification +** Description process pairing keypress notification from peer device +*******************************************************************************/ +void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + STREAM_TO_UINT8(p_cb->peer_keypress_notification, p); + } else { + p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE; + } + p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT; +} + +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_br_process_pairing_command +** Description Process the SMP pairing request/response from peer device via +** BR/EDR transport. +*******************************************************************************/ +void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s", __func__); + /* rejecting BR pairing request over non-SC BR link */ + if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { + reason = SMP_XTRANS_DERIVE_NOT_ALLOW; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + +#if (BLE_INCLUDED == TRUE) + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) { + btm_sec_clear_ble_keys(p_dev_rec); + } +#endif ///BLE_INCLUDED == TRUE + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) { + reason = SMP_INVALID_PARAMETERS; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + + /* peer (master) started pairing sending Pairing Request */ + /* or being master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + if (p_cb->role == HCI_ROLE_SLAVE) { + p_dev_rec->new_encryption_key_is_p256 = FALSE; + /* shortcut to skip Security Grant step */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } else { /* Master receives pairing response */ + SMP_TRACE_DEBUG("%s master rcvs valid PAIRING RESPONSE." + " Supposed to move to key distribution phase. ", __func__); + } + + /* auth_req received via BR/EDR SM channel is set to 0, + but everything derived/exchanged has to be saved */ + p_cb->peer_auth_req |= SMP_AUTH_BOND; + p_cb->loc_auth_req |= SMP_AUTH_BOND; +} + +/******************************************************************************* +** Function smp_br_process_security_grant +** Description process security grant in case of pairing over BR/EDR transport. +*******************************************************************************/ +void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res = *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data); + } else { /*otherwise, start pairing */ + /* send IO request callback */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_br_check_authorization_request +** Description sets the SMP kes to be derived/distribute over BR/EDR transport +** before starting the distribution/derivation +*******************************************************************************/ +void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + + SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + /* In LE SC mode LK field is ignored when BR/EDR transport is used */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. */ + if (p_cb->role == HCI_ROLE_MASTER) { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) { + smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL); + + /* if no peer key is expected, start master key distribution */ + if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0) { + smp_key_distribution_by_transport(p_cb, NULL); + } + } else { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } +} + +/******************************************************************************* +** Function smp_br_select_next_key +** Description selects the next key to derive/send when BR/EDR transport is +** used. +*******************************************************************************/ +void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE || + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) { + /* state check to prevent re-entrance */ + if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) { + if (p_cb->total_tx_unacked == 0) { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } else { + p_cb->wait_for_authorization_complete = TRUE; + } + } + } +} +#endif ///CLASSIC_BT_INCLUDED == TRUE + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_enc_info +** Description process encryption information from peer device +*******************************************************************************/ +void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s\n", __func__); + STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN); + + smp_key_distribution(p_cb, NULL); +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_master_id +** Description process master ID from slave device +*******************************************************************************/ +void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s\np_cb->peer_auth_req = %d,p_cb->loc_auth_req= %d\n", __func__, + p_cb->peer_auth_req, p_cb->loc_auth_req); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE); + + STREAM_TO_UINT16(le_key.ediv, p); + STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN ); + + /* store the encryption keys from peer device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.sec_level = p_cb->sec_level; + le_key.key_size = p_cb->loc_enc_size; + +#if (BLE_INCLUDED == TRUE) + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_proc_enc_info +** Description process identity information from peer device +*******************************************************************************/ +void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s", __func__); + STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */ + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_id_addr +** Description process identity address from peer device +*******************************************************************************/ +void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PID_KEYS pid_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE); + + STREAM_TO_UINT8(pid_key.addr_type, p); + STREAM_TO_BDADDR(pid_key.static_addr, p); + memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN); + + /* to use as BD_ADDR for lk derived from ltk */ + p_cb->id_addr_rcvd = TRUE; + p_cb->id_addr_type = pid_key.addr_type; + memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN); + +#if (BLE_INCLUDED == TRUE) + /* store the ID key from peer device */ + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, + (tBTM_LE_KEY_VALUE *)&pid_key, TRUE); + } +#endif ///BLE_INCLUDED == TRUE + + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_srk_info +** Description process security information from peer device +*******************************************************************************/ +void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ +#if (BLE_INCLUDED == TRUE) + tBTM_LE_PCSRK_KEYS le_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE); + + /* save CSRK to security record */ + le_key.sec_level = p_cb->sec_level; + memcpy (le_key.csrk, p_data, BT_OCTET16_LEN); /* get peer CSRK */ + le_key.counter = 0; /* initialize the peer counter */ + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PCSRK, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + +#endif ///BLE_INCLUDED == TRUE + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_compare +** Description process compare value +*******************************************************************************/ +void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) { + /* compare the max encryption key size, and save the smaller one for the link */ + if ( p_cb->peer_enc_size < p_cb->loc_enc_size) { + p_cb->loc_enc_size = p_cb->peer_enc_size; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_sm_event(p_cb, SMP_RAND_EVT, NULL); + } else { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } + + } else { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_sl_key +** Description process key ready events. +*******************************************************************************/ +void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_type = p_data->key.key_type; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (key_type == SMP_KEY_TYPE_TK) { + smp_generate_srand_mrand_confirm(p_cb, NULL); + } else if (key_type == SMP_KEY_TYPE_CFM) { + smp_set_state(SMP_STATE_WAIT_CONFIRM); + + if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM) { + smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL); + } + } +} + +/******************************************************************************* +** Function smp_start_enc +** Description start encryption +*******************************************************************************/ +void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_STATUS cmd; + UINT8 reason = SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_data != NULL) { + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, TRUE, p_data->key.p_data); + } else { + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL); + } + + if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_discard +** Description processing for discard security request +*******************************************************************************/ +void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { + smp_reset_control_value(p_cb); + } +} + +/******************************************************************************* +** Function smp_enc_cmpl +** Description encryption success +*******************************************************************************/ +void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); +} + +/******************************************************************************* +** Function smp_check_auth_req +** Description check authentication request +*******************************************************************************/ +void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)\n", + __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key); + if (enc_enable == 1) { + if (p_cb->le_secure_connections_mode_is_used) { + /* In LE SC mode LTK is used instead of STK and has to be always saved */ + p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC; + p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC; + + /* In LE SC mode LK is derived from LTK only if both sides request it */ + if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) || + !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK)) { + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. + */ + if (p_cb->role == HCI_ROLE_MASTER) { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + } else { + /* in legacy mode derivation of BR/EDR LK is not supported */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)\n", + __func__, p_cb->local_i_key, p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) { + smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL); + } else { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + } else if (enc_enable == 0) { + /* if failed for encryption after pairing, send callback */ + if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + /* if enc failed for old security information */ + /* if master device, clean up and abck to idle; slave device do nothing */ + else if (p_cb->role == HCI_ROLE_MASTER) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + } +} + +/******************************************************************************* +** Function smp_key_pick_key +** Description Pick a key distribution function based on the key mask. +*******************************************************************************/ +void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key; + UINT8 i = 0; + + SMP_TRACE_DEBUG("%s key_to_dist=0x%x\n", __func__, key_to_dist); + while (i < SMP_KEY_DIST_TYPE_MAX) { + SMP_TRACE_DEBUG("key to send = %02x, i = %d\n", key_to_dist, i); + + if (key_to_dist & (1 << i) && smp_distribute_act[i] != NULL) { + SMP_TRACE_DEBUG("smp_distribute_act[%d]\n", i); + (* smp_distribute_act[i])(p_cb, p_data); + break; + } + i ++; + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_key_distribution +** Description start key distribution if required. +*******************************************************************************/ +void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("\n%s role=%d (0-master) r_keys=0x%x i_keys=0x%x\n", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE || + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) { + /* state check to prevent re-entrant */ + if (smp_get_state() == SMP_STATE_BOND_PENDING) { + if (p_cb->derive_lk) { + smp_derive_link_key_from_long_term_key(p_cb, NULL); + p_cb->derive_lk = FALSE; + } + + if (p_cb->total_tx_unacked == 0) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } else { + p_cb->wait_for_authorization_complete = TRUE; + } + } + } +} + +/******************************************************************************* +** Function smp_decide_association_model +** Description This function is called to select assoc model to be used for +** STK generation and to start STK generation process. +** +*******************************************************************************/ +void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 failure = SMP_UNKNOWN_IO_CAP; + UINT8 int_evt = 0; + tSMP_KEY key; + tSMP_INT_DATA *p = NULL; + + SMP_TRACE_DEBUG("%s Association Model = %d\n", __func__, p_cb->selected_association_model); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */ + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) \n", p_cb->sec_level ); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + p = (tSMP_INT_DATA *)&key; + + memset(p_cb->tk, 0, BT_OCTET16_LEN); + /* TK, ready */ + int_evt = SMP_KEY_READY_EVT; + break; + + case SMP_MODEL_PASSKEY: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level ); + + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_OOB: + SMP_TRACE_ERROR ("Association Model = SMP_MODEL_OOB\n"); + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level ); + + p_cb->cb_evt = SMP_OOB_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_KEY_NOTIF: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_DEBUG("Need to generate Passkey\n"); + + /* generate passkey and notify application */ + smp_generate_passkey(p_cb, NULL); + break; + + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + case SMP_MODEL_SEC_CONN_OOB: + int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT; + break; + + case SMP_MODEL_OUT_OF_RANGE: + SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)\n"); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + break; + + default: + SMP_TRACE_ERROR("Association Model = %d (SOMETHING IS WRONG WITH THE CODE)\n", + p_cb->selected_association_model); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + } + + SMP_TRACE_EVENT ("sec_level=%d \n", p_cb->sec_level ); + if (int_evt) { + smp_sm_event(p_cb, int_evt, p); + } +} + +/******************************************************************************* +** Function smp_process_io_response +** Description process IO response for a slave device. +*******************************************************************************/ +void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + uint8_t reason = SMP_PAIR_AUTH_FAIL; + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { + /* pairing started by local (slave) Security Request */ + smp_set_state(SMP_STATE_SEC_REQ_PENDING); + smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb); + } else { /* plan to send pairing respond */ + /* pairing started by peer (master) Pairing Request */ + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR ("Slave requires secure connection only mode \ + but it can't be provided -> Slave fails pairing\n"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + if (smp_request_oob_data(p_cb)) { + return; + } + } + smp_send_pair_rsp(p_cb, NULL); + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_br_process_slave_keys_response +** Description process application keys response for a slave device +** (BR/EDR transport). +*******************************************************************************/ +void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + smp_br_send_pair_response(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_br_send_pair_response +** Description actions related to sending pairing response over BR/EDR transport. +*******************************************************************************/ +void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb); +} + +/******************************************************************************* +** Function smp_pairing_cmpl +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->total_tx_unacked == 0) { + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +/******************************************************************************* +** Function smp_pair_terminate +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + p_cb->status = SMP_CONN_TOUT; + smp_proc_pairing_cmpl(p_cb); +} + +/******************************************************************************* +** Function smp_idle_terminate +** Description This function calledin idle state to determine to send authentication +** complete or not. +*******************************************************************************/ +void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { + SMP_TRACE_DEBUG("Pairing terminated at IDLE state.\n"); + p_cb->status = SMP_FAIL; + smp_proc_pairing_cmpl(p_cb); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_fast_conn_param +** Description apply default connection parameter for pairing process +*******************************************************************************/ +void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if(p_cb->role == BTM_ROLE_MASTER) { + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE); + } +#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE) + else { + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda); + if(p_rec && p_rec->ble.skip_update_conn_param) { + //do nothing + return; + } + /* Disable L2CAP connection parameter updates while bonding since + some peripherals are not able to revert to fast connection parameters + during the start of service discovery. Connection paramter updates + get enabled again once service discovery completes. */ + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE); + } +#endif +} + +/******************************************************************************* +** Function smp_both_have_public_keys +** Description The function is called when both local and peer public keys are +** saved. +** Actions: +** - invokes DHKey computation; +** - on slave side invokes sending local public key to the peer. +** - invokes SC phase 1 process. +*******************************************************************************/ +void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + /* invokes DHKey computation */ + smp_compute_dhkey(p_cb); + + /* on slave side invokes sending local public key to the peer */ + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_pair_public_key(p_cb, NULL); + } + + smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_start_secure_connection_phase1 +** Description The function starts Secure Connection phase1 i.e. invokes initialization of Secure Connection +** phase 1 parameters and starts building/sending to the peer +** messages appropriate for the role and association model. +*******************************************************************************/ +void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE)\n ", p_cb->sec_level ); + } else { + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED)\n ", p_cb->sec_level ); + } + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + memset(p_cb->local_random, 0, BT_OCTET16_LEN); + smp_start_nonce_generation(p_cb); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + /* user has to provide passkey */ + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + /* passkey has to be provided to user */ + SMP_TRACE_DEBUG("Need to generate SC Passkey\n"); + smp_generate_passkey(p_cb, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + /* use the available OOB information */ + smp_process_secure_connection_oob_data(p_cb, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_local_nonce +** Description The function processes new local nonce. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_SLAVE) { + /* slave calculates and sends local commitment */ + smp_calculate_local_commitment(p_cb); + smp_send_commitment(p_cb, NULL); + /* slave has to wait for peer nonce */ + smp_set_state(SMP_STATE_WAIT_NONCE); + } else { /* i.e. master */ + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) { + /* slave commitment is already received, send local nonce, wait for remote nonce*/ + SMP_TRACE_DEBUG("master in assoc mode = %d \ + already rcvd slave commitment - race condition\n", + p_cb->selected_association_model); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_send_rand(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + smp_calculate_local_commitment(p_cb); + + if (p_cb->role == HCI_ROLE_MASTER) { + smp_send_commitment(p_cb, NULL); + } else { /* slave */ + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) { + /* master commitment is already received */ + smp_send_commitment(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_MASTER) { + smp_send_rand(p_cb, NULL); + } + + smp_set_state(SMP_STATE_WAIT_NONCE); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_peer_nonce +** Description The function processes newly received and saved in CB peer nonce. +** The actions depend on the selected association model and the role. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s start \n", __func__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + /* in these models only master receives commitment */ + if (p_cb->role == HCI_ROLE_MASTER) { + if (!smp_check_commitment(p_cb)) { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + } else { + /* slave sends local nonce */ + smp_send_rand(p_cb, NULL); + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + /* go directly to phase 2 */ + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + } else { /* numeric comparison */ + smp_set_state(SMP_STATE_WAIT_NONCE); + smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL); + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + if (!smp_check_commitment(p_cb)) { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_rand(p_cb, NULL); + } + + if (++p_cb->round < 20) { + smp_set_state(SMP_STATE_SEC_CONN_PHS1_START); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_start_nonce_generation(p_cb); + break; + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_rand(p_cb, NULL); + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } + + SMP_TRACE_DEBUG("%s end\n ", __FUNCTION__); +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_match_dhkey_checks +** Description checks if the calculated peer DHKey Check value is the same as +** received from the peer DHKey check value. +*******************************************************************************/ +void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_DHKEY_CHK_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) { + SMP_TRACE_WARNING ("dhkey checks do no match\n"); + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + SMP_TRACE_EVENT ("dhkey checks match\n"); + + /* compare the max encryption key size, and save the smaller one for the link */ + if (p_cb->peer_enc_size < p_cb->loc_enc_size) { + p_cb->loc_enc_size = p_cb->peer_enc_size; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL); + } else { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_move_to_secure_connections_phase2 +** Description Signal State Machine to start SC phase 2 initialization (to +** compute local DHKey Check value). +** +** Note SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START. +*******************************************************************************/ +void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_phase_2_dhkey_checks_are_present +** Description generates event if dhkey check from the peer is already received. +** +** Note It is supposed to be used on slave to prevent race condition. +** It is supposed to be called after slave dhkey check is calculated. +*******************************************************************************/ +void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK) { + smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_wait_for_both_public_keys +** Description generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and master +** public keys are available. +** +** Note on the slave it is used to prevent race condition. +** +*******************************************************************************/ +void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) && + (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) { + if ((p_cb->role == HCI_ROLE_SLAVE) && + ((p_cb->req_oob_type == SMP_OOB_LOCAL) || (p_cb->req_oob_type == SMP_OOB_BOTH))) { + smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH); + } + smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_start_passkey_verification +** Description Starts SC passkey entry verification. +*******************************************************************************/ +void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = NULL; + + SMP_TRACE_DEBUG("%s\n", __func__); + p = p_cb->local_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p = p_cb->peer_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p_cb->round = 0; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_process_secure_connection_oob_data +** Description Processes local/peer SC OOB data received from somewhere. +*******************************************************************************/ +void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + tSMP_SC_OOB_DATA *p_sc_oob_data = &p_cb->sc_oob_data; + if (p_sc_oob_data->loc_oob_data.present) { + memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer, + sizeof(p_cb->local_random)); + } else { + SMP_TRACE_EVENT ("local OOB randomizer is absent\n"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + + if (!p_sc_oob_data->peer_oob_data.present) { + SMP_TRACE_EVENT ("peer OOB data is absent\n"); + memset(p_cb->peer_random, 0, sizeof (p_cb->peer_random)); + } else { + memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer, + sizeof(p_cb->peer_random)); + memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment, + sizeof(p_cb->remote_commitment)); + + UINT8 reason = SMP_CONFIRM_VALUE_ERR; + /* check commitment */ + if (!smp_check_commitment(p_cb)) { + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) { + /* the peer doesn't have local randomiser */ + SMP_TRACE_EVENT ("peer didn't receive local OOB data, set local randomizer to 0\n"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + } + + print128(p_cb->local_random, (const UINT8 *)"local OOB randomizer"); + print128(p_cb->peer_random, (const UINT8 *)"peer OOB randomizer"); + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_keys +** Description Saves calculated private/public keys in sc_oob_data.loc_oob_data, +** starts nonce generation +** (to be saved in sc_oob_data.loc_oob_data.randomizer). +*******************************************************************************/ +void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key, + BT_OCTET32_LEN); + p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_random_commitment +** Description Saves calculated randomizer and commitment in sc_oob_data.loc_oob_data, +** passes sc_oob_data.loc_oob_data up for safekeeping. +*******************************************************************************/ +void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, + BT_OCTET16_LEN); + + smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.randomizer, 0, + p_cb->sc_oob_data.loc_oob_data.commitment); + +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; + SMP_TRACE_DEBUG("local SC OOB data set:\n"); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.addr_sent_to; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"addr_sent_to", + sizeof(tBLE_BD_ADDR)); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.private_key_used; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"private_key_used", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.x; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.x", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.y; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.y", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.randomizer; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"randomizer", + BT_OCTET16_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.commitment; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *) "commitment", + BT_OCTET16_LEN); + SMP_TRACE_DEBUG(""); +#endif + + /* pass created OOB data up */ + p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT; + smp_send_app_cback(p_cb, NULL); + + smp_cb_cleanup(p_cb); +} + +/******************************************************************************* +** +** Function smp_link_encrypted +** +** Description This function is called when link is encrypted and notified to +** slave device. Proceed to to send LTK, DIV and ER to master if +** bonding the devices. +** +** +** Returns void +** +*******************************************************************************/ +void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable) +{ + tSMP_CB *p_cb = &smp_cb; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable); + + if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) { + /* encryption completed with STK, remmeber the key size now, could be overwite + * when key exchange happens */ + if (p_cb->loc_enc_size != 0 && encr_enable) { + /* update the link encryption key size if a SMP pairing just performed */ + btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size); + } + + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } else if (p_dev_rec && !p_dev_rec->role_master && !p_dev_rec->enc_init_by_we ){ + /* + if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption() + we need initiate pairing_bda and p_cb->role then encryption, for example iPhones + */ + memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN); + p_cb->state = SMP_STATE_ENCRYPTION_PENDING; + p_cb->role = HCI_ROLE_SLAVE; + p_dev_rec->enc_init_by_we = FALSE; + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } else if (p_dev_rec && p_dev_rec->role_master && p_dev_rec->enc_init_by_we){ + memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN); + p_cb->state = SMP_STATE_ENCRYPTION_PENDING; + p_cb->role = HCI_ROLE_MASTER; + p_dev_rec->enc_init_by_we = FALSE; + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } +} + +/******************************************************************************* +** +** Function smp_proc_ltk_request +** +** Description This function is called when LTK request is received from +** controller. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN smp_proc_ltk_request(BD_ADDR bda) +{ + SMP_TRACE_DEBUG("%s state = %d\n", __func__, smp_cb.state); + BOOLEAN match = FALSE; + + if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN)) { + match = TRUE; + } else { + BD_ADDR dummy_bda = {0}; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bda); + if (p_dev_rec != NULL && + 0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda, BD_ADDR_LEN) && + 0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN)) { + match = TRUE; + } + } + + if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING) { + smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function smp_process_secure_connection_long_term_key +** +** Description This function is called to process SC LTK. +** SC LTK is calculated and used instead of STK. +** Here SC LTK is saved in BLE DB. +** +** Returns void +** +*******************************************************************************/ +void smp_process_secure_connection_long_term_key(void) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_DEBUG("%s\n", __func__); + smp_save_secure_connections_long_term_key(p_cb); + + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_set_derive_link_key +** +** Description This function is called to set flag that indicates that +** BR/EDR LK has to be derived from LTK after all keys are +** distributed. +** +** Returns void +** +*******************************************************************************/ +void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s\n", __func__); + p_cb->derive_lk = TRUE; + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_derive_link_key_from_long_term_key +** +** Description This function is called to derive BR/EDR LK from LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!smp_calculate_link_key_from_long_term_key(p_cb)) { + SMP_TRACE_ERROR("%s failed\n", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return; + } +} +#endif ///BLE_INCLUDED == TRUE + +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function smp_br_process_link_key +** +** Description This function is called to process BR/EDR LK: +** - to derive SMP LTK from BR/EDR LK; +*8 - to save SMP LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!smp_calculate_long_term_key_from_link_key(p_cb)) { + SMP_TRACE_ERROR ("%s failed\n", __FUNCTION__); + smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + return; + } + + SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed\n", __FUNCTION__); + smp_save_secure_connections_long_term_key(p_cb); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_br_select_next_key(p_cb, NULL); +} +#endif ///CLASSIC_BT_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_key_distribution_by_transport +** Description depending on the transport used at the moment calls either +** smp_key_distribution(...) or smp_br_key_distribution(...). +*******************************************************************************/ +void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_select_next_key(p_cb, NULL); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } else { +#if (BLE_INCLUDED == TRUE) + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE + } +} + +/******************************************************************************* +** Function smp_br_pairing_complete +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->total_tx_unacked == 0) { + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +#endif