aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-02-19 10:05:57 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-21 15:22:44 -0500
commita5c296832b4fde7d32c01cff9cdd27d9c7c1c4f5 (patch)
tree895ae41944ca568f6eca3c7c4855211bd7db8540
parente9a416b5ce0c0f93819f55d34cf6882196e9c3b2 (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.h17
-rw-r--r--include/net/bluetooth/hci_core.h4
-rw-r--r--include/net/bluetooth/mgmt.h20
-rw-r--r--net/bluetooth/hci_event.c50
-rw-r--r--net/bluetooth/mgmt.c103
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
419struct hci_cp_user_confirm_reply {
420 bdaddr_t bdaddr;
421} __packed;
422struct 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
419struct hci_cp_io_capability_neg_reply { 430struct 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
951struct 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
940struct hci_ev_simple_pair_complete { 957struct 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);
762int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); 762int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
763int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); 763int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
764int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); 764int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
765int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value);
766int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
767int 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
176struct mgmt_cp_user_confirm_reply {
177 __le16 index;
178 bdaddr_t bdaddr;
179} __packed;
180struct 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
176struct mgmt_ev_cmd_complete { 189struct 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
257struct 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
799static 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
810static 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
799static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) 822static 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
2396static 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
2365static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) 2411static 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
1196static 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
1238failed:
1239 hci_dev_unlock_bh(hdev);
1240 hci_dev_put(hdev);
1241
1242 return err;
1243}
1244
1196int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 1245int 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
1600int 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
1613static 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
1635int 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
1641int 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}