diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2011-02-19 10:05:57 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-21 15:22:44 -0500 |
commit | a5c296832b4fde7d32c01cff9cdd27d9c7c1c4f5 (patch) | |
tree | 895ae41944ca568f6eca3c7c4855211bd7db8540 | |
parent | e9a416b5ce0c0f93819f55d34cf6882196e9c3b2 (diff) |
Bluetooth: Add management support for user confirmation request
This patch adds support for the user confirmation (numeric comparison)
Secure Simple Pairing authentication method.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/hci.h | 17 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 4 | ||||
-rw-r--r-- | include/net/bluetooth/mgmt.h | 20 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 50 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 103 |
5 files changed, 194 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index a5f8c4684a32..ec6acf2f1c0b 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
@@ -415,6 +415,17 @@ struct hci_cp_io_capability_reply { | |||
415 | __u8 authentication; | 415 | __u8 authentication; |
416 | } __packed; | 416 | } __packed; |
417 | 417 | ||
418 | #define HCI_OP_USER_CONFIRM_REPLY 0x042c | ||
419 | struct hci_cp_user_confirm_reply { | ||
420 | bdaddr_t bdaddr; | ||
421 | } __packed; | ||
422 | struct hci_rp_user_confirm_reply { | ||
423 | __u8 status; | ||
424 | bdaddr_t bdaddr; | ||
425 | } __packed; | ||
426 | |||
427 | #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d | ||
428 | |||
418 | #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 | 429 | #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 |
419 | struct hci_cp_io_capability_neg_reply { | 430 | struct hci_cp_io_capability_neg_reply { |
420 | bdaddr_t bdaddr; | 431 | bdaddr_t bdaddr; |
@@ -936,6 +947,12 @@ struct hci_ev_io_capa_reply { | |||
936 | __u8 authentication; | 947 | __u8 authentication; |
937 | } __packed; | 948 | } __packed; |
938 | 949 | ||
950 | #define HCI_EV_USER_CONFIRM_REQUEST 0x33 | ||
951 | struct hci_ev_user_confirm_req { | ||
952 | bdaddr_t bdaddr; | ||
953 | __le32 passkey; | ||
954 | } __packed; | ||
955 | |||
939 | #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 | 956 | #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 |
940 | struct hci_ev_simple_pair_complete { | 957 | struct hci_ev_simple_pair_complete { |
941 | __u8 status; | 958 | __u8 status; |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 506f25089207..05f4706e6c34 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -762,6 +762,10 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); | |||
762 | int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); | 762 | int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); |
763 | int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); | 763 | int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); |
764 | int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); | 764 | int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); |
765 | int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); | ||
766 | int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); | ||
767 | int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, | ||
768 | u8 status); | ||
765 | 769 | ||
766 | /* HCI info for socket */ | 770 | /* HCI info for socket */ |
767 | #define hci_pi(sk) ((struct hci_pinfo *) sk) | 771 | #define hci_pi(sk) ((struct hci_pinfo *) sk) |
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 1d25c59be2e3..52376a3295ca 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h | |||
@@ -172,6 +172,19 @@ struct mgmt_rp_pair_device { | |||
172 | __u8 status; | 172 | __u8 status; |
173 | } __packed; | 173 | } __packed; |
174 | 174 | ||
175 | #define MGMT_OP_USER_CONFIRM_REPLY 0x0015 | ||
176 | struct mgmt_cp_user_confirm_reply { | ||
177 | __le16 index; | ||
178 | bdaddr_t bdaddr; | ||
179 | } __packed; | ||
180 | struct mgmt_rp_user_confirm_reply { | ||
181 | __le16 index; | ||
182 | bdaddr_t bdaddr; | ||
183 | __u8 status; | ||
184 | } __packed; | ||
185 | |||
186 | #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 | ||
187 | |||
175 | #define MGMT_EV_CMD_COMPLETE 0x0001 | 188 | #define MGMT_EV_CMD_COMPLETE 0x0001 |
176 | struct mgmt_ev_cmd_complete { | 189 | struct mgmt_ev_cmd_complete { |
177 | __le16 opcode; | 190 | __le16 opcode; |
@@ -239,3 +252,10 @@ struct mgmt_ev_pin_code_request { | |||
239 | __le16 index; | 252 | __le16 index; |
240 | bdaddr_t bdaddr; | 253 | bdaddr_t bdaddr; |
241 | } __packed; | 254 | } __packed; |
255 | |||
256 | #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F | ||
257 | struct mgmt_ev_user_confirm_request { | ||
258 | __le16 index; | ||
259 | bdaddr_t bdaddr; | ||
260 | __le32 value; | ||
261 | } __packed; | ||
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 98b5764e4315..604c7b5fee97 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -796,6 +796,29 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, | |||
796 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); | 796 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); |
797 | } | 797 | } |
798 | 798 | ||
799 | static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) | ||
800 | { | ||
801 | struct hci_rp_user_confirm_reply *rp = (void *) skb->data; | ||
802 | |||
803 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
804 | |||
805 | if (test_bit(HCI_MGMT, &hdev->flags)) | ||
806 | mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr, | ||
807 | rp->status); | ||
808 | } | ||
809 | |||
810 | static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, | ||
811 | struct sk_buff *skb) | ||
812 | { | ||
813 | struct hci_rp_user_confirm_reply *rp = (void *) skb->data; | ||
814 | |||
815 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
816 | |||
817 | if (test_bit(HCI_MGMT, &hdev->flags)) | ||
818 | mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr, | ||
819 | rp->status); | ||
820 | } | ||
821 | |||
799 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 822 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
800 | { | 823 | { |
801 | BT_DBG("%s status 0x%x", hdev->name, status); | 824 | BT_DBG("%s status 0x%x", hdev->name, status); |
@@ -1728,6 +1751,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1728 | hci_cc_le_read_buffer_size(hdev, skb); | 1751 | hci_cc_le_read_buffer_size(hdev, skb); |
1729 | break; | 1752 | break; |
1730 | 1753 | ||
1754 | case HCI_OP_USER_CONFIRM_REPLY: | ||
1755 | hci_cc_user_confirm_reply(hdev, skb); | ||
1756 | break; | ||
1757 | |||
1758 | case HCI_OP_USER_CONFIRM_NEG_REPLY: | ||
1759 | hci_cc_user_confirm_neg_reply(hdev, skb); | ||
1760 | break; | ||
1761 | |||
1731 | default: | 1762 | default: |
1732 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1763 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1733 | break; | 1764 | break; |
@@ -2362,6 +2393,21 @@ unlock: | |||
2362 | hci_dev_unlock(hdev); | 2393 | hci_dev_unlock(hdev); |
2363 | } | 2394 | } |
2364 | 2395 | ||
2396 | static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, | ||
2397 | struct sk_buff *skb) | ||
2398 | { | ||
2399 | struct hci_ev_user_confirm_req *ev = (void *) skb->data; | ||
2400 | |||
2401 | BT_DBG("%s", hdev->name); | ||
2402 | |||
2403 | hci_dev_lock(hdev); | ||
2404 | |||
2405 | if (test_bit(HCI_MGMT, &hdev->flags)) | ||
2406 | mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); | ||
2407 | |||
2408 | hci_dev_unlock(hdev); | ||
2409 | } | ||
2410 | |||
2365 | static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2411 | static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
2366 | { | 2412 | { |
2367 | struct hci_ev_simple_pair_complete *ev = (void *) skb->data; | 2413 | struct hci_ev_simple_pair_complete *ev = (void *) skb->data; |
@@ -2580,6 +2626,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
2580 | hci_io_capa_reply_evt(hdev, skb); | 2626 | hci_io_capa_reply_evt(hdev, skb); |
2581 | break; | 2627 | break; |
2582 | 2628 | ||
2629 | case HCI_EV_USER_CONFIRM_REQUEST: | ||
2630 | hci_user_confirm_request_evt(hdev, skb); | ||
2631 | break; | ||
2632 | |||
2583 | case HCI_EV_SIMPLE_PAIR_COMPLETE: | 2633 | case HCI_EV_SIMPLE_PAIR_COMPLETE: |
2584 | hci_simple_pair_complete_evt(hdev, skb); | 2634 | hci_simple_pair_complete_evt(hdev, skb); |
2585 | break; | 2635 | break; |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d7fc54dcbc9e..fdcc9742bb00 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -1193,6 +1193,55 @@ unlock: | |||
1193 | return err; | 1193 | return err; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | static int user_confirm_reply(struct sock *sk, unsigned char *data, u16 len, | ||
1197 | int success) | ||
1198 | { | ||
1199 | struct mgmt_cp_user_confirm_reply *cp = (void *) data; | ||
1200 | u16 dev_id, mgmt_op, hci_op; | ||
1201 | struct pending_cmd *cmd; | ||
1202 | struct hci_dev *hdev; | ||
1203 | int err; | ||
1204 | |||
1205 | BT_DBG(""); | ||
1206 | |||
1207 | dev_id = get_unaligned_le16(&cp->index); | ||
1208 | |||
1209 | if (success) { | ||
1210 | mgmt_op = MGMT_OP_USER_CONFIRM_REPLY; | ||
1211 | hci_op = HCI_OP_USER_CONFIRM_REPLY; | ||
1212 | } else { | ||
1213 | mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY; | ||
1214 | hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY; | ||
1215 | } | ||
1216 | |||
1217 | hdev = hci_dev_get(dev_id); | ||
1218 | if (!hdev) | ||
1219 | return cmd_status(sk, mgmt_op, ENODEV); | ||
1220 | |||
1221 | if (!test_bit(HCI_UP, &hdev->flags)) { | ||
1222 | err = cmd_status(sk, mgmt_op, ENETDOWN); | ||
1223 | goto failed; | ||
1224 | } | ||
1225 | |||
1226 | cmd = mgmt_pending_add(sk, mgmt_op, dev_id, data, len); | ||
1227 | if (!cmd) { | ||
1228 | err = -ENOMEM; | ||
1229 | goto failed; | ||
1230 | } | ||
1231 | |||
1232 | err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr); | ||
1233 | if (err < 0) { | ||
1234 | list_del(&cmd->list); | ||
1235 | mgmt_pending_free(cmd); | ||
1236 | } | ||
1237 | |||
1238 | failed: | ||
1239 | hci_dev_unlock_bh(hdev); | ||
1240 | hci_dev_put(hdev); | ||
1241 | |||
1242 | return err; | ||
1243 | } | ||
1244 | |||
1196 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 1245 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
1197 | { | 1246 | { |
1198 | unsigned char *buf; | 1247 | unsigned char *buf; |
@@ -1281,6 +1330,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1281 | case MGMT_OP_PAIR_DEVICE: | 1330 | case MGMT_OP_PAIR_DEVICE: |
1282 | err = pair_device(sk, buf + sizeof(*hdr), len); | 1331 | err = pair_device(sk, buf + sizeof(*hdr), len); |
1283 | break; | 1332 | break; |
1333 | case MGMT_OP_USER_CONFIRM_REPLY: | ||
1334 | err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 1); | ||
1335 | break; | ||
1336 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: | ||
1337 | err = user_confirm_reply(sk, buf + sizeof(*hdr), len, 0); | ||
1338 | break; | ||
1284 | default: | 1339 | default: |
1285 | BT_DBG("Unknown op %u", opcode); | 1340 | BT_DBG("Unknown op %u", opcode); |
1286 | err = cmd_status(sk, opcode, 0x01); | 1341 | err = cmd_status(sk, opcode, 0x01); |
@@ -1541,3 +1596,51 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | |||
1541 | 1596 | ||
1542 | return err; | 1597 | return err; |
1543 | } | 1598 | } |
1599 | |||
1600 | int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) | ||
1601 | { | ||
1602 | struct mgmt_ev_user_confirm_request ev; | ||
1603 | |||
1604 | BT_DBG("hci%u", index); | ||
1605 | |||
1606 | put_unaligned_le16(index, &ev.index); | ||
1607 | bacpy(&ev.bdaddr, bdaddr); | ||
1608 | put_unaligned_le32(value, &ev.value); | ||
1609 | |||
1610 | return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, &ev, sizeof(ev), NULL); | ||
1611 | } | ||
1612 | |||
1613 | static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status, | ||
1614 | u8 opcode) | ||
1615 | { | ||
1616 | struct pending_cmd *cmd; | ||
1617 | struct mgmt_rp_user_confirm_reply rp; | ||
1618 | int err; | ||
1619 | |||
1620 | cmd = mgmt_pending_find(opcode, index); | ||
1621 | if (!cmd) | ||
1622 | return -ENOENT; | ||
1623 | |||
1624 | put_unaligned_le16(index, &rp.index); | ||
1625 | bacpy(&rp.bdaddr, bdaddr); | ||
1626 | rp.status = status; | ||
1627 | err = cmd_complete(cmd->sk, opcode, &rp, sizeof(rp)); | ||
1628 | |||
1629 | list_del(&cmd->list); | ||
1630 | mgmt_pending_free(cmd); | ||
1631 | |||
1632 | return err; | ||
1633 | } | ||
1634 | |||
1635 | int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | ||
1636 | { | ||
1637 | return confirm_reply_complete(index, bdaddr, status, | ||
1638 | MGMT_OP_USER_CONFIRM_REPLY); | ||
1639 | } | ||
1640 | |||
1641 | int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, | ||
1642 | u8 status) | ||
1643 | { | ||
1644 | return confirm_reply_complete(index, bdaddr, status, | ||
1645 | MGMT_OP_USER_CONFIRM_NEG_REPLY); | ||
1646 | } | ||