aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
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 /net/bluetooth
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_event.c50
-rw-r--r--net/bluetooth/mgmt.c103
2 files changed, 153 insertions, 0 deletions
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}