aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/bluetooth/hci.h8
-rw-r--r--include/net/bluetooth/hci_core.h4
-rw-r--r--include/net/bluetooth/mgmt.h20
-rw-r--r--net/bluetooth/hci_event.c46
-rw-r--r--net/bluetooth/mgmt.c141
5 files changed, 219 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 08fbf1253b83..e8e52da2b26b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -309,11 +309,19 @@ struct hci_cp_pin_code_reply {
309 __u8 pin_len; 309 __u8 pin_len;
310 __u8 pin_code[16]; 310 __u8 pin_code[16];
311} __packed; 311} __packed;
312struct hci_rp_pin_code_reply {
313 __u8 status;
314 bdaddr_t bdaddr;
315} __packed;
312 316
313#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e 317#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
314struct hci_cp_pin_code_neg_reply { 318struct hci_cp_pin_code_neg_reply {
315 bdaddr_t bdaddr; 319 bdaddr_t bdaddr;
316} __packed; 320} __packed;
321struct hci_rp_pin_code_neg_reply {
322 __u8 status;
323 bdaddr_t bdaddr;
324} __packed;
317 325
318#define HCI_OP_CHANGE_CONN_PTYPE 0x040f 326#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
319struct hci_cp_change_conn_ptype { 327struct hci_cp_change_conn_ptype {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 45caae62cb8e..9ac3da6e4a9a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -213,6 +213,7 @@ struct hci_conn {
213 __u8 auth_type; 213 __u8 auth_type;
214 __u8 sec_level; 214 __u8 sec_level;
215 __u8 pending_sec_level; 215 __u8 pending_sec_level;
216 __u8 pin_length;
216 __u8 power_save; 217 __u8 power_save;
217 __u16 disc_timeout; 218 __u16 disc_timeout;
218 unsigned long pend; 219 unsigned long pend;
@@ -718,6 +719,9 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr);
718int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); 719int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
719int mgmt_disconnect_failed(u16 index); 720int mgmt_disconnect_failed(u16 index);
720int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); 721int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
722int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
723int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
724int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
721 725
722/* HCI info for socket */ 726/* HCI info for socket */
723#define hci_pi(sk) ((struct hci_pinfo *) sk) 727#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 3d8d589fa559..46fb56d21b59 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -140,6 +140,20 @@ struct mgmt_rp_get_connections {
140 bdaddr_t conn[0]; 140 bdaddr_t conn[0];
141} __packed; 141} __packed;
142 142
143#define MGMT_OP_PIN_CODE_REPLY 0x0011
144struct mgmt_cp_pin_code_reply {
145 __le16 index;
146 bdaddr_t bdaddr;
147 __u8 pin_len;
148 __u8 pin_code[16];
149} __packed;
150
151#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0012
152struct mgmt_cp_pin_code_neg_reply {
153 __le16 index;
154 bdaddr_t bdaddr;
155} __packed;
156
143#define MGMT_EV_CMD_COMPLETE 0x0001 157#define MGMT_EV_CMD_COMPLETE 0x0001
144struct mgmt_ev_cmd_complete { 158struct mgmt_ev_cmd_complete {
145 __le16 opcode; 159 __le16 opcode;
@@ -201,3 +215,9 @@ struct mgmt_ev_connect_failed {
201 bdaddr_t bdaddr; 215 bdaddr_t bdaddr;
202 __u8 status; 216 __u8 status;
203} __packed; 217} __packed;
218
219#define MGMT_EV_PIN_CODE_REQUEST 0x000E
220struct mgmt_ev_pin_code_request {
221 __le16 index;
222 bdaddr_t bdaddr;
223} __packed;
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}