mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
Merge tag 'for-net-2025-11-21' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - hci_sock: Prevent race in socket write iter and sock bind - hci_core: Fix triggering cmd_timer for HCI_OP_NOP - hci_core: lookup hci_conn on RX path on protocol side - SMP: Fix not generating mackey and ltk when repairing - btusb: mediatek: Fix kernel crash when releasing mtk iso interface - btusb: mediatek: Avoid btusb_mtk_claim_iso_intf() NULL deref * tag 'for-net-2025-11-21' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: SMP: Fix not generating mackey and ltk when repairing Bluetooth: btusb: mediatek: Avoid btusb_mtk_claim_iso_intf() NULL deref Bluetooth: hci_core: lookup hci_conn on RX path on protocol side Bluetooth: hci_sock: Prevent race in socket write iter and sock bind Bluetooth: hci_core: Fix triggering cmd_timer for HCI_OP_NOP Bluetooth: btusb: mediatek: Fix kernel crash when releasing mtk iso interface ==================== Link: https://patch.msgid.link/20251121145332.177015-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -2711,9 +2711,21 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
static void btusb_mtk_claim_iso_intf(struct btusb_data *data)
|
||||
{
|
||||
struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
|
||||
struct btmtk_data *btmtk_data;
|
||||
int err;
|
||||
|
||||
if (!data->hdev)
|
||||
return;
|
||||
|
||||
btmtk_data = hci_get_priv(data->hdev);
|
||||
if (!btmtk_data)
|
||||
return;
|
||||
|
||||
if (!btmtk_data->isopkt_intf) {
|
||||
bt_dev_err(data->hdev, "Can't claim NULL iso interface");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function usb_driver_claim_interface() is documented to need
|
||||
* locks held if it's not called from a probe routine. The code here
|
||||
@@ -2735,17 +2747,30 @@ static void btusb_mtk_claim_iso_intf(struct btusb_data *data)
|
||||
|
||||
static void btusb_mtk_release_iso_intf(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
||||
struct btmtk_data *btmtk_data;
|
||||
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
btmtk_data = hci_get_priv(hdev);
|
||||
if (!btmtk_data)
|
||||
return;
|
||||
|
||||
if (test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) {
|
||||
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
|
||||
clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
|
||||
|
||||
if (btmtk_data->isopkt_skb) {
|
||||
dev_kfree_skb_irq(btmtk_data->isopkt_skb);
|
||||
btmtk_data->isopkt_skb = NULL;
|
||||
}
|
||||
|
||||
if (btmtk_data->isopkt_intf) {
|
||||
usb_set_intfdata(btmtk_data->isopkt_intf, NULL);
|
||||
usb_driver_release_interface(&btusb_driver,
|
||||
btmtk_data->isopkt_intf);
|
||||
btmtk_data->isopkt_intf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
|
||||
|
||||
@@ -749,7 +749,6 @@ struct hci_conn {
|
||||
|
||||
__u8 remote_cap;
|
||||
__u8 remote_auth;
|
||||
__u8 remote_id;
|
||||
|
||||
unsigned int sent;
|
||||
|
||||
@@ -857,11 +856,12 @@ extern struct mutex hci_cb_list_lock;
|
||||
/* ----- HCI interface to upper protocols ----- */
|
||||
int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int l2cap_disconn_ind(struct hci_conn *hcon);
|
||||
void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
|
||||
int l2cap_recv_acldata(struct hci_dev *hdev, u16 handle, struct sk_buff *skb,
|
||||
u16 flags);
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_BREDR)
|
||||
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
|
||||
void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
|
||||
int sco_recv_scodata(struct hci_dev *hdev, u16 handle, struct sk_buff *skb);
|
||||
#else
|
||||
static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__u8 *flags)
|
||||
@@ -869,23 +869,30 @@ static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
|
||||
static inline int sco_recv_scodata(struct hci_dev *hdev, u16 handle,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_LE)
|
||||
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
|
||||
void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
|
||||
int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb,
|
||||
u16 flags);
|
||||
#else
|
||||
static inline int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__u8 *flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void iso_recv(struct hci_conn *hcon, struct sk_buff *skb,
|
||||
u16 flags)
|
||||
|
||||
static inline int iso_recv(struct hci_dev *hdev, u16 handle,
|
||||
struct sk_buff *skb, u16 flags)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3832,13 +3832,14 @@ static void hci_tx_work(struct work_struct *work)
|
||||
static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_acl_hdr *hdr;
|
||||
struct hci_conn *conn;
|
||||
__u16 handle, flags;
|
||||
int err;
|
||||
|
||||
hdr = skb_pull_data(skb, sizeof(*hdr));
|
||||
if (!hdr) {
|
||||
bt_dev_err(hdev, "ACL packet too small");
|
||||
goto drop;
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
handle = __le16_to_cpu(hdr->handle);
|
||||
@@ -3850,36 +3851,27 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hdev->stat.acl_rx++;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
conn = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (conn) {
|
||||
hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
|
||||
|
||||
/* Send to upper protocol */
|
||||
l2cap_recv_acldata(conn, skb, flags);
|
||||
return;
|
||||
} else {
|
||||
err = l2cap_recv_acldata(hdev, handle, skb, flags);
|
||||
if (err == -ENOENT)
|
||||
bt_dev_err(hdev, "ACL packet for unknown connection handle %d",
|
||||
handle);
|
||||
}
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
else if (err)
|
||||
bt_dev_dbg(hdev, "ACL packet recv for handle %d failed: %d",
|
||||
handle, err);
|
||||
}
|
||||
|
||||
/* SCO data packet */
|
||||
static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_sco_hdr *hdr;
|
||||
struct hci_conn *conn;
|
||||
__u16 handle, flags;
|
||||
int err;
|
||||
|
||||
hdr = skb_pull_data(skb, sizeof(*hdr));
|
||||
if (!hdr) {
|
||||
bt_dev_err(hdev, "SCO packet too small");
|
||||
goto drop;
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
handle = __le16_to_cpu(hdr->handle);
|
||||
@@ -3891,34 +3883,28 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hdev->stat.sco_rx++;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
conn = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (conn) {
|
||||
/* Send to upper protocol */
|
||||
hci_skb_pkt_status(skb) = flags & 0x03;
|
||||
sco_recv_scodata(conn, skb);
|
||||
return;
|
||||
} else {
|
||||
|
||||
err = sco_recv_scodata(hdev, handle, skb);
|
||||
if (err == -ENOENT)
|
||||
bt_dev_err_ratelimited(hdev, "SCO packet for unknown connection handle %d",
|
||||
handle);
|
||||
}
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
else if (err)
|
||||
bt_dev_dbg(hdev, "SCO packet recv for handle %d failed: %d",
|
||||
handle, err);
|
||||
}
|
||||
|
||||
static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_iso_hdr *hdr;
|
||||
struct hci_conn *conn;
|
||||
__u16 handle, flags;
|
||||
int err;
|
||||
|
||||
hdr = skb_pull_data(skb, sizeof(*hdr));
|
||||
if (!hdr) {
|
||||
bt_dev_err(hdev, "ISO packet too small");
|
||||
goto drop;
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
handle = __le16_to_cpu(hdr->handle);
|
||||
@@ -3928,22 +3914,13 @@ static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
bt_dev_dbg(hdev, "len %d handle 0x%4.4x flags 0x%4.4x", skb->len,
|
||||
handle, flags);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
conn = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!conn) {
|
||||
err = iso_recv(hdev, handle, skb, flags);
|
||||
if (err == -ENOENT)
|
||||
bt_dev_err(hdev, "ISO packet for unknown connection handle %d",
|
||||
handle);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Send to upper protocol */
|
||||
iso_recv(conn, skb, flags);
|
||||
return;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
else if (err)
|
||||
bt_dev_dbg(hdev, "ISO packet recv for handle %d failed: %d",
|
||||
handle, err);
|
||||
}
|
||||
|
||||
static bool hci_req_is_complete(struct hci_dev *hdev)
|
||||
@@ -4121,7 +4098,7 @@ static void hci_rx_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -4133,16 +4110,19 @@ static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (!hdev->sent_cmd) {
|
||||
skb_queue_head(&hdev->cmd_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->cmd_work);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hci_skb_opcode(skb) != HCI_OP_NOP) {
|
||||
err = hci_send_frame(hdev, skb);
|
||||
if (err < 0) {
|
||||
hci_cmd_sync_cancel_sync(hdev, -err);
|
||||
return;
|
||||
return err;
|
||||
}
|
||||
atomic_dec(&hdev->cmd_cnt);
|
||||
} else {
|
||||
err = -ENODATA;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
if (hdev->req_status == HCI_REQ_PEND &&
|
||||
@@ -4150,12 +4130,15 @@ static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
kfree_skb(hdev->req_skb);
|
||||
hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void hci_cmd_work(struct work_struct *work)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s cmd_cnt %d cmd queued %d", hdev->name,
|
||||
atomic_read(&hdev->cmd_cnt), skb_queue_len(&hdev->cmd_q));
|
||||
@@ -4166,7 +4149,9 @@ static void hci_cmd_work(struct work_struct *work)
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
hci_send_cmd_sync(hdev, skb);
|
||||
err = hci_send_cmd_sync(hdev, skb);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
if (test_bit(HCI_RESET, &hdev->flags) ||
|
||||
|
||||
@@ -1311,7 +1311,9 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||
goto done;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_index_removed(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
err = hci_dev_open(hdev->id);
|
||||
if (err) {
|
||||
|
||||
@@ -2314,14 +2314,31 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
iso_conn_del(hcon, bt_to_errno(reason));
|
||||
}
|
||||
|
||||
void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
|
||||
{
|
||||
struct iso_conn *conn = hcon->iso_data;
|
||||
struct hci_conn *hcon;
|
||||
struct iso_conn *conn;
|
||||
struct skb_shared_hwtstamps *hwts;
|
||||
__u16 pb, ts, len, sn;
|
||||
|
||||
if (!conn)
|
||||
goto drop;
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!hcon) {
|
||||
hci_dev_unlock(hdev);
|
||||
kfree_skb(skb);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
conn = iso_conn_hold_unless_zero(hcon->iso_data);
|
||||
hcon = NULL;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!conn) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pb = hci_iso_flags_pb(flags);
|
||||
ts = hci_iso_flags_ts(flags);
|
||||
@@ -2377,7 +2394,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
hci_skb_pkt_status(skb) = flags & 0x03;
|
||||
hci_skb_pkt_seqnum(skb) = sn;
|
||||
iso_recv_frame(conn, skb);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pb == ISO_SINGLE) {
|
||||
@@ -2455,6 +2472,9 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
done:
|
||||
iso_conn_put(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hci_cb iso_cb = {
|
||||
|
||||
@@ -7510,13 +7510,24 @@ struct l2cap_conn *l2cap_conn_hold_unless_zero(struct l2cap_conn *c)
|
||||
return c;
|
||||
}
|
||||
|
||||
void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
int l2cap_recv_acldata(struct hci_dev *hdev, u16 handle,
|
||||
struct sk_buff *skb, u16 flags)
|
||||
{
|
||||
struct hci_conn *hcon;
|
||||
struct l2cap_conn *conn;
|
||||
int len;
|
||||
|
||||
/* Lock hdev to access l2cap_data to avoid race with l2cap_conn_del */
|
||||
hci_dev_lock(hcon->hdev);
|
||||
/* Lock hdev for hci_conn, and race on l2cap_data vs. l2cap_conn_del */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!hcon) {
|
||||
hci_dev_unlock(hdev);
|
||||
kfree_skb(skb);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
hci_conn_enter_active_mode(hcon, BT_POWER_FORCE_ACTIVE_OFF);
|
||||
|
||||
conn = hcon->l2cap_data;
|
||||
|
||||
@@ -7524,12 +7535,13 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
conn = l2cap_conn_add(hcon);
|
||||
|
||||
conn = l2cap_conn_hold_unless_zero(conn);
|
||||
hcon = NULL;
|
||||
|
||||
hci_dev_unlock(hcon->hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!conn) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("conn %p len %u flags 0x%x", conn, skb->len, flags);
|
||||
@@ -7643,6 +7655,7 @@ drop:
|
||||
unlock:
|
||||
mutex_unlock(&conn->lock);
|
||||
l2cap_conn_put(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hci_cb l2cap_cb = {
|
||||
|
||||
@@ -1458,22 +1458,39 @@ static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
sco_conn_del(hcon, bt_to_errno(reason));
|
||||
}
|
||||
|
||||
void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
|
||||
int sco_recv_scodata(struct hci_dev *hdev, u16 handle, struct sk_buff *skb)
|
||||
{
|
||||
struct sco_conn *conn = hcon->sco_data;
|
||||
struct hci_conn *hcon;
|
||||
struct sco_conn *conn;
|
||||
|
||||
if (!conn)
|
||||
goto drop;
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!hcon) {
|
||||
hci_dev_unlock(hdev);
|
||||
kfree_skb(skb);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
conn = sco_conn_hold_unless_zero(hcon->sco_data);
|
||||
hcon = NULL;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!conn) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("conn %p len %u", conn, skb->len);
|
||||
|
||||
if (skb->len) {
|
||||
if (skb->len)
|
||||
sco_recv_frame(conn, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
drop:
|
||||
else
|
||||
kfree_skb(skb);
|
||||
|
||||
sco_conn_put(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hci_cb sco_cb = {
|
||||
|
||||
@@ -2136,7 +2136,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
u8 *pkax, *pkbx, *na, *nb, confirm_hint;
|
||||
u32 passkey;
|
||||
u32 passkey = 0;
|
||||
int err;
|
||||
|
||||
bt_dev_dbg(hcon->hdev, "conn %p", conn);
|
||||
@@ -2188,24 +2188,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
|
||||
smp->prnd);
|
||||
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
|
||||
|
||||
/* Only Just-Works pairing requires extra checks */
|
||||
if (smp->method != JUST_WORKS)
|
||||
goto mackey_and_ltk;
|
||||
|
||||
/* If there already exists long term key in local host, leave
|
||||
* the decision to user space since the remote device could
|
||||
* be legitimate or malicious.
|
||||
*/
|
||||
if (hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
hcon->role)) {
|
||||
/* Set passkey to 0. The value can be any number since
|
||||
* it'll be ignored anyway.
|
||||
*/
|
||||
passkey = 0;
|
||||
confirm_hint = 1;
|
||||
goto confirm;
|
||||
}
|
||||
}
|
||||
|
||||
mackey_and_ltk:
|
||||
@@ -2226,11 +2208,12 @@ mackey_and_ltk:
|
||||
if (err)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
confirm_hint = 0;
|
||||
|
||||
confirm:
|
||||
if (smp->method == JUST_WORKS)
|
||||
confirm_hint = 1;
|
||||
/* Always require user confirmation for Just-Works pairing to prevent
|
||||
* impersonation attacks, or in case of a legitimate device that is
|
||||
* repairing use the confirmation as acknowledgment to proceed with the
|
||||
* creation of new keys.
|
||||
*/
|
||||
confirm_hint = smp->method == JUST_WORKS ? 1 : 0;
|
||||
|
||||
err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
|
||||
hcon->dst_type, passkey, confirm_hint);
|
||||
|
||||
Reference in New Issue
Block a user