Bluetooth: BR/EDR: Reply to IO Capability request

For now as local host works as pairing acceptor, the pairing context
flag is set when remote IO Capabilities is received.
Reply to the request uses remote's authentication requirement
cross-checked against predefined authentication methods that are based
on local and remote IO capabilities.

> HCI Event: IO Capability Response (0x32) plen 9
	Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd)
	IO capability: NoInputNoOutput (0x03)
	OOB data: Authentication data not present (0x00)
	Authentication: No Bonding - MITM not required (0x00)
> HCI Event: IO Capability Request (0x31) plen 6
	Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd)
< HCI Command: IO Capability Request Reply (0x01|0x002b) plen 9
	Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd)
	IO capability: DisplayYesNo (0x01)
	OOB data: Authentication data not present (0x00)
	Authentication: No Bonding - MITM not required (0x00)
> HCI Event: Command Complete (0x0e) plen 10
	IO Capability Request Reply (0x01|0x002b) ncmd 1
	Status: Success (0x00)
	Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd)

Change-Id: I0f95a58178618f06de16cce0e9d9cf6c85209677
Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
This commit is contained in:
Arkadiusz Lichwa 2016-01-29 16:12:55 +01:00 committed by Johan Hedberg
commit 02f541dfc5
4 changed files with 86 additions and 4 deletions

View file

@ -138,6 +138,12 @@ struct bt_hci_cmd_hdr {
#define BT_HCI_GENERAL_BONDING 0x04 #define BT_HCI_GENERAL_BONDING 0x04
#define BT_HCI_GENERAL_BONDING_MITM 0x05 #define BT_HCI_GENERAL_BONDING_MITM 0x05
/*
* MITM protection is enabled in SSP authentication requirements octet when
* LSB bit is set.
*/
#define BT_MITM 0x01
/* I/O capabilities */ /* I/O capabilities */
#define BT_IO_DISPLAY_ONLY 0x00 #define BT_IO_DISPLAY_ONLY 0x00
#define BT_IO_DISPLAY_YESNO 0x01 #define BT_IO_DISPLAY_YESNO 0x01

View file

@ -62,6 +62,23 @@ const struct bt_conn_auth_cb *bt_auth;
static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN]; static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN];
static struct bt_conn_cb *callback_list; static struct bt_conn_cb *callback_list;
#if defined(CONFIG_BLUETOOTH_BREDR)
enum pairing_method {
JUST_WORKS, /* JustWorks pairing */
PASSKEY_INPUT, /* Passkey Entry input */
PASSKEY_DISPLAY, /* Passkey Entry display */
PASSKEY_CONFIRM, /* Passkey confirm */
};
/* based on table 5.7, Core Spec 4.2, Vol.3 Part C, 5.2.2.6 */
static const uint8_t ssp_method[4 /* remote */][4 /* local */] = {
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS },
{ JUST_WORKS, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS },
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS },
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
};
#endif /* CONFIG_BLUETOOTH_BREDR */
#if defined(CONFIG_BLUETOOTH_DEBUG_CONN) #if defined(CONFIG_BLUETOOTH_DEBUG_CONN)
static const char *state2str(bt_conn_state_t state) static const char *state2str(bt_conn_state_t state)
{ {
@ -755,6 +772,50 @@ void bt_conn_pin_code_req(struct bt_conn *conn)
pin_code_neg_reply(&conn->br.dst); pin_code_neg_reply(&conn->br.dst);
} }
} }
uint8_t bt_conn_get_io_capa(void)
{
if (!bt_auth) {
return BT_IO_NO_INPUT_OUTPUT;
}
if (bt_auth->passkey_confirm && bt_auth->passkey_display) {
return BT_IO_DISPLAY_YESNO;
}
if (bt_auth->passkey_entry) {
return BT_IO_KEYBOARD_ONLY;
}
if (bt_auth->passkey_display) {
return BT_IO_DISPLAY_ONLY;
}
return BT_IO_NO_INPUT_OUTPUT;
}
static uint8_t ssp_pair_method(const struct bt_conn *conn)
{
return ssp_method[conn->br.remote_io_capa][bt_conn_get_io_capa()];
}
uint8_t bt_conn_ssp_get_auth(const struct bt_conn *conn)
{
/* Validate no bond auth request, and if valid use it. */
if ((conn->br.remote_auth == BT_HCI_NO_BONDING) ||
((conn->br.remote_auth == BT_HCI_NO_BONDING_MITM) &&
(ssp_pair_method(conn) > JUST_WORKS))) {
return conn->br.remote_auth;
}
/* Local & remote have enough IO capabilities to get MITM protection. */
if (ssp_pair_method(conn) > JUST_WORKS) {
return conn->br.remote_auth | BT_MITM;
}
/* No MITM protection possible so ignore remote MITM requirement. */
return (conn->br.remote_auth & ~BT_MITM);
}
#endif #endif
static void timeout_fiber(int arg1, int arg2) static void timeout_fiber(int arg1, int arg2)

View file

@ -124,6 +124,8 @@ struct bt_conn *bt_conn_add_br(const bt_addr_t *peer);
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer); struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer);
void bt_conn_pin_code_req(struct bt_conn *conn); void bt_conn_pin_code_req(struct bt_conn *conn);
uint8_t bt_conn_get_io_capa(void);
uint8_t bt_conn_ssp_get_auth(const struct bt_conn *conn);
#endif #endif
/* Look up an existing connection */ /* Look up an existing connection */

View file

@ -1175,6 +1175,7 @@ static void io_capa_resp(struct net_buf *buf)
conn->br.remote_io_capa = evt->capability; conn->br.remote_io_capa = evt->capability;
conn->br.remote_auth = evt->authentication; conn->br.remote_auth = evt->authentication;
atomic_set_bit(conn->flags, BT_CONN_BR_PAIRING);
bt_conn_unref(conn); bt_conn_unref(conn);
} }
@ -1182,20 +1183,32 @@ static void io_capa_req(struct net_buf *buf)
{ {
struct bt_hci_evt_io_capa_req *evt = (void *)buf->data; struct bt_hci_evt_io_capa_req *evt = (void *)buf->data;
struct net_buf *resp_buf; struct net_buf *resp_buf;
struct bt_hci_cp_io_capability_neg_reply *cp; struct bt_conn *conn;
struct bt_hci_cp_io_capability_reply *cp;
BT_DBG(""); BT_DBG("");
resp_buf = bt_hci_cmd_create(BT_HCI_OP_IO_CAPABILITY_NEG_REPLY, conn = bt_conn_lookup_addr_br(&evt->bdaddr);
if (!conn) {
BT_ERR("Can't find conn for %s", bt_addr_str(&evt->bdaddr));
return;
}
resp_buf = bt_hci_cmd_create(BT_HCI_OP_IO_CAPABILITY_REPLY,
sizeof(*cp)); sizeof(*cp));
if (!resp_buf) { if (!resp_buf) {
BT_ERR("Out of command buffers");
bt_conn_unref(conn);
return; return;
} }
cp = net_buf_add(resp_buf, sizeof(*cp)); cp = net_buf_add(resp_buf, sizeof(*cp));
bt_addr_copy(&cp->bdaddr, &evt->bdaddr); bt_addr_copy(&cp->bdaddr, &evt->bdaddr);
cp->reason = BT_HCI_ERR_PAIRING_NOT_ALLOWED; cp->capability = bt_conn_get_io_capa();
bt_hci_cmd_send_sync(BT_HCI_OP_IO_CAPABILITY_NEG_REPLY, resp_buf, NULL); cp->authentication = bt_conn_ssp_get_auth(conn);
cp->oob_data = 0;
bt_hci_cmd_send_sync(BT_HCI_OP_IO_CAPABILITY_REPLY, resp_buf, NULL);
bt_conn_unref(conn);
} }
static void ssp_complete(struct net_buf *buf) static void ssp_complete(struct net_buf *buf)