aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-01-21 23:10:07 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-07 22:40:07 -0500
commit980e1a537fed7dfa53e9a4b6e586b43341f8c2d5 (patch)
tree36d7716d48a71e16f37afb5d8afdb527463826cd /net
parenta38528f1117590169c0bf61cbf874e9fd2d5c5c9 (diff)
Bluetooth: Add support for PIN code handling in the management interface
This patch adds the necessary commands and events needed to communicate PIN code related actions between the kernel and userspace. This includes a pin_code_request event as well as pin_code_reply and pin_code_negative_reply commands. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/hci_event.c46
-rw-r--r--net/bluetooth/mgmt.c141
2 files changed, 187 insertions, 0 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 995ae6c17f11..98bcf78f2021 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -743,6 +743,40 @@ static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
743 hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status); 743 hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
744} 744}
745 745
746static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
747{
748 struct hci_rp_pin_code_reply *rp = (void *) skb->data;
749 struct hci_cp_pin_code_reply *cp;
750 struct hci_conn *conn;
751
752 BT_DBG("%s status 0x%x", hdev->name, rp->status);
753
754 if (test_bit(HCI_MGMT, &hdev->flags))
755 mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
756
757 if (rp->status != 0)
758 return;
759
760 cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
761 if (!cp)
762 return;
763
764 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
765 if (conn)
766 conn->pin_length = cp->pin_len;
767}
768
769static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
770{
771 struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
772
773 BT_DBG("%s status 0x%x", hdev->name, rp->status);
774
775 if (test_bit(HCI_MGMT, &hdev->flags))
776 mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
777 rp->status);
778}
779
746static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) 780static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
747{ 781{
748 BT_DBG("%s status 0x%x", hdev->name, status); 782 BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1619,6 +1653,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
1619 hci_cc_set_event_flt(hdev, skb); 1653 hci_cc_set_event_flt(hdev, skb);
1620 break; 1654 break;
1621 1655
1656 case HCI_OP_PIN_CODE_REPLY:
1657 hci_cc_pin_code_reply(hdev, skb);
1658 break;
1659
1660 case HCI_OP_PIN_CODE_NEG_REPLY:
1661 hci_cc_pin_code_neg_reply(hdev, skb);
1662 break;
1663
1622 default: 1664 default:
1623 BT_DBG("%s opcode 0x%x", hdev->name, opcode); 1665 BT_DBG("%s opcode 0x%x", hdev->name, opcode);
1624 break; 1666 break;
@@ -1821,6 +1863,9 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
1821 hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, 1863 hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1822 sizeof(ev->bdaddr), &ev->bdaddr); 1864 sizeof(ev->bdaddr), &ev->bdaddr);
1823 1865
1866 if (test_bit(HCI_MGMT, &hdev->flags))
1867 mgmt_pin_code_request(hdev->id, &ev->bdaddr);
1868
1824 hci_dev_unlock(hdev); 1869 hci_dev_unlock(hdev);
1825} 1870}
1826 1871
@@ -1889,6 +1934,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
1889 if (conn) { 1934 if (conn) {
1890 hci_conn_hold(conn); 1935 hci_conn_hold(conn);
1891 conn->disc_timeout = HCI_DISCONN_TIMEOUT; 1936 conn->disc_timeout = HCI_DISCONN_TIMEOUT;
1937 pin_len = conn->pin_length;
1892 hci_conn_put(conn); 1938 hci_conn_put(conn);
1893 } 1939 }
1894 1940
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 005288b2a58e..3800aaf5792d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -933,6 +933,89 @@ unlock:
933 return err; 933 return err;
934} 934}
935 935
936static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
937{
938 struct hci_dev *hdev;
939 struct mgmt_cp_pin_code_reply *cp;
940 struct hci_cp_pin_code_reply reply;
941 u16 dev_id;
942 int err;
943
944 BT_DBG("");
945
946 cp = (void *) data;
947 dev_id = get_unaligned_le16(&cp->index);
948
949 hdev = hci_dev_get(dev_id);
950 if (!hdev)
951 return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
952
953 hci_dev_lock_bh(hdev);
954
955 if (!test_bit(HCI_UP, &hdev->flags)) {
956 err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
957 goto failed;
958 }
959
960 err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
961 if (err < 0)
962 goto failed;
963
964 bacpy(&reply.bdaddr, &cp->bdaddr);
965 reply.pin_len = cp->pin_len;
966 memcpy(reply.pin_code, cp->pin_code, 16);
967
968 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
969 if (err < 0)
970 mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
971
972failed:
973 hci_dev_unlock_bh(hdev);
974 hci_dev_put(hdev);
975
976 return err;
977}
978
979static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
980{
981 struct hci_dev *hdev;
982 struct mgmt_cp_pin_code_neg_reply *cp;
983 u16 dev_id;
984 int err;
985
986 BT_DBG("");
987
988 cp = (void *) data;
989 dev_id = get_unaligned_le16(&cp->index);
990
991 hdev = hci_dev_get(dev_id);
992 if (!hdev)
993 return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
994
995 hci_dev_lock_bh(hdev);
996
997 if (!test_bit(HCI_UP, &hdev->flags)) {
998 err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
999 goto failed;
1000 }
1001
1002 err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
1003 data, len);
1004 if (err < 0)
1005 goto failed;
1006
1007 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
1008 &cp->bdaddr);
1009 if (err < 0)
1010 mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
1011
1012failed:
1013 hci_dev_unlock_bh(hdev);
1014 hci_dev_put(hdev);
1015
1016 return err;
1017}
1018
936int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 1019int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
937{ 1020{
938 unsigned char *buf; 1021 unsigned char *buf;
@@ -1009,6 +1092,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1009 case MGMT_OP_GET_CONNECTIONS: 1092 case MGMT_OP_GET_CONNECTIONS:
1010 err = get_connections(sk, buf + sizeof(*hdr), len); 1093 err = get_connections(sk, buf + sizeof(*hdr), len);
1011 break; 1094 break;
1095 case MGMT_OP_PIN_CODE_REPLY:
1096 err = pin_code_reply(sk, buf + sizeof(*hdr), len);
1097 break;
1098 case MGMT_OP_PIN_CODE_NEG_REPLY:
1099 err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
1100 break;
1012 default: 1101 default:
1013 BT_DBG("Unknown op %u", opcode); 1102 BT_DBG("Unknown op %u", opcode);
1014 err = cmd_status(sk, opcode, 0x01); 1103 err = cmd_status(sk, opcode, 0x01);
@@ -1217,3 +1306,55 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
1217 1306
1218 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL); 1307 return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
1219} 1308}
1309
1310int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
1311{
1312 struct mgmt_ev_pin_code_request ev;
1313
1314 put_unaligned_le16(index, &ev.index);
1315 bacpy(&ev.bdaddr, bdaddr);
1316
1317 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
1318}
1319
1320int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1321{
1322 struct pending_cmd *cmd;
1323 int err;
1324
1325 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
1326 if (!cmd)
1327 return -ENOENT;
1328
1329 if (status != 0)
1330 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
1331 else
1332 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
1333 bdaddr, sizeof(*bdaddr));
1334
1335 list_del(&cmd->list);
1336 mgmt_pending_free(cmd);
1337
1338 return err;
1339}
1340
1341int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
1342{
1343 struct pending_cmd *cmd;
1344 int err;
1345
1346 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
1347 if (!cmd)
1348 return -ENOENT;
1349
1350 if (status != 0)
1351 err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
1352 else
1353 err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
1354 bdaddr, sizeof(*bdaddr));
1355
1356 list_del(&cmd->list);
1357 mgmt_pending_free(cmd);
1358
1359 return err;
1360}