Skip to content

Commit

Permalink
Bluetooth: mgmt: Implement support for passkey notification
Browse files Browse the repository at this point in the history
This patch adds support for Secure Simple Pairing with devices that have
KeyboardOnly as their IO capability. Such devices will cause a passkey
notification on our side and optionally also keypress notifications.
Without this patch some keyboards cannot be paired using the mgmt
interface.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Cc: stable@vger.kernel.org
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
  • Loading branch information
Johan Hedberg authored and Gustavo Padovan committed Sep 19, 2012
1 parent 5ad7779 commit 92a2525
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
18 changes: 18 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
bdaddr_t bdaddr;
} __packed;

#define HCI_EV_USER_PASSKEY_NOTIFY 0x3b
struct hci_ev_user_passkey_notify {
bdaddr_t bdaddr;
__le32 passkey;
} __packed;

#define HCI_KEYPRESS_STARTED 0
#define HCI_KEYPRESS_ENTERED 1
#define HCI_KEYPRESS_ERASED 2
#define HCI_KEYPRESS_CLEARED 3
#define HCI_KEYPRESS_COMPLETED 4

#define HCI_EV_KEYPRESS_NOTIFY 0x3c
struct hci_ev_keypress_notify {
bdaddr_t bdaddr;
__u8 type;
} __packed;

#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
Expand Down
5 changes: 5 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ struct hci_conn {
__u8 pin_length;
__u8 enc_key_size;
__u8 io_capability;
__u32 passkey_notify;
__u8 passkey_entered;
__u16 disc_timeout;
unsigned long flags;

Expand Down Expand Up @@ -1022,6 +1024,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u32 passkey,
u8 entered);
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status);
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
Expand Down
7 changes: 7 additions & 0 deletions include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,10 @@ struct mgmt_ev_device_unblocked {
struct mgmt_ev_device_unpaired {
struct mgmt_addr_info addr;
} __packed;

#define MGMT_EV_PASSKEY_NOTIFY 0x0017
struct mgmt_ev_passkey_notify {
struct mgmt_addr_info addr;
__le32 passkey;
__u8 entered;
} __packed;
67 changes: 67 additions & 0 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -3263,6 +3263,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
}

static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
struct hci_conn *conn;

BT_DBG("%s", hdev->name);

conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
return;

conn->passkey_notify = __le32_to_cpu(ev->passkey);
conn->passkey_entered = 0;

if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
}

static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_keypress_notify *ev = (void *) skb->data;
struct hci_conn *conn;

BT_DBG("%s", hdev->name);

conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
return;

switch (ev->type) {
case HCI_KEYPRESS_STARTED:
conn->passkey_entered = 0;
return;

case HCI_KEYPRESS_ENTERED:
conn->passkey_entered++;
break;

case HCI_KEYPRESS_ERASED:
conn->passkey_entered--;
break;

case HCI_KEYPRESS_CLEARED:
conn->passkey_entered = 0;
break;

case HCI_KEYPRESS_COMPLETED:
return;
}

if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
}

static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
Expand Down Expand Up @@ -3627,6 +3686,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_user_passkey_request_evt(hdev, skb);
break;

case HCI_EV_USER_PASSKEY_NOTIFY:
hci_user_passkey_notify_evt(hdev, skb);
break;

case HCI_EV_KEYPRESS_NOTIFY:
hci_keypress_notify_evt(hdev, skb);
break;

case HCI_EV_SIMPLE_PAIR_COMPLETE:
hci_simple_pair_complete_evt(hdev, skb);
break;
Expand Down
17 changes: 17 additions & 0 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ static const u16 mgmt_events[] = {
MGMT_EV_DEVICE_BLOCKED,
MGMT_EV_DEVICE_UNBLOCKED,
MGMT_EV_DEVICE_UNPAIRED,
MGMT_EV_PASSKEY_NOTIFY,
};

/*
Expand Down Expand Up @@ -3276,6 +3277,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
MGMT_OP_USER_PASSKEY_NEG_REPLY);
}

int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u32 passkey,
u8 entered)
{
struct mgmt_ev_passkey_notify ev;

BT_DBG("%s", hdev->name);

bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.passkey = __cpu_to_le32(passkey);
ev.entered = entered;

return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
}

int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status)
{
Expand Down

0 comments on commit 92a2525

Please sign in to comment.