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 /net/bluetooth/mgmt.c | |
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>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 103 |
1 files changed, 103 insertions, 0 deletions
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 | } | ||