bluetooth pull request for net:

- MGMT: Add error handling to pair_device()
  - HCI: Invert LE State quirk to be opt-out rather then opt-in
  - hci_core: Fix LE quote calculation
  - SMP: Fix assumption of Central always being Initiator
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAma+N98ZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKd4hEAChdssSToDfurZ7CC4kssnE
 ySwb2ADmB+67fqgaXuWsL3y0rHZQHg7rT1u6G0T4qc92UnVfqNJb5xvDKrWQ9d8+
 rsN/xAYqz/xegJysueXB/u6Q+82aKsTl22aA9vUl+KWuuuTA4W4SvSwi3I3JY1Go
 t8UuW5GaW1c3GNukHzmSXqmmSs19z78LnCCjqXx+4Ec+FhVkW45v6OKKSzYi52wZ
 yfAh6xJ+E2+FjpJfI1vyOD4XJ/RSH8V5kauI+bvyWlmRuKjAwtYzdj7zzpZ6geJg
 p+6NHdJEjiI8Wm/Fth3AGWyztbbnot/9c3i9NLF7tvxAtmFV30QaTNeAEWbmYleZ
 PE5ED2x+DZLxTi+60+Xu0zFUdnC8pqjJs7sU9HxJiNCJYcAorcVG7VE2dlj9Vy5G
 D/iY147rWWG4ZPkNRfnXuTgHPNs1Zpa71CMH2A1h1w9sRjbTgNwl8Xp5RdxN6yoL
 Zdz2x0zO5afUV3fzrdV/pq8DOMWtkjchEVk9nK9q6vRSiXbrgWqeYfKE+iLEFmrp
 hKKiHcgvaS91C5kFHiSIcV+koVNw6mivympjZ+hl1zcKtojt17A0nUX4aweSxwd7
 UksHVT0quuKQUDSE5uDYdfs2bxMj8m0q6/NiGH00oELQyaKOL1ge7eF3lgf8Af0b
 WDzeZo8zzrMnWA602m6kNg==
 =CjpO
 -----END PGP SIGNATURE-----

Merge tag 'for-net-2024-08-15' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - MGMT: Add error handling to pair_device()
 - HCI: Invert LE State quirk to be opt-out rather then opt-in
 - hci_core: Fix LE quote calculation
 - SMP: Fix assumption of Central always being Initiator

* tag 'for-net-2024-08-15' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: MGMT: Add error handling to pair_device()
  Bluetooth: SMP: Fix assumption of Central always being Initiator
  Bluetooth: hci_core: Fix LE quote calculation
  Bluetooth: HCI: Invert LE State quirk to be opt-out rather then opt-in
====================

Link: https://patch.msgid.link/20240815171950.1082068-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-08-16 19:07:30 -07:00
commit 2d7423040b
13 changed files with 100 additions and 117 deletions

View File

@ -2945,9 +2945,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
INTEL_ROM_LEGACY_NO_WBS_SUPPORT)) INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks); &hdev->quirks);
if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
set_bit(HCI_QUIRK_VALID_LE_STATES,
&hdev->quirks);
err = btintel_legacy_rom_setup(hdev, &ver); err = btintel_legacy_rom_setup(hdev, &ver);
break; break;
@ -2956,7 +2953,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
case 0x12: /* ThP */ case 0x12: /* ThP */
case 0x13: /* HrP */ case 0x13: /* HrP */
case 0x14: /* CcP */ case 0x14: /* CcP */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
fallthrough; fallthrough;
case 0x0c: /* WsP */ case 0x0c: /* WsP */
/* Apply the device specific HCI quirks /* Apply the device specific HCI quirks
@ -3048,9 +3044,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
/* These variants don't seem to support LE Coded PHY */ /* These variants don't seem to support LE Coded PHY */
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
/* Set Valid LE States quirk */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */ /* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant); btintel_set_msft_opcode(hdev, ver.hw_variant);
@ -3076,9 +3069,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
*/ */
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* Apply LE States quirk from solar onwards */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */ /* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, btintel_set_msft_opcode(hdev,
INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); INTEL_HW_VARIANT(ver_tlv.cnvi_bt));

View File

@ -1180,9 +1180,6 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
*/ */
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* Apply LE States quirk from solar onwards */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */ /* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, btintel_set_msft_opcode(hdev,
INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); INTEL_HW_VARIANT(ver_tlv.cnvi_bt));

View File

@ -1148,9 +1148,6 @@ static int btmtksdio_setup(struct hci_dev *hdev)
} }
} }
/* Valid LE States quirk for MediaTek 7921 */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
break; break;
case 0x7663: case 0x7663:
case 0x7668: case 0x7668:

View File

@ -1287,7 +1287,6 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
case CHIP_ID_8852C: case CHIP_ID_8852C:
case CHIP_ID_8851B: case CHIP_ID_8851B:
case CHIP_ID_8852BT: case CHIP_ID_8852BT:
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* RTL8852C needs to transmit mSBC data continuously without /* RTL8852C needs to transmit mSBC data continuously without

View File

@ -3956,8 +3956,8 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_WIDEBAND_SPEECH) if (id->driver_info & BTUSB_WIDEBAND_SPEECH)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
if (id->driver_info & BTUSB_VALID_LE_STATES) if (!(id->driver_info & BTUSB_VALID_LE_STATES))
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_LE_STATES, &hdev->quirks);
if (id->driver_info & BTUSB_DIGIANSWER) { if (id->driver_info & BTUSB_DIGIANSWER) {
data->cmdreq_type = USB_TYPE_VENDOR; data->cmdreq_type = USB_TYPE_VENDOR;

View File

@ -2474,8 +2474,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks); &hdev->quirks);
if (data->capabilities & QCA_CAP_VALID_LE_STATES) if (!(data->capabilities & QCA_CAP_VALID_LE_STATES))
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_LE_STATES, &hdev->quirks);
} }
return 0; return 0;

View File

@ -425,8 +425,6 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
if (opcode & 0x80) if (opcode & 0x80)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
hci_free_dev(hdev); hci_free_dev(hdev);

View File

@ -206,14 +206,17 @@ enum {
*/ */
HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
/* When this quirk is set, the controller has validated that /* When this quirk is set, the LE states reported through the
* LE states reported through the HCI_LE_READ_SUPPORTED_STATES are * HCI_LE_READ_SUPPORTED_STATES are invalid/broken.
* valid. This mechanism is necessary as many controllers have *
* been seen has having trouble initiating a connectable * This mechanism is necessary as many controllers have been seen has
* advertisement despite the state combination being reported as * having trouble initiating a connectable advertisement despite the
* supported. * state combination being reported as supported.
*
* This quirk can be set before hci_register_dev is called or
* during the hdev->setup vendor callback.
*/ */
HCI_QUIRK_VALID_LE_STATES, HCI_QUIRK_BROKEN_LE_STATES,
/* When this quirk is set, then erroneous data reporting /* When this quirk is set, then erroneous data reporting
* is ignored. This is mainly due to the fact that the HCI * is ignored. This is mainly due to the fact that the HCI

View File

@ -825,7 +825,7 @@ extern struct mutex hci_cb_list_lock;
} while (0) } while (0)
#define hci_dev_le_state_simultaneous(hdev) \ #define hci_dev_le_state_simultaneous(hdev) \
(test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) && \ (!test_bit(HCI_QUIRK_BROKEN_LE_STATES, &hdev->quirks) && \
(hdev->le_states[4] & 0x08) && /* Central */ \ (hdev->le_states[4] & 0x08) && /* Central */ \
(hdev->le_states[4] & 0x40) && /* Peripheral */ \ (hdev->le_states[4] & 0x40) && /* Peripheral */ \
(hdev->le_states[3] & 0x10)) /* Simultaneous */ (hdev->le_states[3] & 0x10)) /* Simultaneous */

View File

@ -3664,19 +3664,19 @@ static void hci_sched_le(struct hci_dev *hdev)
{ {
struct hci_chan *chan; struct hci_chan *chan;
struct sk_buff *skb; struct sk_buff *skb;
int quote, cnt, tmp; int quote, *cnt, tmp;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, LE_LINK)) if (!hci_conn_num(hdev, LE_LINK))
return; return;
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; cnt = hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt;
__check_timeout(hdev, cnt, LE_LINK); __check_timeout(hdev, *cnt, LE_LINK);
tmp = cnt; tmp = *cnt;
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) { while (*cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority; u32 priority = (skb_peek(&chan->data_q))->priority;
while (quote-- && (skb = skb_peek(&chan->data_q))) { while (quote-- && (skb = skb_peek(&chan->data_q))) {
BT_DBG("chan %p skb %p len %d priority %u", chan, skb, BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
@ -3691,7 +3691,7 @@ static void hci_sched_le(struct hci_dev *hdev)
hci_send_frame(hdev, skb); hci_send_frame(hdev, skb);
hdev->le_last_tx = jiffies; hdev->le_last_tx = jiffies;
cnt--; (*cnt)--;
chan->sent++; chan->sent++;
chan->conn->sent++; chan->conn->sent++;
@ -3701,12 +3701,7 @@ static void hci_sched_le(struct hci_dev *hdev)
} }
} }
if (hdev->le_pkts) if (*cnt != tmp)
hdev->le_cnt = cnt;
else
hdev->acl_cnt = cnt;
if (cnt != tmp)
hci_prio_recalculate(hdev, LE_LINK); hci_prio_recalculate(hdev, LE_LINK);
} }

View File

@ -5920,7 +5920,7 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
* while we have an existing one in peripheral role. * while we have an existing one in peripheral role.
*/ */
if (hdev->conn_hash.le_num_peripheral > 0 && if (hdev->conn_hash.le_num_peripheral > 0 &&
(!test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) || (test_bit(HCI_QUIRK_BROKEN_LE_STATES, &hdev->quirks) ||
!(hdev->le_states[3] & 0x10))) !(hdev->le_states[3] & 0x10)))
return NULL; return NULL;

View File

@ -3456,6 +3456,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
* will be kept and this function does nothing. * will be kept and this function does nothing.
*/ */
p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); p = hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
if (!p) {
err = -EIO;
goto unlock;
}
if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT) if (p->auto_connect == HCI_AUTO_CONN_EXPLICIT)
p->auto_connect = HCI_AUTO_CONN_DISABLED; p->auto_connect = HCI_AUTO_CONN_DISABLED;

View File

@ -914,7 +914,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
* Confirms and the responder Enters the passkey. * Confirms and the responder Enters the passkey.
*/ */
if (smp->method == OVERLAP) { if (smp->method == OVERLAP) {
if (hcon->role == HCI_ROLE_MASTER) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
smp->method = CFM_PASSKEY; smp->method = CFM_PASSKEY;
else else
smp->method = REQ_PASSKEY; smp->method = REQ_PASSKEY;
@ -964,7 +964,7 @@ static u8 smp_confirm(struct smp_chan *smp)
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
if (conn->hcon->out) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
else else
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
@ -980,7 +980,8 @@ static u8 smp_random(struct smp_chan *smp)
int ret; int ret;
bt_dev_dbg(conn->hcon->hdev, "conn %p %s", conn, bt_dev_dbg(conn->hcon->hdev, "conn %p %s", conn,
conn->hcon->out ? "initiator" : "responder"); test_bit(SMP_FLAG_INITIATOR, &smp->flags) ? "initiator" :
"responder");
ret = smp_c1(smp->tk, smp->rrnd, smp->preq, smp->prsp, ret = smp_c1(smp->tk, smp->rrnd, smp->preq, smp->prsp,
hcon->init_addr_type, &hcon->init_addr, hcon->init_addr_type, &hcon->init_addr,
@ -994,7 +995,7 @@ static u8 smp_random(struct smp_chan *smp)
return SMP_CONFIRM_FAILED; return SMP_CONFIRM_FAILED;
} }
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
u8 stk[16]; u8 stk[16];
__le64 rand = 0; __le64 rand = 0;
__le16 ediv = 0; __le16 ediv = 0;
@ -1256,14 +1257,15 @@ static void smp_distribute_keys(struct smp_chan *smp)
rsp = (void *) &smp->prsp[1]; rsp = (void *) &smp->prsp[1];
/* The responder sends its keys first */ /* The responder sends its keys first */
if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags) &&
(smp->remote_key_dist & KEY_DIST_MASK)) {
smp_allow_key_dist(smp); smp_allow_key_dist(smp);
return; return;
} }
req = (void *) &smp->preq[1]; req = (void *) &smp->preq[1];
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
keydist = &rsp->init_key_dist; keydist = &rsp->init_key_dist;
*keydist &= req->init_key_dist; *keydist &= req->init_key_dist;
} else { } else {
@ -1432,7 +1434,7 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
struct hci_conn *hcon = smp->conn->hcon; struct hci_conn *hcon = smp->conn->hcon;
u8 *na, *nb, a[7], b[7]; u8 *na, *nb, a[7], b[7];
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
na = smp->prnd; na = smp->prnd;
nb = smp->rrnd; nb = smp->rrnd;
} else { } else {
@ -1460,7 +1462,7 @@ static void sc_dhkey_check(struct smp_chan *smp)
a[6] = hcon->init_addr_type; a[6] = hcon->init_addr_type;
b[6] = hcon->resp_addr_type; b[6] = hcon->resp_addr_type;
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
local_addr = a; local_addr = a;
remote_addr = b; remote_addr = b;
memcpy(io_cap, &smp->preq[1], 3); memcpy(io_cap, &smp->preq[1], 3);
@ -1539,7 +1541,7 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
/* The round is only complete when the initiator /* The round is only complete when the initiator
* receives pairing random. * receives pairing random.
*/ */
if (!hcon->out) { if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd); sizeof(smp->prnd), smp->prnd);
if (smp->passkey_round == 20) if (smp->passkey_round == 20)
@ -1567,7 +1569,7 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd); sizeof(smp->prnd), smp->prnd);
return 0; return 0;
@ -1578,7 +1580,7 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
case SMP_CMD_PUBLIC_KEY: case SMP_CMD_PUBLIC_KEY:
default: default:
/* Initiating device starts the round */ /* Initiating device starts the round */
if (!hcon->out) if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags))
return 0; return 0;
bt_dev_dbg(hdev, "Starting passkey round %u", bt_dev_dbg(hdev, "Starting passkey round %u",
@ -1623,7 +1625,7 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
} }
/* Initiator sends DHKey check first */ /* Initiator sends DHKey check first */
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
sc_dhkey_check(smp); sc_dhkey_check(smp);
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
} else if (test_and_clear_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags)) { } else if (test_and_clear_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags)) {
@ -1746,7 +1748,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_cmd_pairing rsp, *req = (void *) skb->data;
struct l2cap_chan *chan = conn->smp; struct l2cap_chan *chan = conn->smp;
struct hci_dev *hdev = conn->hcon->hdev; struct hci_dev *hdev = conn->hcon->hdev;
struct smp_chan *smp; struct smp_chan *smp = chan->data;
u8 key_size, auth, sec_level; u8 key_size, auth, sec_level;
int ret; int ret;
@ -1755,16 +1757,14 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (skb->len < sizeof(*req)) if (skb->len < sizeof(*req))
return SMP_INVALID_PARAMS; return SMP_INVALID_PARAMS;
if (conn->hcon->role != HCI_ROLE_SLAVE) if (smp && test_bit(SMP_FLAG_INITIATOR, &smp->flags))
return SMP_CMD_NOTSUPP; return SMP_CMD_NOTSUPP;
if (!chan->data) if (!smp) {
smp = smp_chan_create(conn); smp = smp_chan_create(conn);
else if (!smp)
smp = chan->data; return SMP_UNSPECIFIED;
}
if (!smp)
return SMP_UNSPECIFIED;
/* We didn't start the pairing, so match remote */ /* We didn't start the pairing, so match remote */
auth = req->auth_req & AUTH_REQ_MASK(hdev); auth = req->auth_req & AUTH_REQ_MASK(hdev);
@ -1946,7 +1946,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if (skb->len < sizeof(*rsp)) if (skb->len < sizeof(*rsp))
return SMP_INVALID_PARAMS; return SMP_INVALID_PARAMS;
if (conn->hcon->role != HCI_ROLE_MASTER) if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags))
return SMP_CMD_NOTSUPP; return SMP_CMD_NOTSUPP;
skb_pull(skb, sizeof(*rsp)); skb_pull(skb, sizeof(*rsp));
@ -2041,7 +2041,7 @@ static u8 sc_check_confirm(struct smp_chan *smp)
if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY) if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
return sc_passkey_round(smp, SMP_CMD_PAIRING_CONFIRM); return sc_passkey_round(smp, SMP_CMD_PAIRING_CONFIRM);
if (conn->hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp->prnd); smp->prnd);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
@ -2063,7 +2063,7 @@ static int fixup_sc_false_positive(struct smp_chan *smp)
u8 auth; u8 auth;
/* The issue is only observed when we're in responder role */ /* The issue is only observed when we're in responder role */
if (hcon->out) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) { if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
@ -2099,7 +2099,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
bt_dev_dbg(hdev, "conn %p %s", conn, bt_dev_dbg(hdev, "conn %p %s", conn,
hcon->out ? "initiator" : "responder"); test_bit(SMP_FLAG_INITIATOR, &smp->flags) ? "initiator" :
"responder");
if (skb->len < sizeof(smp->pcnf)) if (skb->len < sizeof(smp->pcnf))
return SMP_INVALID_PARAMS; return SMP_INVALID_PARAMS;
@ -2121,7 +2122,7 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
return ret; return ret;
} }
if (conn->hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp->prnd); smp->prnd);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
@ -2156,7 +2157,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
if (!test_bit(SMP_FLAG_SC, &smp->flags)) if (!test_bit(SMP_FLAG_SC, &smp->flags))
return smp_random(smp); return smp_random(smp);
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
pkax = smp->local_pk; pkax = smp->local_pk;
pkbx = smp->remote_pk; pkbx = smp->remote_pk;
na = smp->prnd; na = smp->prnd;
@ -2169,7 +2170,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
} }
if (smp->method == REQ_OOB) { if (smp->method == REQ_OOB) {
if (!hcon->out) if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags))
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd); sizeof(smp->prnd), smp->prnd);
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
@ -2180,7 +2181,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY) if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM); return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
u8 cfm[16]; u8 cfm[16];
err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk, err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
@ -2221,7 +2222,7 @@ mackey_and_ltk:
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
if (smp->method == REQ_OOB) { if (smp->method == REQ_OOB) {
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
sc_dhkey_check(smp); sc_dhkey_check(smp);
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
} }
@ -2295,10 +2296,27 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
return false; return false;
} }
static void smp_send_pairing_req(struct smp_chan *smp, __u8 auth)
{
struct smp_cmd_pairing cp;
if (smp->conn->hcon->type == ACL_LINK)
build_bredr_pairing_cmd(smp, &cp, NULL);
else
build_pairing_cmd(smp->conn, &cp, NULL, auth);
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
}
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_security_req *rp = (void *) skb->data;
struct smp_cmd_pairing cp;
struct hci_conn *hcon = conn->hcon; struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
struct smp_chan *smp; struct smp_chan *smp;
@ -2347,18 +2365,22 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(*rp)); skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp)); smp_send_pairing_req(smp, auth);
build_pairing_cmd(conn, &cp, NULL, auth);
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
return 0; return 0;
} }
static void smp_send_security_req(struct smp_chan *smp, __u8 auth)
{
struct smp_cmd_security_req cp;
cp.auth_req = auth;
smp_send_cmd(smp->conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
clear_bit(SMP_FLAG_INITIATOR, &smp->flags);
}
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
@ -2427,23 +2449,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
authreq |= SMP_AUTH_MITM; authreq |= SMP_AUTH_MITM;
} }
if (hcon->role == HCI_ROLE_MASTER) { if (hcon->role == HCI_ROLE_MASTER)
struct smp_cmd_pairing cp; smp_send_pairing_req(smp, authreq);
else
smp_send_security_req(smp, authreq);
build_pairing_cmd(conn, &cp, NULL, authreq);
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
} else {
struct smp_cmd_security_req cp;
cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
}
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
ret = 0; ret = 0;
unlock: unlock:
@ -2694,8 +2704,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 sc_select_method(struct smp_chan *smp) static u8 sc_select_method(struct smp_chan *smp)
{ {
struct l2cap_conn *conn = smp->conn;
struct hci_conn *hcon = conn->hcon;
struct smp_cmd_pairing *local, *remote; struct smp_cmd_pairing *local, *remote;
u8 local_mitm, remote_mitm, local_io, remote_io, method; u8 local_mitm, remote_mitm, local_io, remote_io, method;
@ -2708,7 +2716,7 @@ static u8 sc_select_method(struct smp_chan *smp)
* the "struct smp_cmd_pairing" from them we need to skip the * the "struct smp_cmd_pairing" from them we need to skip the
* first byte which contains the opcode. * first byte which contains the opcode.
*/ */
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
local = (void *) &smp->preq[1]; local = (void *) &smp->preq[1];
remote = (void *) &smp->prsp[1]; remote = (void *) &smp->prsp[1];
} else { } else {
@ -2777,7 +2785,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
/* Non-initiating device sends its public key after receiving /* Non-initiating device sends its public key after receiving
* the key from the initiating device. * the key from the initiating device.
*/ */
if (!hcon->out) { if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
err = sc_send_public_key(smp); err = sc_send_public_key(smp);
if (err) if (err)
return err; return err;
@ -2839,7 +2847,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
} }
if (smp->method == REQ_OOB) { if (smp->method == REQ_OOB) {
if (hcon->out) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd); sizeof(smp->prnd), smp->prnd);
@ -2848,7 +2856,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
return 0; return 0;
} }
if (hcon->out) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
if (smp->method == REQ_PASSKEY) { if (smp->method == REQ_PASSKEY) {
@ -2863,7 +2871,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
/* The Initiating device waits for the non-initiating device to /* The Initiating device waits for the non-initiating device to
* send the confirm value. * send the confirm value.
*/ */
if (conn->hcon->out) if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
return 0; return 0;
err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd,
@ -2897,7 +2905,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
a[6] = hcon->init_addr_type; a[6] = hcon->init_addr_type;
b[6] = hcon->resp_addr_type; b[6] = hcon->resp_addr_type;
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
local_addr = a; local_addr = a;
remote_addr = b; remote_addr = b;
memcpy(io_cap, &smp->prsp[1], 3); memcpy(io_cap, &smp->prsp[1], 3);
@ -2922,7 +2930,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
if (crypto_memneq(check->e, e, 16)) if (crypto_memneq(check->e, e, 16))
return SMP_DHKEY_CHECK_FAILED; return SMP_DHKEY_CHECK_FAILED;
if (!hcon->out) { if (!test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) { if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) {
set_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags); set_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags);
return 0; return 0;
@ -2934,7 +2942,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
sc_add_ltk(smp); sc_add_ltk(smp);
if (hcon->out) { if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
hci_le_start_enc(hcon, 0, 0, smp->tk, smp->enc_key_size); hci_le_start_enc(hcon, 0, 0, smp->tk, smp->enc_key_size);
hcon->enc_key_size = smp->enc_key_size; hcon->enc_key_size = smp->enc_key_size;
} }
@ -3083,7 +3091,6 @@ static void bredr_pairing(struct l2cap_chan *chan)
struct l2cap_conn *conn = chan->conn; struct l2cap_conn *conn = chan->conn;
struct hci_conn *hcon = conn->hcon; struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
struct smp_cmd_pairing req;
struct smp_chan *smp; struct smp_chan *smp;
bt_dev_dbg(hdev, "chan %p", chan); bt_dev_dbg(hdev, "chan %p", chan);
@ -3135,14 +3142,7 @@ static void bredr_pairing(struct l2cap_chan *chan)
bt_dev_dbg(hdev, "starting SMP over BR/EDR"); bt_dev_dbg(hdev, "starting SMP over BR/EDR");
/* Prepare and send the BR/EDR SMP Pairing Request */ smp_send_pairing_req(smp, 0x00);
build_bredr_pairing_cmd(smp, &req, NULL);
smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], &req, sizeof(req));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(req), &req);
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
} }
static void smp_resume_cb(struct l2cap_chan *chan) static void smp_resume_cb(struct l2cap_chan *chan)