Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Aug 2021 14:33:48 +0200
From:      Andreas Kempe <kempe@lysator.liu.se>
To:        freebsd-bluetooth@freebsd.org
Cc:        freebsd-hackers@freebsd.org
Subject:   RFC: PoC: Bluetooth secure simple pairing support
Message-ID:  <YQqJLE/NQ0C9XmD4@moira.hest-guild.se>

next in thread | raw e-mail | index | archive | help

--+pkO+WIezJok9CBI
Content-Type: multipart/mixed; boundary="m88YXiM89buYlW4g"
Content-Disposition: inline


--m88YXiM89buYlW4g
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hello everyone,

A few months back I sent a mail titled "Wireless Logitecgh M557 mouse
issues" to the bluetooth list and since then I finally found some time
to do more digging into the issue.

Comparing the FreeBSD behaviour to that of Linux via packet dumps, I
found that the reason my buetooth mouse is not able to reconnect to my
FreeBSD machine is that no pairing is performed. Currently, the
initial connection to the mouse is made and the mouse is used in an
unpaired state. When the mouse tries to reconnect, the computer has no
authentication key and the connection fails.

Attached to this mail, you can find a proof of concept patch for
allowing pairing between my mouse and the FreeBSD host. Using the
attached patch, I'm able to connect my mouse and it reconnects when
switched off and on again. The patch applies on top of Git revision
142f0d36d90979a983e1bb0b69d1d859338b4d90.

Using the PoC
-------------

In its current form, hcsecd has a very rudimentary implementation of
pairing support. No real state machine is used and error handling is
pretty much non-existent. The implementation assumes all operations
went well (which they have always done with my mouse so far).

Using the patch and performing the pairing:

1. Ensure that /var/db/{hcsecd.keys,bthidd.hids} do not contain
   entries fro the mouse.

2. Prep the hcsecd configuration file with the mouse.

device {
	bdaddr	00:1f:20:f5:cd:5f;
	name	"Bluetooth Mouse M557";
	key	nokey;
	pin	nopin;
}

3. Prep the bthidd configuration file.

device {
	bdaddr			00:1f:20:f5:cd:5f;
	name			"Bluetooth Mouse M557";
	vendor_id		0x046d;
	product_id		0xb010;
	version			0x1001;
	control_psm		0x11;
	interrupt_psm		0x13;
	reconnect_initiate	true;
	battery_power		true;
	normally_connectable	false;
	hid_descriptor		{
		[...]
	};
}

4. Start hcsecd.

service hcsecd start

5. Create a connection to the mouse.

hccontrol Create_connection 00:1f:20:f5:cd:5f

Creating the connection causes the pairing to happen.

6. Start bthidd.

service bthidd start

The mouse should now connect and work as intended. After the initial
pairing, the mouse can be turned off and on again and as long as
hcsecd and bthidd are running the mouse should reconnect.

During the initial pairing, bthidd can't be left running since it will
try to connect to the mouse and send HID-related things disturbing the
pairing process.

Questions
---------

Is implementing the pairing in hcsecd the correct approach?

Is a more complex state machine needed or can the expected pairing
flow be hard coded like the PoC albeit with proper error handling?
static int pairing used in the PoC is the only "state machine" state
currently present and should be done in a nicer way, but I deemed it
sufficent for the PoC.

How should one handle the interaction between bthidd and hcsecd? If
one wants the initial to pairing to work, bthidd can't send its
messages until the pairing is completed.

Is my approach to this sane or am I going in the wrong direction?

Looking forward to your feedback!
Cordially,
Andreas Kempe

--m88YXiM89buYlW4g
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="secure_simple_pairing_v0.patch"
Content-Transfer-Encoding: quoted-printable

diff --git a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c b/sys/netgraph/blueto=
oth/hci/ng_hci_cmds.c
index 9bef544cc98..2934206e634 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
@@ -615,8 +615,10 @@ process_hc_baseband_params(ng_hci_unit_p unit, u_int16=
_t ocf,
 	case NG_HCI_OCF_READ_LOCAL_NAME:
 	case NG_HCI_OCF_READ_UNIT_CLASS:
 	case NG_HCI_OCF_WRITE_UNIT_CLASS:
+	case NG_HCI_OCF_WRITE_SIMPLE_PAIRING:
 	case NG_HCI_OCF_READ_LE_HOST_SUPPORTED:
 	case NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED:
+	case NG_HCI_OCF_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT:
 		/* These do not need post processing */
 		break;
=20
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c b/sys/netgraph/blueto=
oth/hci/ng_hci_evnt.c
index b0dae0e18ec..6bd8f3b7e8c 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
@@ -121,6 +121,7 @@ ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *e=
vent)
 	case NG_HCI_EVENT_VENDOR:
 	case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL:
 	case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
+	case NG_HCI_EVENT_IO_CAPABILITY_REQUEST:
 		/* These do not need post processing */
 		NG_FREE_M(event);
 		break;
diff --git a/sys/netgraph/bluetooth/include/ng_hci.h b/sys/netgraph/bluetoo=
th/include/ng_hci.h
index ba23ba0563c..3effff8071b 100644
--- a/sys/netgraph/bluetooth/include/ng_hci.h
+++ b/sys/netgraph/bluetooth/include/ng_hci.h
@@ -115,6 +115,8 @@
 #define NG_HCI_LMP_FLOW_CONTROL_LAG0		0x10
 #define NG_HCI_LMP_FLOW_CONTROL_LAG1		0x20
 #define NG_HCI_LMP_FLOW_CONTROL_LAG2		0x40
+/* ------------------- byte 6 --------------------*/
+#define NG_HCI_LMP_SIMPLE_SECURE_CONNECT	0x08
=20
 /* Link types */
 #define NG_HCI_LINK_SCO				0x00 /* Voice */
@@ -797,6 +799,30 @@ typedef struct {
 } __attribute__ ((packed)) ng_hci_read_clock_offset_cp;
 /* No return parameter(s) */
=20
+#define NG_HCI_IO_CAPABILITY_REQUEST_REPLY	0x002b
+typedef struct {
+	bdaddr_t	bdaddr;
+	u_int8_t	io_capability;
+	u_int8_t	oob_data_present;
+	u_int8_t	authentication_requirements;
+} __attribute__ ((packed)) ng_hci_io_capability_request_reply_cp;
+
+typedef struct {
+	u_int8_t	status;
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) ng_hci_io_capability_request_reply_rp;
+
+#define NG_HCI_USER_CONFIRMATION_REQUEST_REPLY 0x002c
+typedef struct {
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) ng_hci_user_confirmation_request_reply_cp;
+
+typedef struct {
+	u_int8_t	status;
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) ng_hci_user_confirmation_request_reply_rp;
+
+
 /**************************************************************************
  **************************************************************************
  **        Link policy commands and return parameters
@@ -1311,6 +1337,13 @@ typedef struct {
=20
 typedef ng_hci_status_rp	ng_hci_write_page_scan_rp;
=20
+#define NG_HCI_OCF_WRITE_SIMPLE_PAIRING 0x0056
+typedef struct {
+	u_int8_t simple_pairing; /* 1 -> enabled, 0 -> disabled */
+} __attribute__ ((packed)) ng_hci_write_simple_pairing_cp;
+
+typedef ng_hci_status_rp	ng_hcy_write_simple_pairing_rp;
+
 #define NG_HCI_OCF_READ_LE_HOST_SUPPORTED  0x6c
 typedef struct {
 	u_int8_t	status;         /* 0x00 - success */
@@ -1326,6 +1359,13 @@ typedef struct {
=20
 typedef ng_hci_status_rp	ng_hci_write_le_host_supported_rp;
=20
+#define NG_HCI_OCF_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT 0x7a
+typedef struct {
+	u_int8_t support; /* 0 - disabled, 1 - enabled */
+} __attribute__ ((packed)) ng_hci_write_secure_connections_host_support_cp;
+
+typedef ng_hci_status_rp ng_hci_write_secure_connections_host_support_rp;
+
 /**************************************************************************
  **************************************************************************
  **           Informational commands and return parameters=20
@@ -1800,6 +1840,7 @@ typedef struct {
 	u_int8_t	features[NG_HCI_FEATURES_SIZE]; /* LMP features bitmsk*/
 } __attribute__ ((packed)) ng_hci_read_remote_features_compl_ep;
=20
+
 #define NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL	0x0c
 typedef struct {
 	u_int8_t	status;         /* 0x00 - success */
@@ -1939,6 +1980,18 @@ typedef struct {
 	bdaddr_t	bdaddr;             /* destination address */
 	u_int8_t	page_scan_rep_mode; /* page scan repetition mode */
 } __attribute__ ((packed)) ng_hci_page_scan_rep_mode_change_ep;
+
+#define NG_HCI_EVENT_IO_CAPABILITY_REQUEST 0x31
+typedef struct {
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) ng_hci_io_capability_request_ep;
+
+#define NG_HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33
+typedef struct {
+	bdaddr_t	bdaddr;
+	u_int32_t	numeric_value;
+} __attribute__ ((packed)) ng_hci_user_confirmation_request_ep;
+
 #define NG_HCI_EVENT_LE				0x3e
 typedef struct {
 	u_int8_t	subevent_code;=09
diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.c b/usr.sbin/bluetooth/hcsecd=
/hcsecd.c
index 160b77e1b04..8a22a162f09 100644
--- a/usr.sbin/bluetooth/hcsecd/hcsecd.c
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.c
@@ -46,7 +46,10 @@
 #include "hcsecd.h"
=20
 static int	done =3D 0;
+static int	pairing =3D 0;
=20
+static int enable_simple_pairing(int sock);
+static int unmask_events(int sock);
 static int process_pin_code_request_event
 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
 static int process_link_key_request_event
@@ -57,6 +60,17 @@ static int send_link_key_reply
 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key);
 static int process_link_key_notification_event
 	(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep=
);
+static int process_read_remote_features_compl_event
+	(int sock, struct sockaddr_hci *addr,
+	 ng_hci_read_remote_features_compl_ep *ep);
+static int process_con_compl_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_con_compl_ep *ep);
+static int process_io_capabilities_request_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_io_capability_request_ep *ep=
);
+static int process_user_confirmation_request_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_user_confirmation_request_ep=
 *ep);
+static int process_auth_compl_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_auth_compl_ep *ep);
 static void sighup
 	(int s);
 static void sigint
@@ -126,6 +140,11 @@ main(int argc, char *argv[])
 	bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);
 	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);
 	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_IO_CAPABILITY_REQUEST - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_USER_CONFIRMATION_REQUEST - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_AUTH_COMPL - 1);
=20
 	if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
 			(void * const) &filter, sizeof(filter)) < 0)
@@ -139,6 +158,9 @@ main(int argc, char *argv[])
 	read_config_file();
 	read_keys_file();
=20
+	enable_simple_pairing(sock);
+	unmask_events(sock);
+
 	if (detach) {
 		FILE	*pid =3D NULL;
=20
@@ -188,6 +210,31 @@ main(int argc, char *argv[])
 				(ng_hci_link_key_notification_ep *)(event + 1));
 			break;
=20
+		case NG_HCI_EVENT_CON_COMPL:
+			process_con_compl_event(sock, &addr,
+				(ng_hci_con_compl_ep *)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
+			process_read_remote_features_compl_event(sock, &addr,
+				(ng_hci_read_remote_features_compl_ep *)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_IO_CAPABILITY_REQUEST:
+			process_io_capabilities_request_event(sock,
+				&addr, (ng_hci_io_capability_request_ep *)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_USER_CONFIRMATION_REQUEST:
+			process_user_confirmation_request_event(sock, &addr,
+				(ng_hci_user_confirmation_request_ep *)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_AUTH_COMPL:
+			process_auth_compl_event(sock, &addr,
+				(ng_hci_auth_compl_ep *)(event + 1));
+			break;
+
 		default:
 			syslog(LOG_ERR, "Received unexpected HCI event, " \
 					"event=3D%#x", event->event);
@@ -208,6 +255,148 @@ main(int argc, char *argv[])
 	return (0);
 }
=20
+static int
+find_hci_nodes(struct nodeinfo** nodes)
+{
+	struct ng_btsocket_hci_raw_node_list_names	r;
+	struct sockaddr_hci				addr;
+	int						s;
+	const char *					node =3D "ubt0hci";
+
+	r.num_names =3D 16;
+	r.names =3D (struct nodeinfo*)calloc(16, sizeof(struct nodeinfo));
+	if (r.names =3D=3D NULL)
+		err(8, "Could not allocate memory");
+
+	s =3D socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0)
+		err(9, "Could not create socket");
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_len =3D sizeof(addr);
+	addr.hci_family =3D AF_BLUETOOTH;
+	strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		err(10, "Could not bind socket");
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0)
+		err(11, "Could not get list of HCI nodes");
+
+	close(s);
+
+	*nodes =3D r.names;
+
+	return (r.num_names);
+} /* find_hci_nodes */
+
+static int enable_simple_pairing(int sock)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+	struct nodeinfo		*nodes;
+	struct sockaddr_hci	addr;
+	int num;
+	char *node;
+
+	num =3D find_hci_nodes(&nodes);
+	if (num =3D=3D 0) {
+		syslog(LOG_ERR, "Could not find HCI nodes");
+		free(nodes);
+		return (-1);
+	}
+
+	node =3D strdup(nodes[0].name);
+
+	free(nodes);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_len =3D sizeof(addr);
+	addr.hci_family =3D AF_BLUETOOTH;
+	strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+	free(node);
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_write_simple_pairing_cp	*cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+					NG_HCI_OCF_WRITE_SIMPLE_PAIRING));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_write_simple_pairing_cp *)(cmd + 1);
+	cp->simple_pairing =3D 1;
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+				(struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send write simple pairing. " \
+				"%s (%d)", strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int unmask_events(int sock)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+	struct nodeinfo		*nodes;
+	struct sockaddr_hci	addr;
+	int num;
+	char *node;
+
+	num =3D find_hci_nodes(&nodes);
+	if (num =3D=3D 0) {
+		syslog(LOG_ERR, "Could not find HCI nodes");
+		free(nodes);
+		return (-1);
+	}
+
+	node =3D strdup(nodes[0].name);
+
+	free(nodes);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_len =3D sizeof(addr);
+	addr.hci_family =3D AF_BLUETOOTH;
+	strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+	free(node);
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_set_event_mask_cp *cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+					NG_HCI_OCF_SET_EVENT_MASK));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_set_event_mask_cp *)(cmd + 1);
+	memset(cp->event_mask, 0xff, NG_HCI_EVENT_MASK_SIZE);
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+				(struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send set event mask. " \
+				"%s (%d)", strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
 /* Process PIN_Code_Request event */
 static int
 process_pin_code_request_event(int sock, struct sockaddr_hci *addr,
@@ -415,6 +604,225 @@ process_link_key_notification_event(int sock, struct =
sockaddr_hci *addr,
 	return (0);
 }
=20
+static int send_auth_req(int sock, struct sockaddr_hci *addr,
+		u_int16_t con_handle)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_auth_req_cp	*cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+					NG_HCI_OCF_AUTH_REQ));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_auth_req_cp *)(cmd + 1);
+	cp->con_handle =3D htole16(con_handle);
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send auth req to for con_handle =3D %d. " \
+				"%s (%d)", con_handle, strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int process_read_remote_features_compl_event(int sock,
+		struct sockaddr_hci *addr, ng_hci_read_remote_features_compl_ep *ep)
+{
+	if (ep->features[6] & NG_HCI_LMP_SIMPLE_SECURE_CONNECT) {
+		return (send_auth_req(sock, addr, ep->con_handle));
+	} else
+		return (0);
+}
+
+static int send_read_remote_features(int sock, struct sockaddr_hci *addr,
+		u_int16_t con_handle)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_read_remote_features_cp	*cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+					NG_HCI_OCF_READ_REMOTE_FEATURES));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_read_remote_features_cp *)(cmd + 1);
+	cp->con_handle =3D htole16(con_handle);
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send read remote features for " \
+				"con_handle =3D %d. %s (%d)", con_handle, strerror(errno),
+				errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int process_con_compl_event(int sock, struct sockaddr_hci *addr,
+		ng_hci_con_compl_ep *ep)
+{
+	return (send_read_remote_features(sock, addr, ep->con_handle));
+}
+
+static int send_io_capability_request_reply(int sock, struct sockaddr_hci =
*addr,
+		bdaddr_p bdaddr)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_io_capability_request_reply_cp	*cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+					NG_HCI_IO_CAPABILITY_REQUEST_REPLY));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_io_capability_request_reply_cp *)(cmd + 1);
+	memcpy(&cp->bdaddr, bdaddr, sizeof(bdaddr_t));
+	cp->io_capability =3D 0x03; /* 0x03 - NoInputNoOutput */
+	cp->oob_data_present =3D 0x00; /* 0x00 - OOB authentication data not pres=
ent */
+	 /* 0x03 - MITM protection required - Dedicated Bonding. Use IO
+	  * Capabilities to determine authentication procedure. */
+	cp->authentication_requirements =3D 0x03;
+
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send IO capability request reply to " \
+				"remote bdaddr '%s'. %s (%d)", bt_ntoa(bdaddr, NULL),
+				strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int process_io_capabilities_request_event(int sock,
+	struct sockaddr_hci *addr, ng_hci_io_capability_request_ep *ep)
+{
+	/* Requesting IO capabilities is the start of simple pairing. */
+	pairing =3D 1;
+	return (send_io_capability_request_reply(sock, addr, &ep->bdaddr));
+}
+
+static int send_user_confirmation_request_reply(int sock,
+	struct sockaddr_hci *addr, bdaddr_p bdaddr)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	ng_hci_user_confirmation_request_reply_cp	*cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+					NG_HCI_USER_CONFIRMATION_REQUEST_REPLY));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_user_confirmation_request_reply_cp *)(cmd + 1);
+	memcpy(&cp->bdaddr, bdaddr, sizeof(bdaddr_t));
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not user confirmation request reply to remote " \
+				" bdaddr '%s'. %s (%d)", bt_ntoa(bdaddr, NULL),
+				strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int process_user_confirmation_request_event(int sock,
+	struct sockaddr_hci *addr, ng_hci_user_confirmation_request_ep *ep)
+{
+	return (send_user_confirmation_request_reply(sock, addr, &ep->bdaddr));
+}
+
+static int send_set_con_encryption_enabled(int sock, struct sockaddr_hci *=
addr,
+	u_int16_t con_handle)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd =3D NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd =3D (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type =3D NG_HCI_CMD_PKT;
+
+	 ng_hci_set_con_encryption_cp *cp =3D NULL;
+
+	cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+					NG_HCI_OCF_SET_CON_ENCRYPTION));
+	cmd->length =3D sizeof(*cp);
+
+	cp =3D (ng_hci_set_con_encryption_cp *)(cmd + 1);
+	cp->con_handle =3D htole16(con_handle);
+	cp->encryption_enable =3D 0x01; /* 0x01 - encryption enabled */
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno =3D=3D EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not set encryption enabled for con_handle =3D %d.=
" \
+				" %s (%d)", con_handle, strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int process_auth_compl_event(int sock, struct sockaddr_hci *addr,
+	ng_hci_auth_compl_ep *ep)
+{
+	if (pairing =3D=3D 1) {
+		pairing =3D 0;
+		return (send_set_con_encryption_enabled(sock, addr, ep->con_handle));
+	} else
+		return (0);
+}
+
 /* Signal handlers */
 static void
 sighup(int s)

--m88YXiM89buYlW4g--

--+pkO+WIezJok9CBI
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEETci4cPcl+ZcyiACiCkqKrhcKSD0FAmEKiSYACgkQCkqKrhcK
SD1cQQ/+OHgphpdczZsG6lKjf4g+t+MsQiYmFJCRB49UyOSarn1VO6QbuOTioTp/
wqREt2c50PY5E2fYra4qo5AME8BalVJXMfcOqYfkp0b2BcgyxpW+SGzqn816QEAo
I3Zc35ynhP39hwboU2Z3Omuh3WabksfJrVakKbnWd4wghMY6KRa66re91sKdxB17
uOW42HQpP4QLvOL0DkFlHcwL32kMHqbUoTFHv6S0LhAtEYa5NVpOyDJpWieadTUN
6BI6BSIvaCtUgH+rhQNC6XUpoCi7X3Sk3H3Kpx6Yiusj58CRwS1cnDamaiKKifRi
6T5FJBvQ10AtqZSrSn1xpKQoCjreSRz+1jd8FUybtAw4HFNk9iwePqLuM4OKHs4e
FP2zAePZsllCCb31wMEvVyPOrKPexD9YICJ3828DYWIZ3TfJVX+Jk9kK0XCwLvyA
jGJXfGpD0OAb/EKKi/8Kp9hxIoJIqeoBuMcrQ8QymRw2qz+86NuPOGRsjidr1Ge9
PnsIyzeJha1Ui1VJHzep8iji7lrT5li/K7JRvETFS5rkeFo0iXyqTNhgnrrBc9y+
Biqj041I+d73NrP9nreAwRXW0avqbXv+HK5TDudhiFLJ/GI0Kdlp7SxVBjl3fH4i
PVracfCnG0GzZgf69wymCHrSVoSRmJsUo8pGeNoK/pWoq1f1y90=
=Nnl2
-----END PGP SIGNATURE-----

--+pkO+WIezJok9CBI--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?YQqJLE/NQ0C9XmD4>