bluetooth: Add support for SSP and refactor AcceptConnection and

CreateConnection

Move expecting commands from RemoteDevice::Authenticate to where they
are called.In SSP we expect for the events after ConnectionComplete.
For the state machine, LINK_KEY_NOTIFY tells us the end of the pairing
in both pairings, so we clear all expected events there for the ones we added in
ConnectionComplete, In SimplePairingComplete we clear the ones added
in IOCapabilityRequest. Tested with both bluetooth 2.1 and older pairing.

Change-Id: Ia208506c9f289d9f44dc3b8b0e4cd8a726a5d726
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10526
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
vighnesh-sawant
2026-03-16 12:19:26 +00:00
committed by waddlesplash
parent dbf6744326
commit aa864b9d41
7 changed files with 283 additions and 62 deletions
+19 -1
View File
@@ -184,7 +184,25 @@ struct hci_command_header {
uint16 voice_setting;
} __attribute__ ((packed));
#define OCF_HOST_BUFFER_SIZE 0x0033
#define OCF_IO_CAPABILITY_REQUEST_REPLY 0x002B
struct hci_cp_io_capability_request_reply {
bdaddr_t bdaddr;
uint8 capability;
uint8 oob_data;
uint8 authentication;
} __attribute__((packed));
#define OCF_USER_CONFIRM_REPLY 0x002C
struct hci_cp_user_confirm_reply {
bdaddr_t bdaddr;
} __attribute__((packed));
#define OCF_USER_CONFIRM_NEG_REPLY 0x002D
struct hci_cp_user_confirm_neg_reply {
bdaddr_t bdaddr;
} __attribute__((packed));
#define OCF_HOST_BUFFER_SIZE 0x0033
struct hci_cp_host_buffer_size {
uint16 acl_mtu;
uint8 sco_mtu;
+33 -1
View File
@@ -292,16 +292,48 @@ struct hci_ev_extended_inquiry_info {
#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30
#define HCI_EVENT_IO_CAPABILITY_REQUEST 0x31
struct hci_ev_io_capability_request {
bdaddr_t bdaddr;
} __attribute__((packed));
#define HCI_EVENT_IO_CAPABILITY_RESPONSE 0x32
struct hci_ev_io_capability_response {
bdaddr_t bdaddr;
uint8 capability;
uint8 oob_data;
uint8 authentication;
} __attribute__((packed));
#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33
#define HCI_IO_CAP_DISPLAY_ONLY 0x00
#define HCI_IO_CAP_DISPLAY_YES_NO 0x01
#define HCI_IO_CAP_KEYBOARD_ONLY 0x02
#define HCI_IO_CAP_NO_INPUT_NO_OUTPUT 0x03
#define HCI_OOB_DATA_NOT_PRESENT 0x00
#define HCI_OOB_DATA_PRESENT 0x01
#define HCI_AUTH_REQ_NO_MITM_NO_BOND 0x00
#define HCI_AUTH_REQ_MITM_NO_BOND 0x01
#define HCI_AUTH_REQ_NO_MITM_DEDICATED_BOND 0x02
#define HCI_AUTH_REQ_MITM_DEDICATED_BOND 0x03
#define HCI_AUTH_REQ_NO_MITM_GENERAL_BOND 0x04
#define HCI_AUTH_REQ_MITM_GENERAL_BOND 0x05
#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33
struct hci_ev_user_confirmation_request {
bdaddr_t bdaddr;
uint32 passkey;
} __attribute__((packed));
#define HCI_EVENT_USER_PASSKEY_REQUEST 0x34
#define HCI_EVENT_OOB_DATA_REQUEST 0x35
#define HCI_EVENT_SIMPLE_PAIRING_COMPLETE 0x36
struct hci_ev_simple_pairing_complete {
uint8 status;
bdaddr_t bdaddr;
} __attribute__((packed));
#define HCI_EVENT_LINK_SUPERVISION_TIMEOUT_CHANGED 0x38
@@ -120,6 +120,9 @@ void* buildPinCodeRequestNegativeReply(bdaddr_t bdaddr, size_t* outsize);
void* buildAcceptConnectionRequest(bdaddr_t bdaddr, uint8 role,
size_t* outsize);
void* buildRejectConnectionRequest(bdaddr_t bdaddr, size_t* outsize);
void* buildIOCapabilityRequestReply(bdaddr_t bdaddr, uint8 capability, uint8 oob_data,
uint8 authentication, size_t* outsize);
void* buildUserConfirmReply(bdaddr_t bdaddr, size_t* outsize);
/* OGF_INFORMATIONAL_PARAM */
void* buildReadLocalVersionInformation(size_t* outsize);
+38
View File
@@ -261,6 +261,44 @@ buildRejectConnectionRequest(bdaddr_t bdaddr, size_t* outsize)
}
void*
buildIOCapabilityRequestReply(bdaddr_t bdaddr, uint8 capability, uint8 oob_data,
uint8 authentication, size_t* outsize)
{
CALLED();
struct hci_cp_io_capability_request_reply* param;
void* command = buildCommand(OGF_LINK_CONTROL, OCF_IO_CAPABILITY_REQUEST_REPLY, (void**)&param,
sizeof(struct hci_cp_io_capability_request_reply), outsize);
if (command != NULL) {
param->bdaddr = bdaddr;
param->capability = capability;
param->oob_data = oob_data;
param->authentication = authentication;
}
return command;
}
void*
buildUserConfirmReply(bdaddr_t bdaddr, size_t* outsize)
{
CALLED();
struct hci_cp_user_confirm_reply* param;
void* command = buildCommand(OGF_LINK_CONTROL, OCF_USER_CONFIRM_REPLY, (void**)&param,
sizeof(struct hci_cp_user_confirm_reply), outsize);
if (command != NULL)
param->bdaddr = bdaddr;
return command;
}
#if 0
#pragma mark - INFORMATIONAL_PARAM -
#endif
+1 -25
View File
@@ -181,32 +181,8 @@ RemoteDevice::Authenticate()
request.AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL,
OCF_CREATE_CONN));
// if authentication needed, we will send any of these commands
// to accept or deny the LINK KEY [a]
request.AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
request.AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL,
OCF_LINK_KEY_REPLY));
request.AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
request.AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL,
OCF_LINK_KEY_NEG_REPLY));
// in negative case, a pincode will be replied [b]
// this request will be handled by sepatated by the pincode window
// request.AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
// request.AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL,
// OCF_PIN_CODE_REPLY));
// [a] this is expected of authentication required
request.AddInt16("eventExpected", HCI_EVENT_LINK_KEY_REQ);
// [b] If we deny the key an authentication will be requested
// but this request will be handled by sepatated by the pincode
// window
// request.AddInt16("eventExpected", HCI_EVENT_PIN_CODE_REQ);
// this almost involves already the happy end
request.AddInt16("eventExpected", HCI_EVENT_LINK_KEY_NOTIFY);
request.AddInt16("eventExpected", HCI_EVENT_ROLE_CHANGE);
request.AddInt16("eventExpected", HCI_EVENT_CONN_COMPLETE);
if (fMessenger->SendMessage(&request, &reply) == B_OK)
+181 -35
View File
@@ -7,9 +7,10 @@
#include "BluetoothServer.h"
#include "LocalDeviceImpl.h"
#include "CommandManager.h"
#include "Debug.h"
#include "LocalDeviceImpl.h"
#include "bluetooth/HCI/btHCI_command.h"
#include <bluetooth/bdaddrUtils.h>
#include <bluetooth/bluetooth_error.h>
@@ -131,11 +132,7 @@ LocalDeviceImpl::HandleUnexpectedEvent(struct hci_event_header* event)
<struct hci_ev_disconnection_complete_reply>(event),
NULL);
break;
case HCI_EVENT_PIN_CODE_REQ:
PinCodeRequest(
JumpEventHeader<struct hci_ev_pin_code_req>(event), NULL);
break;
default:
// TODO: feedback unexpected not handled
break;
}
@@ -267,6 +264,30 @@ LocalDeviceImpl::HandleExpectedRequest(struct hci_event_header* event,
case HCI_EVENT_SYNCHRONOUS_CONNECTION_CHANGED:
break;
case HCI_EVENT_IO_CAPABILITY_REQUEST:
IOCapabilityRequest(JumpEventHeader<struct hci_ev_io_capability_request>(event),
request);
break;
case HCI_EVENT_IO_CAPABILITY_RESPONSE:
IOCapabilityResponse(JumpEventHeader<struct hci_ev_io_capability_response>(event),
request);
break;
case HCI_EVENT_USER_CONFIRMATION_REQUEST:
UserConfirmationRequest(JumpEventHeader<struct hci_ev_user_confirmation_request>(event),
request);
break;
case HCI_EVENT_SIMPLE_PAIRING_COMPLETE:
SimplePairingComplete(JumpEventHeader<struct hci_ev_simple_pairing_complete>(event),
request);
break;
case HCI_EVENT_PIN_CODE_REQ:
PinCodeRequest(JumpEventHeader<struct hci_ev_pin_code_req>(event), NULL);
break;
}
}
@@ -510,8 +531,9 @@ LocalDeviceImpl::CommandComplete(struct hci_ev_cmd_complete* event,
// This request is not gonna be used anymore
ClearWantedEvent(request);
break;
}
break;
case PACK_OPCODE(OGF_INFORMATIONAL_PARAM, OCF_READ_BD_ADDR):
{
@@ -533,9 +555,8 @@ LocalDeviceImpl::CommandComplete(struct hci_ev_cmd_complete* event,
// This request is not gonna be used anymore
ClearWantedEvent(request);
break;
}
break;
case PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_READ_CLASS_OF_DEV):
{
@@ -680,6 +701,17 @@ LocalDeviceImpl::CommandComplete(struct hci_ev_cmd_complete* event,
break;
}
// without clearing all events, no reply
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_IO_CAPABILITY_REQUEST_REPLY):
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_USER_CONFIRM_REPLY):
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_USER_CONFIRM_NEG_REPLY):
{
TRACE_BT("LocalDeviceImpl: %s for %s status %x\n", __FUNCTION__,
BluetoothCommandOpcode(opcodeExpected), *(uint8*)(event + 1));
ClearWantedEvent(request, HCI_EVENT_CMD_COMPLETE, opcodeExpected);
break;
}
// place here all CC that just replies a uint8 status
case PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_RESET):
case PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_WRITE_SCAN_ENABLE):
@@ -744,37 +776,50 @@ LocalDeviceImpl::CommandStatus(struct hci_ev_cmd_status* event,
break;
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_REMOTE_NAME_REQUEST):
{
TRACE_BT("LocalDeviceImpl: Command Status for remote friendly name %x\n",
event->status);
reply.AddInt8("status", event->status);
request->SendReply(&reply);
// printf("Sending reply... %ld\n", status);
// debug reply.PrintToStream();
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
}
break;
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_CREATE_CONN):
{
if (event->status == BT_OK) {
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
} else {
TRACE_BT("LocalDeviceImpl: Command Status for remote friendly name %x\n",
event->status);
TRACE_BT("LocalDeviceImpl: Command Status for create connection %x\n", event->status);
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
if (event->status != BT_OK) {
reply.AddInt8("status", event->status);
request->SendReply(&reply);
//printf("Sending reply... %ld\n", status);
// debug reply.PrintToStream();
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
// printf("Sending reply... %ld\n", status);
// debug reply.PrintToStream();
}
}
break;
/*
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ):
{
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS,
PACK_OPCODE(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ));
TRACE_BT("LocalDeviceImpl: Command Status for accept connection request %x\n",
event->status);
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
}
break;
case PACK_OPCODE(OGF_LINK_CONTROL, OCF_REJECT_CONN_REQ):
{
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS,
PACK_OPCODE(OGF_LINK_CONTROL, OCF_REJECT_CONN_REQ));
}
break;*/
TRACE_BT("LocalDeviceImpl: Command Status for reject connection request %x\n",
event->status);
ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, opcodeExpected);
} break;
default:
TRACE_BT("LocalDeviceImpl: Command Status not handled\n");
@@ -1018,17 +1063,16 @@ LocalDeviceImpl::ConnectionRequest(struct hci_ev_conn_request* event,
newrequest->AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL,
OCF_ACCEPT_CONN_REQ));
newrequest->AddInt16("eventExpected", HCI_EVENT_CONN_COMPLETE);
newrequest->AddInt16("eventExpected", HCI_EVENT_PIN_CODE_REQ);
newrequest->AddInt16("eventExpected", HCI_EVENT_ROLE_CHANGE);
newrequest->AddInt16("eventExpected", HCI_EVENT_LINK_KEY_NOTIFY);
newrequest->AddInt16("eventExpected",
HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE);
newrequest->AddInt16("eventExpected", HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE);
#if 0
newrequest->AddInt16("eventExpected", HCI_EVENT_LINK_KEY_REQ);
newrequest->AddInt16("eventExpected", HCI_EVENT_ROLE_CHANGE);
newrequest->AddInt16("eventExpected", HCI_EVENT_CONN_COMPLETE);
#if 0
newrequest->AddInt16("eventExpected", HCI_EVENT_MAX_SLOT_CHANGE);
newrequest->AddInt16("eventExpected", HCI_EVENT_DISCONNECTION_COMPLETE);
#endif
#endif
AddWantedEvent(newrequest);
@@ -1064,6 +1108,15 @@ LocalDeviceImpl::ConnectionComplete(struct hci_ev_conn_complete* event,
BluetoothError(event->status));
}
BMessage* newrequest = new BMessage;
newrequest->AddInt16("eventExpected", HCI_EVENT_IO_CAPABILITY_REQUEST);
newrequest->AddInt16("eventExpected", HCI_EVENT_IO_CAPABILITY_RESPONSE);
// this implies PAIRING complete
newrequest->AddInt16("eventExpected", HCI_EVENT_LINK_KEY_NOTIFY);
AddWantedEvent(newrequest);
// it was expected
if (request != NULL) {
BMessage reply;
@@ -1078,8 +1131,7 @@ LocalDeviceImpl::ConnectionComplete(struct hci_ev_conn_complete* event,
printf("%s: Error sending reply!\n", __func__);
// debug reply.PrintToStream();
// This request is not gonna be used anymore
ClearWantedEvent(request);
ClearWantedEvent(request, HCI_EVENT_CONN_COMPLETE);
}
}
@@ -1111,6 +1163,7 @@ void
LocalDeviceImpl::PinCodeRequest(struct hci_ev_pin_code_req* event,
BMessage* request)
{
TRACE_BT("LocalDeviceImpl: Opening PincodeWindow...");
PincodeWindow* iPincode = new PincodeWindow(event->bdaddr, GetID());
iPincode->Show();
}
@@ -1140,6 +1193,8 @@ LocalDeviceImpl::LinkKeyNotify(hci_ev_link_key_notify* event,
TRACE_BT("LocalDeviceImpl: %s: Address %s, key=%s, type=%d\n", __FUNCTION__,
bdaddrUtils::ToString(event->bdaddr).String(),
LinkKeyUtils::ToString(event->link_key).String(), event->key_type);
if (request != NULL)
ClearWantedEvent(request);
}
@@ -1160,6 +1215,12 @@ LocalDeviceImpl::LinkKeyRequested(struct hci_ev_link_key_req* keyRequested,
BluetoothCommand<typed_command(hci_cp_link_key_neg_reply)>
linkKeyNegativeReply(OGF_LINK_CONTROL, OCF_LINK_KEY_NEG_REPLY);
BMessage* newrequest = new BMessage;
newrequest->AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
newrequest->AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL, OCF_LINK_KEY_NEG_REPLY));
// on neg reply we expect this
newrequest->AddInt16("eventExpected", HCI_EVENT_PIN_CODE_REQ);
AddWantedEvent(newrequest);
bdaddrUtils::Copy(linkKeyNegativeReply->bdaddr, keyRequested->bdaddr);
if ((fHCIDelegate)->IssueCommand(linkKeyNegativeReply.Data(),
@@ -1230,6 +1291,91 @@ LocalDeviceImpl::NumberOfCompletedPackets(struct hci_ev_num_comp_pkts* event)
}
void
LocalDeviceImpl::IOCapabilityRequest(struct hci_ev_io_capability_request* event, BMessage* request)
{
size_t size;
void* command;
TRACE_BT("LocalDeviceImpl: IO Capability Request from %s...\n",
bdaddrUtils::ToString(event->bdaddr).String());
// this should be temporary, need to change this to HCI_IO_CAP_DISPLAY_YES_NO
command = buildIOCapabilityRequestReply(event->bdaddr, HCI_IO_CAP_NO_INPUT_NO_OUTPUT,
HCI_OOB_DATA_NOT_PRESENT, HCI_AUTH_REQ_NO_MITM_NO_BOND, &size);
BMessage* newrequest = new BMessage;
newrequest->AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
newrequest->AddInt16("opcodeExpected",
PACK_OPCODE(OGF_LINK_CONTROL, OCF_IO_CAPABILITY_REQUEST_REPLY));
// TODO:Check if there are more events we need to look for
newrequest->AddInt16("eventExpected", HCI_EVENT_USER_CONFIRMATION_REQUEST);
newrequest->AddInt16("eventExpected", HCI_EVENT_USER_PASSKEY_REQUEST);
newrequest->AddInt16("eventExpected", HCI_EVENT_SIMPLE_PAIRING_COMPLETE);
AddWantedEvent(newrequest);
if ((fHCIDelegate)->IssueCommand(command, size) == B_ERROR)
TRACE_BT("LocalDeviceImpl: Command issued error for reply %s\n", __FUNCTION__);
else
TRACE_BT("LocalDeviceImpl: Command issued in reply of %s\n", __FUNCTION__);
}
void
LocalDeviceImpl::IOCapabilityResponse(struct hci_ev_io_capability_response* event,
BMessage* request)
{
TRACE_BT("LocalDeviceImpl: %s for %s - Capability: 0x%02x, OOB: 0x%02x, Auth: 0x%02x\n",
__FUNCTION__, bdaddrUtils::ToString(event->bdaddr).String(), event->capability,
event->oob_data, event->authentication);
}
void
LocalDeviceImpl::UserConfirmationRequest(struct hci_ev_user_confirmation_request* event,
BMessage* request)
{
size_t size;
void* command;
TRACE_BT("LocalDeviceImpl: User Confirmation Request for %s (Passkey: %06" B_PRIu32 ")\n",
bdaddrUtils::ToString(event->bdaddr).String(), event->passkey);
command = buildUserConfirmReply(event->bdaddr, &size);
BMessage* newrequest = new BMessage;
newrequest->AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE);
newrequest->AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL, OCF_USER_CONFIRM_REPLY));
AddWantedEvent(newrequest);
if ((fHCIDelegate)->IssueCommand(command, size) == B_ERROR)
TRACE_BT("LocalDeviceImpl: Command issued error for reply %s\n", __FUNCTION__);
else
TRACE_BT("LocalDeviceImpl: Command issued in reply of %s\n", __FUNCTION__);
}
void
LocalDeviceImpl::SimplePairingComplete(struct hci_ev_simple_pairing_complete* event,
BMessage* request)
{
if (event->status == BT_OK) {
TRACE_BT("LocalDeviceImpl: %s successfull for %s!\n", __FUNCTION__,
bdaddrUtils::ToString(event->bdaddr).String());
} else {
TRACE_BT("LocalDeviceImpl: %s failed for %s with error %s\n", __FUNCTION__,
bdaddrUtils::ToString(event->bdaddr).String(), BluetoothError(event->status));
}
if (request != NULL)
ClearWantedEvent(request);
}
#if 0
#pragma mark - Request Methods -
#endif
+8
View File
@@ -76,6 +76,14 @@ private:
void HardwareError(struct hci_ev_hardware_error* event);
// Simple Secure Pairing
void IOCapabilityRequest(struct hci_ev_io_capability_request* event,
BMessage* request);
void IOCapabilityResponse(struct hci_ev_io_capability_response* event,
BMessage* request);
void UserConfirmationRequest(struct hci_ev_user_confirmation_request* event, BMessage* request);
void SimplePairingComplete(struct hci_ev_simple_pairing_complete* event,
BMessage* request);
};
#endif